Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion pages/api/address/balance/[address].ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { runMiddleware, satoshisToUnit } from 'utils/index'
import xecaddr from 'xecaddrjs'
import { multiBlockchainClient } from 'services/chronikService'

const { ADDRESS_NOT_PROVIDED_400 } = RESPONSE_MESSAGES
const { ADDRESS_NOT_PROVIDED_400, INVALID_ADDRESS_400 } = RESPONSE_MESSAGES
const cors = Cors({
methods: ['GET', 'HEAD']
})
Expand All @@ -24,6 +24,9 @@ export default async (req: NextApiRequest, res: NextApiResponse): Promise<void>
case ADDRESS_NOT_PROVIDED_400.message:
res.status(ADDRESS_NOT_PROVIDED_400.statusCode).json(ADDRESS_NOT_PROVIDED_400)
break
case INVALID_ADDRESS_400.message:
res.status(INVALID_ADDRESS_400.statusCode).json(INVALID_ADDRESS_400)
break
default:
res.status(500).json({ statusCode: 500, message: err.message })
}
Expand Down
3 changes: 3 additions & 0 deletions pages/api/address/transactions/count/[address].ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export default async (req: NextApiRequest, res: NextApiResponse): Promise<void>
case RESPONSE_MESSAGES.MULTIPLE_USER_IDS_PROVIDED_400.message:
res.status(400).json(RESPONSE_MESSAGES.MULTIPLE_USER_IDS_PROVIDED_400)
break
case RESPONSE_MESSAGES.INVALID_ADDRESS_400.message:
res.status(RESPONSE_MESSAGES.INVALID_ADDRESS_400.statusCode).json(RESPONSE_MESSAGES.INVALID_ADDRESS_400)
break
default:
res.status(500).json({ statusCode: 500, message: err.message })
}
Expand Down
35 changes: 35 additions & 0 deletions tests/integration-tests/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import walletsEndpoint from 'pages/api/wallets/index'
import walletEndpoint from 'pages/api/wallet/index'
import walletIdEndpoint from 'pages/api/wallet/[id]'
import transactionsEndpoint from 'pages/api/address/transactions/[address]'
import transactionCountEndpoint from 'pages/api/address/transactions/count/[address]'
import balanceEndpoint from 'pages/api/address/balance/[address]'
import dashboardEndpoint from 'pages/api/dashboard/index'
import paymentsEndpoint from 'pages/api/payments/index'
Expand Down Expand Up @@ -1285,6 +1286,24 @@ describe('GET /api/address/transactions/[address]', () => {
})
})

describe('GET /api/address/transactions/count/[address]', () => {
it('HTTP 400 when multiple address query parameters are provided', async () => {
const requestOptions: RequestOptions = {
method: 'GET' as RequestMethod,
headers: {
'Content-Type': 'application/json'
},
query: {
address: ['address1', 'address2']
}
}
const res = await testEndpoint(requestOptions, transactionCountEndpoint)
const responseData = res._getJSONData()
expect(res.statusCode).toBe(RESPONSE_MESSAGES.INVALID_ADDRESS_400.statusCode)
expect(responseData.message).toBe(RESPONSE_MESSAGES.INVALID_ADDRESS_400.message)
})
})

describe('GET /api/address/balance/[address]', () => {
const baseRequestOptions: RequestOptions = {
method: 'GET' as RequestMethod,
Expand All @@ -1300,6 +1319,22 @@ describe('GET /api/address/balance/[address]', () => {
const responseData = res._getJSONData()
expect(responseData.message).toBe(RESPONSE_MESSAGES.ADDRESS_NOT_PROVIDED_400.message)
})

it('Should return HTTP 400 when multiple address query parameters are provided', async () => {
const requestOptions: RequestOptions = {
method: 'GET' as RequestMethod,
headers: {
'Content-Type': 'application/json'
},
query: {
address: ['address1', 'address2']
}
}
const res = await testEndpoint(requestOptions, balanceEndpoint)
const responseData = res._getJSONData()
expect(res.statusCode).toBe(RESPONSE_MESSAGES.INVALID_ADDRESS_400.statusCode)
expect(responseData.message).toBe(RESPONSE_MESSAGES.INVALID_ADDRESS_400.message)
})
})

describe('GET /api/payments', () => {
Expand Down
6 changes: 6 additions & 0 deletions tests/unittests/validators.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ describe('parseAddress', () => {
v.parseAddress('')
}).toThrow(RESPONSE_MESSAGES.ADDRESS_NOT_PROVIDED_400.message)
})

it('Reject repeated query parameters passed as an array', () => {
expect(() => {
v.parseAddress([exampleAddresses.ecash, exampleAddresses.bitcoincash])
}).toThrow(RESPONSE_MESSAGES.INVALID_ADDRESS_400.message)
})
})

describe('parseError', () => {
Expand Down
5 changes: 4 additions & 1 deletion utils/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ const parseAddressTextBlock = function (addressBlock: string): string[] {
.filter((value, index, self) => self.indexOf(value) === index)
}

export const parseAddress = function (addressString: string | undefined): string {
export const parseAddress = function (addressString: string | string[] | undefined): string {
// Repeated query keys arrive as arrays. String methods like includes() then
// check membership instead of a substring, so reject non-strings before use.
if (Array.isArray(addressString)) throw new Error(RESPONSE_MESSAGES.INVALID_ADDRESS_400.message)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added INVALID_ADDRESS_400 handling to both routes and added repeated-address endpoint response tests in commit 83d123a3.

if (addressString === '' || addressString === undefined) throw new Error(RESPONSE_MESSAGES.ADDRESS_NOT_PROVIDED_400.message)
let parsedAddress: string
if (
Expand Down