From fe18cd0e2c1d65e51a0badfb22e32106028ba13c Mon Sep 17 00:00:00 2001 From: Blair Currey <12960453+BlairCurrey@users.noreply.github.com> Date: Fri, 1 Mar 2024 10:01:33 -0500 Subject: [PATCH] feat: update receiver regex validation (#430) * feat: update receiver regex validation * fix: example url typo * Update openapi/schemas.yaml Co-authored-by: Max Kurapov * chore: add changeset * test(openapi): add quote validation tests * chore: generate new types --------- Co-authored-by: Max Kurapov --- .changeset/fuzzy-rivers-jog.md | 5 + openapi/auth-server.yaml | 2 +- openapi/schemas.yaml | 7 +- .../openapi/generated/auth-server-types.ts | 2 +- .../generated/resource-server-types.ts | 2 +- .../generated/wallet-address-server-types.ts | 2 +- packages/openapi/src/middleware.test.ts | 98 +++++++++++++++++++ 7 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 .changeset/fuzzy-rivers-jog.md diff --git a/.changeset/fuzzy-rivers-jog.md b/.changeset/fuzzy-rivers-jog.md new file mode 100644 index 00000000..a0c1c360 --- /dev/null +++ b/.changeset/fuzzy-rivers-jog.md @@ -0,0 +1,5 @@ +--- +'@interledger/open-payments': minor +--- + +Widened receiver regex to accept http and any id format. Removed previously deprecated 'connections' path. diff --git a/openapi/auth-server.yaml b/openapi/auth-server.yaml index 66129f2f..1f868fce 100644 --- a/openapi/auth-server.yaml +++ b/openapi/auth-server.yaml @@ -110,7 +110,7 @@ paths: - read identifier: 'https://ilp.rafiki.money/alice' limits: - receiver: 'https://ilp.rafiki.money/connections/45a0d0ee-26dc-4c66-89e0-01fbf93156f7' + receiver: 'https://ilp.rafiki.money/incoming-payments/45a0d0ee-26dc-4c66-89e0-01fbf93156f7' interval: 'R12/2019-08-24T14:15:22Z/P1M' debitAmount: value: '500' diff --git a/openapi/schemas.yaml b/openapi/schemas.yaml index fc0bce44..c08ff832 100644 --- a/openapi/schemas.yaml +++ b/openapi/schemas.yaml @@ -40,12 +40,13 @@ components: receiver: title: Receiver type: string - description: The URL of the incoming payment or ILP STREAM connection that is being paid. + description: The URL of the incoming payment that is being paid. format: uri - pattern: '^https://(.+)/(incoming-payments|connections)/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' + pattern: '^(https|http)://(.+)/incoming-payments/(.+)$' examples: - 'https://ilp.rafiki.money/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c' - - 'https://ilp.rafiki.money/connections/016da9d5-c9a4-4c80-a354-86b915a04ff8' + - 'http://ilp.rafiki.money/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c' + - 'https://ilp.rafiki.money/incoming-payments/1' walletAddress: title: Wallet Address type: string diff --git a/packages/open-payments/src/openapi/generated/auth-server-types.ts b/packages/open-payments/src/openapi/generated/auth-server-types.ts index 3a2e6c65..2f8f4943 100644 --- a/packages/open-payments/src/openapi/generated/auth-server-types.ts +++ b/packages/open-payments/src/openapi/generated/auth-server-types.ts @@ -337,7 +337,7 @@ export interface external { /** * Receiver * Format: uri - * @description The URL of the incoming payment or ILP STREAM connection that is being paid. + * @description The URL of the incoming payment that is being paid. */ receiver: string; /** diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index 7320e577..641e229c 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -629,7 +629,7 @@ export interface external { /** * Receiver * Format: uri - * @description The URL of the incoming payment or ILP STREAM connection that is being paid. + * @description The URL of the incoming payment that is being paid. */ receiver: string; /** diff --git a/packages/open-payments/src/openapi/generated/wallet-address-server-types.ts b/packages/open-payments/src/openapi/generated/wallet-address-server-types.ts index 12d1082c..3e4d0c6d 100644 --- a/packages/open-payments/src/openapi/generated/wallet-address-server-types.ts +++ b/packages/open-payments/src/openapi/generated/wallet-address-server-types.ts @@ -156,7 +156,7 @@ export interface external { /** * Receiver * Format: uri - * @description The URL of the incoming payment or ILP STREAM connection that is being paid. + * @description The URL of the incoming payment that is being paid. */ receiver: string; /** diff --git a/packages/openapi/src/middleware.test.ts b/packages/openapi/src/middleware.test.ts index 7aa14187..29e08e2a 100644 --- a/packages/openapi/src/middleware.test.ts +++ b/packages/openapi/src/middleware.test.ts @@ -256,6 +256,104 @@ describe('OpenAPI Validator', (): void => { expect(next).toHaveBeenCalled() } ) + + describe('Quote', (): void => { + let validateQuotePostMiddleware: AppMiddleware + + beforeAll((): void => { + validateQuotePostMiddleware = createValidatorMiddleware(openApi, { + path: '/quotes', + method: HttpMethod.POST + }) + }) + + test.each` + body | description + ${{ receiver: 'ht999tp://something.com/incoming-payments' }} | ${'invalid receiver, unknown protocol'} + ${{ receiver: 'http://something.com/incoming-payments' }} | ${'invalid receiver, missing incoming payment id'} + ${{ receiver: 'http://something.com/connections/c3a0d182-b221-4612-a500-07ad106b5f5d' }} | ${'invalid receiver, wrong path'} + `( + 'returns 400 on invalid quote body ($description)', + async ({ body }): Promise => { + const ctx = createContext( + { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + }, + {} + ) + addTestSignatureHeaders(ctx) + ctx.request.body = { + ...body, + walletAddress: WALLET_ADDRESS, + method: 'ilp' + } + await expect( + validateQuotePostMiddleware(ctx, next) + ).rejects.toMatchObject({ + status: 400, + message: + 'body.receiver must match pattern "^(https|http):..(.+).incoming-payments.(.+)$"' + }) + expect(next).not.toHaveBeenCalled() + } + ) + test.each` + receiver | description + ${'http://something.com/incoming-payments/c3a0d182-b221-4612-a500-07ad106b5f5d'} | ${'accepts http and uuid'} + ${'https://something.com/incoming-payments/123'} | ${'accepts http and non uuid id format'} + `( + 'calls next on valid request: ($description)', + async ({ receiver }): Promise => { + const ctx = createContext( + { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + url: '/quotes' + }, + {} + ) + addTestSignatureHeaders(ctx) + ctx.request.body = { + receiver, + walletAddress: WALLET_ADDRESS, + method: 'ilp' + } + const next = jest.fn().mockImplementation(() => { + expect(ctx.request.body.receiver).toEqual(receiver) + ctx.status = 201 + ctx.response.body = { + id: 'https://something-else/quotes/3b461206-daae-4d97-88b0-abffbcaa6f96', + walletAddress: 'https://something-else/accounts/someone', + receiveAmount: { + value: '100', + assetCode: 'USD', + assetScale: 2 + }, + debitAmount: { + value: '205', + assetCode: 'USD', + assetScale: 2 + }, + receiver, + expiresAt: '2024-02-28T16:26:32.444Z', + createdAt: '2024-02-28T16:21:32.444Z', + method: 'ilp' + } + }) + + await expect( + validateQuotePostMiddleware(ctx, next) + ).resolves.toBeUndefined() + + expect(next).toHaveBeenCalled() + } + ) + }) }) })