]> git.codecow.com Git - libnemo.git/commitdiff
Add stricter validation on block_info response.
authorChris Duncan <chris@codecow.com>
Mon, 10 Aug 2026 22:16:20 +0000 (15:16 -0700)
committerChris Duncan <chris@codecow.com>
Mon, 10 Aug 2026 22:16:20 +0000 (15:16 -0700)
src/lib/rpc/block_info.ts

index fdbdc6736b6a45f04878bc4681b047b7f6e76046..35e064e06e05b1ab23f3658f0c89c6fffa737c82 100644 (file)
@@ -38,18 +38,22 @@ export type BlockInfoResponse = {
 
 export function block_info (body: unknown): BlockInfoResponse {
        if (body != null && typeof body === 'object') {
-               if ('amount' in body && typeof body.amount === 'string'
-                       && 'balance' in body && typeof body.balance === 'string'
-                       && 'block_account' in body && typeof body.block_account === 'string'
-                       && 'confirmed' in body && typeof body.confirmed === 'string'
-                       && 'height' in body && typeof body.height === 'string'
-                       && 'linked_account' in body && typeof body.linked_account === 'string'
-                       && 'local_timestamp' in body && typeof body.local_timestamp === 'string'
+               if ('error' in body && typeof body.error === 'string') {
+                       throw new RpcError(body.error)
+               }
+
+               if ('amount' in body && typeof body.amount === 'string' && /^\d+$/.test(body.amount)
+                       && 'balance' in body && typeof body.balance === 'string' && /^\d+$/.test(body.balance)
+                       && 'block_account' in body && Account.isValid(body.block_account)
+                       && 'confirmed' in body && (body.confirmed === 'true' || body.confirmed === 'false')
+                       && 'height' in body && typeof body.height === 'string' && /^\d+$/.test(body.height)
+                       && 'linked_account' in body && (body.linked_account === '0' || Account.isValid(body.linked_account))
+                       && 'local_timestamp' in body && typeof body.local_timestamp === 'string' && /^\d+$/.test(body.local_timestamp)
                        && 'subtype' in body && (body.subtype === 'change' || body.subtype === 'epoch' || body.subtype === 'open' || body.subtype === 'receive' || body.subtype === 'send')
-                       && 'successor' in body && typeof body.successor === 'string'
+                       && 'successor' in body && hex.is(body.successor, 64)
                        && 'contents' in body && body.contents != null && typeof body.contents === 'object'
-                       && 'account' in body.contents && typeof body.contents.account === 'string'
-                       && 'balance' in body.contents && typeof body.contents.balance === 'string'
+                       && 'account' in body.contents && Account.isValid(body.contents.account)
+                       && 'balance' in body.contents && typeof body.contents.balance === 'string' && /^\d+$/.test(body.contents.balance)
                        && 'link' in body.contents && hex.is(body.contents.link, 64)
                        && 'link_as_account' in body.contents && Account.isValid(body.contents.link_as_account)
                        && 'previous' in body.contents && hex.is(body.contents.previous, 64)
@@ -58,32 +62,31 @@ export function block_info (body: unknown): BlockInfoResponse {
                        && 'type' in body.contents && body.contents.type === 'state'
                        && 'work' in body.contents && typeof body.contents.work === 'string'
                ) {
-                       return {
-                               contents: {
-                                       account: body.contents.account,
-                                       balance: body.contents.balance,
-                                       link: body.contents.link,
-                                       link_as_account: body.contents.link_as_account,
-                                       previous: body.contents.previous,
-                                       representative: body.contents.representative,
-                                       signature: body.contents.signature,
-                                       type: body.contents.type,
-                                       work: body.contents.work,
-                               },
-                               amount: body.amount,
-                               balance: body.balance,
-                               block_account: body.block_account,
-                               confirmed: body.confirmed,
-                               height: body.height,
-                               linked_account: body.linked_account,
-                               local_timestamp: body.local_timestamp,
-                               subtype: body.subtype,
-                               successor: body.successor,
-                       }
-               }
-               if ('error' in body && typeof body.error === 'string') {
-                       throw new RpcError(body.error)
+                       const response: BlockInfoResponse = Object.create(null)
+                       response.amount = body.amount
+                       response.balance = body.balance
+                       response.block_account = body.block_account
+                       response.confirmed = body.confirmed
+                       response.height = body.height
+                       response.linked_account = body.linked_account
+                       response.local_timestamp = body.local_timestamp
+                       response.subtype = body.subtype
+                       response.successor = body.successor
+
+                       const contents: BlockInfoContents = Object.create(null)
+                       contents.account = body.contents.account
+                       contents.balance = body.contents.balance
+                       contents.link = body.contents.link
+                       contents.link_as_account = body.contents.link_as_account
+                       contents.previous = body.contents.previous
+                       contents.representative = body.contents.representative
+                       contents.signature = body.contents.signature
+                       contents.type = body.contents.type
+                       contents.work = body.contents.work
+                       response.contents = contents
+
+                       return response
                }
        }
-       throw new RpcError('Invalid block_info response')
+       throw new RpcError('Invalid block_info response', { cause: body })
 }