Skip to content

Commit 3d5c477

Browse files
committed
Merge branch 'main' into pos-card-services
2 parents 673623a + 2fb0a36 commit 3d5c477

File tree

8 files changed

+86
-32
lines changed

8 files changed

+86
-32
lines changed

packages/auth/src/interaction/routes.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
import { Interaction, InteractionState } from './model'
2323
import { Grant, GrantState, GrantFinalization } from '../grant/model'
2424
import { Access } from '../access/model'
25-
import { generateNonce } from '../shared/utils'
25+
import { ensureTrailingSlash, generateNonce } from '../shared/utils'
2626
import { GNAPErrorCode } from '../shared/gnapErrors'
2727
import { generateBaseGrant } from '../tests/grant'
2828
import { generateBaseInteraction } from '../tests/interaction'
@@ -418,13 +418,14 @@ describe('Interaction Routes', (): void => {
418418
const { clientNonce } = grant
419419
const { nonce: interactNonce, ref: interactRef } = interaction
420420

421-
const grantRequestUrl = config.authServerUrl + `/`
422-
421+
const grantRequestUrl =
422+
ensureTrailingSlash(config.authServerUrl) + grant.tenantId
423423
const data = `${clientNonce}\n${interactNonce}\n${interactRef}\n${grantRequestUrl}`
424424
const hash = crypto
425425
.createHash('sha-256')
426426
.update(data)
427427
.digest('base64')
428+
428429
clientRedirectUri.searchParams.set('hash', hash)
429430
assert.ok(interactRef)
430431
clientRedirectUri.searchParams.set('interact_ref', interactRef)
@@ -434,6 +435,7 @@ describe('Interaction Routes', (): void => {
434435
await expect(interactionRoutes.finish(ctx)).resolves.toBeUndefined()
435436
expect(ctx.response).toSatisfyApiSpec()
436437
expect(ctx.status).toBe(302)
438+
437439
expect(redirectSpy).toHaveBeenCalledWith(clientRedirectUri.toString())
438440

439441
const issuedGrant = await Grant.query().findById(grant.id)

packages/auth/src/interaction/routes.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from '../grant/model'
1919
import { toOpenPaymentsAccess } from '../access/model'
2020
import { GNAPErrorCode, GNAPServerRouteError } from '../shared/gnapErrors'
21-
import { generateRouteLogs } from '../shared/utils'
21+
import { ensureTrailingSlash, generateRouteLogs } from '../shared/utils'
2222
import { SubjectService } from '../subject/service'
2323
import { toOpenPaymentsSubject } from '../subject/model'
2424
import { TenantService } from '../tenant/service'
@@ -377,7 +377,8 @@ async function handleFinishableGrant(
377377

378378
const { clientNonce } = grant
379379
const { nonce: interactNonce, ref: interactRef } = interaction
380-
const grantRequestUrl = config.authServerUrl + `/`
380+
const grantRequestUrl =
381+
ensureTrailingSlash(config.authServerUrl) + grant.tenantId
381382

382383
// https://datatracker.ietf.org/doc/html/draft-ietf-gnap-core-protocol#section-4.2.3
383384
const data = `${clientNonce}\n${interactNonce}\n${interactRef}\n${grantRequestUrl}`

packages/auth/src/shared/utils.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isValidDateString } from './utils'
1+
import { ensureTrailingSlash, isValidDateString } from './utils'
22

33
describe('utils', (): void => {
44
describe('isValidDateString', () => {
@@ -15,4 +15,13 @@ describe('utils', (): void => {
1515
expect(isValidDateString(input!)).toBe(expected)
1616
})
1717
})
18+
19+
describe('ensureTrailingSlash', (): void => {
20+
test('test ensuring trailing slash', async (): Promise<void> => {
21+
const path = '/utils'
22+
23+
expect(ensureTrailingSlash(path)).toBe(`${path}/`)
24+
expect(ensureTrailingSlash(`${path}/`)).toBe(`${path}/`)
25+
})
26+
})
1827
})

packages/auth/src/shared/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ export function generateRouteLogs(ctx: AppContext): {
2929
export function isValidDateString(date: string): boolean {
3030
return !isNaN(Date.parse(date))
3131
}
32+
33+
export function ensureTrailingSlash(str: string): string {
34+
if (!str.endsWith('/')) return `${str}/`
35+
return str
36+
}

packages/backend/src/shared/utils.test.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import {
1010
requestWithTimeout,
1111
sleep,
1212
getTenantFromApiSignature,
13-
ensureTrailingSlash,
14-
urlWithoutTenantId
13+
ensureTrailingSlash
1514
} from './utils'
1615
import { AppServices, AppContext } from '../app'
1716
import { TestContainer, createTestApp } from '../tests/app'
@@ -457,13 +456,4 @@ describe('utils', (): void => {
457456
expect(ensureTrailingSlash(path)).toBe(`${path}/`)
458457
expect(ensureTrailingSlash(`${path}/`)).toBe(`${path}/`)
459458
})
460-
461-
test('test tenant id stripped from url', async (): Promise<void> => {
462-
expect(
463-
urlWithoutTenantId(
464-
'http://happy-life-bank-test-auth:4106/cf5fd7d3-1eb1-4041-8e43-ba45747e9e5d'
465-
)
466-
).toBe('http://happy-life-bank-test-auth:4106')
467-
expect(urlWithoutTenantId('http://happy-life')).toBe('http://happy-life')
468-
})
469459
})

packages/backend/src/shared/utils.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,3 @@ export function ensureTrailingSlash(str: string): string {
241241
if (!str.endsWith('/')) return `${str}/`
242242
return str
243243
}
244-
245-
/**
246-
* @param url remove the tenant id from the {url}
247-
*/
248-
export function urlWithoutTenantId(url: string): string {
249-
if (url.length > 36 && validateId(url.slice(-36))) return url.slice(0, -37)
250-
return url
251-
}

test/integration/integration.test.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,18 +200,27 @@ describe('Integration tests', (): void => {
200200
quoteGrant.access_token.value,
201201
incomingPayment
202202
)
203+
204+
const clientNonce = crypto.randomUUID()
205+
const finishUri = 'https://example.com'
206+
203207
const outgoingPaymentGrant = await grantRequestOutgoingPayment(
204208
senderWalletAddress,
205209
{ receiveAmount: quote.receiveAmount },
206210
{
207211
method: 'redirect',
208-
uri: 'https://example.com',
209-
nonce: '456'
212+
uri: finishUri,
213+
nonce: clientNonce
210214
}
211215
)
212216
const interactRef = await consentInteractionWithInteractRef(
213217
outgoingPaymentGrant,
214-
senderWalletAddress
218+
senderWalletAddress,
219+
{
220+
clientNonce,
221+
finishUri,
222+
initialGrantUrl: senderWalletAddress.authServer
223+
}
215224
)
216225
const finalizedGrant = await grantContinue(
217226
outgoingPaymentGrant,

test/integration/lib/test-actions/index.ts

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import assert from 'assert'
2+
import { createHash } from 'crypto'
23
import type { MockASE } from 'test-lib'
34
import { parseCookies, urlWithoutTenantId } from '../utils'
45
import { WalletAddress, PendingGrant } from '@interledger/open-payments'
@@ -11,14 +12,21 @@ export interface TestActionsDeps {
1112
receivingASE: MockASE
1213
}
1314

15+
interface InteractionArgs {
16+
clientNonce: string
17+
initialGrantUrl: string
18+
finishUri: string
19+
}
20+
1421
export interface TestActions {
1522
consentInteraction(
1623
outgoingPaymentGrant: PendingGrant,
1724
senderWalletAddress: WalletAddress
1825
): Promise<void>
1926
consentInteractionWithInteractRef(
2027
outgoingPaymentGrant: PendingGrant,
21-
senderWalletAddress: WalletAddress
28+
senderWalletAddress: WalletAddress,
29+
args: InteractionArgs
2230
): Promise<string>
2331
admin: AdminActions
2432
openPayments: OpenPaymentsActions
@@ -31,12 +39,14 @@ export function createTestActions(deps: TestActionsDeps): TestActions {
3139
consentInteraction(deps, outgoingPaymentGrant, senderWalletAddress),
3240
consentInteractionWithInteractRef: (
3341
outgoingPaymentGrant,
34-
senderWalletAddress
42+
senderWalletAddress,
43+
args
3544
) =>
3645
consentInteractionWithInteractRef(
3746
deps,
3847
outgoingPaymentGrant,
39-
senderWalletAddress
48+
senderWalletAddress,
49+
args
4050
),
4151
admin: createAdminActions(deps),
4252
openPayments: createOpenPaymentsActions(deps),
@@ -73,7 +83,8 @@ async function consentInteraction(
7383
async function consentInteractionWithInteractRef(
7484
deps: TestActionsDeps,
7585
outgoingPaymentGrant: PendingGrant,
76-
senderWalletAddress: WalletAddress
86+
senderWalletAddress: WalletAddress,
87+
interactionArgs: InteractionArgs
7788
): Promise<string> {
7889
const { idpSecret } = deps.sendingASE.config
7990
const { interactId, nonce, cookie } = await _startAndAcceptInteraction(
@@ -98,14 +109,49 @@ async function consentInteractionWithInteractRef(
98109

99110
const redirectURI = finishResponse.headers.get('location')
100111
assert(redirectURI)
112+
expect(redirectURI.startsWith(interactionArgs.finishUri))
101113

102114
const url = new URL(redirectURI)
103115
const interact_ref = url.searchParams.get('interact_ref')
116+
const hash = url.searchParams.get('hash')
117+
118+
assert(hash)
119+
assert(interact_ref)
120+
121+
verifyHash({
122+
initialGrantUrl: interactionArgs.initialGrantUrl,
123+
clientNonce: interactionArgs.clientNonce,
124+
interactNonce: nonce,
125+
receivedHash: hash,
126+
interactRef: interact_ref
127+
})
104128
assert(interact_ref)
105129

106130
return interact_ref
107131
}
108132

133+
interface VerifyHashArgs {
134+
clientNonce: string
135+
initialGrantUrl: string
136+
receivedHash: string
137+
interactNonce: string
138+
interactRef: string
139+
}
140+
141+
async function verifyHash(args: VerifyHashArgs) {
142+
const {
143+
clientNonce,
144+
interactNonce,
145+
interactRef,
146+
initialGrantUrl,
147+
receivedHash
148+
} = args
149+
const data = `${clientNonce}\n${interactNonce}\n${interactRef}\n${initialGrantUrl}`
150+
const hash = createHash('sha-256').update(data).digest('base64')
151+
152+
expect(hash).toBe(receivedHash)
153+
}
154+
109155
async function _startAndAcceptInteraction(
110156
deps: TestActionsDeps,
111157
outgoingPaymentGrant: PendingGrant,

0 commit comments

Comments
 (0)