diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index 9d9b5f262..4b8aecab8 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -28,6 +28,7 @@ const TXID_REGEX = /^[a-f0-9]{64}$/i; const BLOCK_HASH_REGEX = /^[a-f0-9]{64}$/i; const ADDRESS_REGEX = /^[a-z0-9]{2,120}$/i; const SCRIPT_HASH_REGEX = /^([a-f0-9]{2})+$/i; +const MAX_TRANSACTION_TIMES = 100; class BitcoinRoutes { public initRoutes(app: Application) { @@ -144,11 +145,18 @@ class BitcoinRoutes { private getTransactionTimes(req: Request, res: Response) { if (!req.query.txId || typeof req.query.txId !== 'object') { - handleError(req, res, 500, 'invalid txId format'); + handleError(req, res, 400, 'invalid txId format'); return; } + + const requestedTxIds = Object.values(req.query.txId); + if (requestedTxIds.length > MAX_TRANSACTION_TIMES) { + handleError(req, res, 400, 'Too many txids requested'); + return; + } + const txIds: string[] = []; - for (const txid of Object.values(req.query.txId)) { + for (const txid of requestedTxIds) { if (typeof txid === 'string' && TXID_REGEX.test(txid)) { txIds.push(txid); } @@ -161,7 +169,7 @@ class BitcoinRoutes { private async $getBatchedOutspends(req: Request, res: Response): Promise { const txids_csv = req.query.txids; if (!txids_csv || typeof txids_csv !== 'string') { - handleError(req, res, 500, 'Invalid txids format'); + handleError(req, res, 400, 'Invalid txids format'); return; } const txids = txids_csv.split(','); @@ -184,7 +192,7 @@ class BitcoinRoutes { private async $getCpfpInfo(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } @@ -246,7 +254,7 @@ class BitcoinRoutes { private async getTransaction(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -265,7 +273,7 @@ class BitcoinRoutes { private async getRawTransaction(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -353,7 +361,7 @@ class BitcoinRoutes { private async getTransactionStatus(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -372,7 +380,7 @@ class BitcoinRoutes { private async getStrippedBlockTransactions(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -386,11 +394,11 @@ class BitcoinRoutes { private async getStrippedBlockTransaction(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } if (!TXID_REGEX.test(req.params.txid)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -408,7 +416,7 @@ class BitcoinRoutes { private async getBlock(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -434,7 +442,7 @@ class BitcoinRoutes { private async getBlockHeader(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -448,7 +456,7 @@ class BitcoinRoutes { private async getBlockAuditSummary(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -467,11 +475,11 @@ class BitcoinRoutes { private async $getBlockTxAuditSummary(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } if (!TXID_REGEX.test(req.params.txid)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -621,7 +629,7 @@ class BitcoinRoutes { private async getBlockTransactions(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -663,7 +671,7 @@ class BitcoinRoutes { return; } if (!ADDRESS_REGEX.test(req.params.address)) { - handleError(req, res, 501, `Invalid address`); + handleError(req, res, 400, `Invalid address`); return; } @@ -689,7 +697,7 @@ class BitcoinRoutes { return; } if (!ADDRESS_REGEX.test(req.params.address)) { - handleError(req, res, 501, `Invalid address`); + handleError(req, res, 400, `Invalid address`); return; } @@ -719,7 +727,7 @@ class BitcoinRoutes { return; } if (!ADDRESS_REGEX.test(req.params.address)) { - handleError(req, res, 501, `Invalid address`); + handleError(req, res, 400, `Invalid address`); return; } @@ -752,7 +760,7 @@ class BitcoinRoutes { return; } if (!SCRIPT_HASH_REGEX.test(req.params.scripthash)) { - handleError(req, res, 501, `Invalid scripthash`); + handleError(req, res, 400, `Invalid scripthash`); return; } @@ -776,7 +784,7 @@ class BitcoinRoutes { return; } if (!SCRIPT_HASH_REGEX.test(req.params.scripthash)) { - handleError(req, res, 501, `Invalid scripthash`); + handleError(req, res, 400, `Invalid scripthash`); return; } @@ -804,7 +812,7 @@ class BitcoinRoutes { return; } if (!SCRIPT_HASH_REGEX.test(req.params.scripthash)) { - handleError(req, res, 501, `Invalid scripthash`); + handleError(req, res, 400, `Invalid scripthash`); return; } @@ -937,7 +945,7 @@ class BitcoinRoutes { private async getRawBlock(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -951,7 +959,7 @@ class BitcoinRoutes { private async getTxIdsForBlock(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -964,7 +972,7 @@ class BitcoinRoutes { private async validateAddress(req: Request, res: Response) { if (!ADDRESS_REGEX.test(req.params.address)) { - handleError(req, res, 501, `Invalid address`); + handleError(req, res, 400, `Invalid address`); return; } try { @@ -977,7 +985,7 @@ class BitcoinRoutes { private async getRbfHistory(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -1012,7 +1020,7 @@ class BitcoinRoutes { private async getCachedTx(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -1029,7 +1037,7 @@ class BitcoinRoutes { private async getTransactionOutspends(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -1042,7 +1050,7 @@ class BitcoinRoutes { private async getTransactionMerkleProof(req: Request, res: Response): Promise { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try {