Skip to content

Commit 55aa0a1

Browse files
njliecozminu
andauthored
feat(localenv): expose subject during consent in mock-ase (#3666)
* feat(localenv): expose subject during consent in mock-ase * feat: include client name in subject grant line * fix(mase): grantId not being retrieved * fix(mase): consent and confirmation texts * fix: handle subject-only grants properly --------- Co-authored-by: Cozmin Ungureanu <[email protected]>
1 parent 751dad2 commit 55aa0a1

File tree

8 files changed

+238
-39
lines changed

8 files changed

+238
-39
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
meta {
2+
name: Continuation Request
3+
type: http
4+
seq: 8
5+
}
6+
7+
post {
8+
url: {{senderOpenPaymentsContinuationUri}}
9+
body: json
10+
auth: none
11+
}
12+
13+
headers {
14+
Authorization: GNAP {{continueToken}}
15+
}
16+
17+
script:pre-request {
18+
const scripts = require('./scripts');
19+
20+
await scripts.addSignatureHeaders();
21+
}
22+
23+
script:post-response {
24+
const scripts = require('./scripts');
25+
26+
scripts.storeTokenDetails();
27+
}
28+
29+
tests {
30+
test("Status code is 200", function() {
31+
expect(res.getStatus()).to.equal(200);
32+
});
33+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
meta {
2+
name: Get sender wallet address
3+
type: http
4+
seq: 1
5+
}
6+
7+
get {
8+
url: {{senderWalletAddress}}
9+
body: none
10+
auth: none
11+
}
12+
13+
headers {
14+
Accept: application/json
15+
}
16+
17+
script:pre-request {
18+
const scripts = require('./scripts');
19+
20+
scripts.addHostHeader("senderOpenPaymentsHost");
21+
}
22+
23+
script:post-response {
24+
const url = require('url')
25+
26+
if (res.getStatus() !== 200) {
27+
return
28+
}
29+
30+
const body = res.getBody()
31+
bru.setEnvVar("senderAssetCode", body?.assetCode)
32+
bru.setEnvVar("senderAssetScale", body?.assetScale)
33+
34+
const authUrl = url.parse(body?.authServer)
35+
if (
36+
authUrl.hostname.includes('cloud-nine-wallet') ||
37+
authUrl.hostname.includes('happy-life-bank')
38+
){
39+
const port = authUrl.hostname.includes('cloud-nine-wallet')? authUrl.port: Number(authUrl.port) + 1000
40+
bru.setEnvVar("senderOpenPaymentsAuthHost", authUrl.protocol + '//localhost:' + port + authUrl.path);
41+
} else {
42+
bru.setEnvVar("senderOpenPaymentsAuthHost", body?.authServer);
43+
}
44+
45+
const resourceUrl = url.parse(body?.resourceServer)
46+
if (resourceUrl.hostname.includes('cloud-nine-wallet') || resourceUrl.hostname.includes('happy-life-bank')) {
47+
const port = resourceUrl.hostname.includes('happy-life-bank') ? bru.getEnvVar('happyLifeOpenPaymentsPort') : bru.getEnvVar('cloudNineOpenPaymentsPort')
48+
bru.setEnvVar("senderOpenPaymentsHost", 'http://localhost:' + port + resourceUrl.path);
49+
} else {
50+
bru.setEnvVar("senderOpenPaymentsHost", body?.resourceServer);
51+
}
52+
}
53+
54+
tests {
55+
test("Status code is 200", function() {
56+
expect(res.getStatus()).to.equal(200);
57+
});
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
meta {
2+
name: Grant Request for Subject Information
3+
type: http
4+
seq: 7
5+
}
6+
7+
post {
8+
url: {{senderOpenPaymentsAuthHost}}
9+
body: json
10+
auth: none
11+
}
12+
13+
body:json {
14+
{
15+
"subject": {
16+
"sub_ids": [
17+
{
18+
"id": "{{senderWalletAddress}}",
19+
"format": "uri"
20+
}
21+
]
22+
},
23+
"client": "{{clientWalletAddress}}",
24+
"interact": {
25+
"start": [
26+
"redirect"
27+
]
28+
}
29+
}
30+
31+
}
32+
33+
script:pre-request {
34+
const scripts = require('./scripts');
35+
36+
await scripts.addSignatureHeaders();
37+
}
38+
39+
script:post-response {
40+
const scripts = require('./scripts');
41+
42+
scripts.storeTokenDetails();
43+
44+
const body = res.getBody()
45+
bru.setEnvVar("senderOpenPaymentsContinuationUri", body?.continue.uri)
46+
}
47+
48+
tests {
49+
test("Status code is 200", function() {
50+
expect(res.getStatus()).to.equal(200);
51+
});
52+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
meta {
2+
name: Vailidating Wallet Address Ownership with Open Payments
3+
seq: 6
4+
}

localenv/mock-account-servicing-entity/app/lib/apiClient.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ export class ApiClient {
5050
if (response.status === 200) {
5151
return {
5252
isFailure: false,
53-
payload: response.data.access,
53+
payload: {
54+
access: response.data.access,
55+
subject: response.data.subject,
56+
grantId: response.data.grantId,
57+
state: response.data.state
58+
},
5459
contextUpdates: {
5560
grant: response.data
5661
}

localenv/mock-account-servicing-entity/app/lib/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ export interface Access {
2828
limits?: AccessLimit
2929
}
3030

31+
export interface SubjectId {
32+
id: string
33+
format: string
34+
}
35+
3136
export type InstanceConfig = {
3237
name: string
3338
logo: string

localenv/mock-account-servicing-entity/app/routes/mock-idp._index.tsx

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { Dispatch, SetStateAction } from 'react'
88
import { useEffect, useState } from 'react'
99
import { Button } from '~/components'
1010
import { ApiClient } from '~/lib/apiClient'
11-
import type { Access, InstanceConfig } from '~/lib/types'
11+
import type { Access, InstanceConfig, SubjectId } from '~/lib/types'
1212
import { CONFIG } from '~/lib/parse_config.server'
1313

1414
interface ConsentScreenContext {
@@ -20,6 +20,7 @@ interface ConsentScreenContext {
2020
returnUrl: string
2121
accesses: Array<Access> | null
2222
outgoingPaymentAccess: Access | null
23+
subjectId: SubjectId | null
2324
price: GrantAmount | null
2425
costToUser: GrantAmount | null
2526
errors: Array<Error>
@@ -47,19 +48,23 @@ export function loader() {
4748
function ConsentScreenBody({
4849
_thirdPartyUri,
4950
thirdPartyName,
51+
accesses,
5052
price,
5153
costToUser,
5254
interactId,
5355
nonce,
54-
returnUrl
56+
returnUrl,
57+
subjectId
5558
}: {
5659
_thirdPartyUri: string
5760
thirdPartyName: string
61+
accesses: Access[] | null
5862
price: GrantAmount | null
5963
costToUser: GrantAmount | null
6064
interactId: string
6165
nonce: string
6266
returnUrl: string
67+
subjectId: SubjectId | null
6368
}) {
6469
const chooseConsent = (accept: boolean) => {
6570
const href = new URL(returnUrl)
@@ -72,31 +77,46 @@ function ConsentScreenBody({
7277
return (
7378
<>
7479
<div className='bg-white rounded-md p-8 px-16'>
75-
<div className='col-12'>
76-
{price && (
77-
<p>
78-
{thirdPartyName} wants to send {price.currencyDisplayCode}{' '}
79-
{price.amount.toFixed(2)} to its account.
80-
</p>
81-
)}
80+
<div className='row mt-2'>
81+
<div className='col-12'>
82+
{subjectId && (
83+
<p>
84+
{thirdPartyName} is asking you to confirm ownership of{' '}
85+
{subjectId.id}.
86+
</p>
87+
)}
88+
</div>
89+
</div>
90+
<div className='row mt-2'>
91+
<div className='col-12'>
92+
{price && (
93+
<p>
94+
{thirdPartyName} wants to send {price.currencyDisplayCode}{' '}
95+
{price.amount.toFixed(2)} to its account.
96+
</p>
97+
)}
98+
</div>
8299
</div>
83100
<div className='row mt-2'>
84101
<div className='col-12'>
85102
{costToUser && (
86103
<p>
87-
This will cost you {costToUser.currencyDisplayCode}{' '}
104+
You will be charged {costToUser.currencyDisplayCode}{' '}
88105
{costToUser.amount.toFixed(2)}
89106
</p>
90107
)}
91108
</div>
92109
</div>
93110
<div className='row mt-2'>
94111
<div className='col-12'>
95-
{!price && !costToUser && (
112+
{accesses?.length &&
113+
accesses.length > 0 &&
114+
!price &&
115+
!costToUser ? (
96116
<p>
97117
{thirdPartyName} is requesting grant for an unlimited amount
98118
</p>
99-
)}
119+
) : undefined}
100120
</div>
101121
</div>
102122
<div className='row mt-2'>
@@ -238,6 +258,7 @@ export default function ConsentScreen({ idpSecretParam }: ConsentScreenProps) {
238258
//TODO returnUrl: 'http://localhost:3030/mock-idp/consent?interactid=demo-interact-id&nonce=demo-interact-nonce',
239259
accesses: null,
240260
outgoingPaymentAccess: null,
261+
subjectId: null,
241262
price: null,
242263
costToUser: null,
243264
errors: new Array<Error>()
@@ -292,21 +313,21 @@ export default function ConsentScreen({ idpSecretParam }: ConsentScreenProps) {
292313
...ctx,
293314
errors: response.errors.map((e) => new Error(e))
294315
})
295-
} else if (!response.payload) {
316+
} else if (!response.payload.access && !response.payload.subject) {
296317
setCtx({
297318
...ctx,
298-
errors: [new Error('no accesses in grant')]
319+
errors: [new Error('no accesses or subjects in grant')]
299320
})
300321
} else {
301322
const outgoingPaymentAccess =
302-
response.payload.find(
323+
response.payload.access.find(
303324
// eslint-disable-next-line @typescript-eslint/no-explicit-any
304325
(p: Record<string, any>) => p.type === 'outgoing-payment'
305326
) || null
306327
const returnUrlObject = new URL(ctx.returnUrl)
307328
returnUrlObject.searchParams.append(
308329
'grantId',
309-
outgoingPaymentAccess.grantId
330+
response.payload.grantId
310331
)
311332
returnUrlObject.searchParams.append(
312333
'thirdPartyName',
@@ -334,17 +355,24 @@ export default function ConsentScreen({ idpSecretParam }: ConsentScreenProps) {
334355
outgoingPaymentAccess?.limits?.receiveAmount?.assetScale ??
335356
null
336357
)
358+
if (outgoingPaymentAccess) {
359+
returnUrlObject.searchParams.append(
360+
'amountType',
361+
outgoingPaymentAccess.limits?.receiveAmount
362+
? AmountType.RECEIVE
363+
: outgoingPaymentAccess.limits?.debitAmount
364+
? AmountType.DEBIT
365+
: AmountType.UNLIMITED
366+
)
367+
}
337368
returnUrlObject.searchParams.append(
338-
'amountType',
339-
outgoingPaymentAccess?.limits?.receiveAmount
340-
? AmountType.RECEIVE
341-
: outgoingPaymentAccess?.limits?.debitAmount
342-
? AmountType.DEBIT
343-
: AmountType.UNLIMITED
369+
'subjectId',
370+
response.payload.subject.sub_ids[0]?.id ?? null
344371
)
345372
setCtx({
346373
...ctx,
347-
accesses: response.payload,
374+
accesses: response.payload.access,
375+
subjectId: response.payload.subject.sub_ids[0],
348376
outgoingPaymentAccess: outgoingPaymentAccess,
349377
thirdPartyName: ctx.thirdPartyName,
350378
thirdPartyUri: ctx.thirdPartyUri,
@@ -433,11 +461,13 @@ export default function ConsentScreen({ idpSecretParam }: ConsentScreenProps) {
433461
<ConsentScreenBody
434462
_thirdPartyUri={ctx.thirdPartyUri}
435463
thirdPartyName={ctx.thirdPartyName}
464+
accesses={ctx.accesses}
436465
price={ctx.price}
437466
costToUser={ctx.costToUser}
438467
interactId={ctx.interactId}
439468
nonce={ctx.nonce}
440469
returnUrl={ctx.returnUrl}
470+
subjectId={ctx.subjectId}
441471
/>
442472
)}
443473
</>

0 commit comments

Comments
 (0)