@pagopa/io-react-native-wallet 0.13.1 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/commonjs/cie/component.js +180 -0
- package/lib/commonjs/cie/component.js.map +1 -0
- package/lib/commonjs/cie/error.js +44 -0
- package/lib/commonjs/cie/error.js.map +1 -0
- package/lib/commonjs/cie/index.js +32 -0
- package/lib/commonjs/cie/index.js.map +1 -0
- package/lib/commonjs/cie/manager.js +142 -0
- package/lib/commonjs/cie/manager.js.map +1 -0
- package/lib/commonjs/client/index.js +5 -2
- package/lib/commonjs/client/index.js.map +1 -1
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +144 -19
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +12 -4
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/commonjs/credential/issuance/index.js +18 -0
- package/lib/commonjs/credential/issuance/index.js.map +1 -1
- package/lib/commonjs/credential/issuance/types.js +9 -1
- package/lib/commonjs/credential/issuance/types.js.map +1 -1
- package/lib/commonjs/index.js +3 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/trust/types.js +5 -3
- package/lib/commonjs/trust/types.js.map +1 -1
- package/lib/commonjs/utils/decoder.js +28 -19
- package/lib/commonjs/utils/decoder.js.map +1 -1
- package/lib/module/cie/component.js +171 -0
- package/lib/module/cie/component.js.map +1 -0
- package/lib/module/cie/error.js +36 -0
- package/lib/module/cie/error.js.map +1 -0
- package/lib/module/cie/index.js +4 -0
- package/lib/module/cie/index.js.map +1 -0
- package/lib/module/cie/manager.js +133 -0
- package/lib/module/cie/manager.js.map +1 -0
- package/lib/module/client/index.js +5 -2
- package/lib/module/client/index.js.map +1 -1
- package/lib/module/credential/issuance/04-complete-user-authorization.js +141 -18
- package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js +12 -4
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/module/credential/issuance/index.js +2 -2
- package/lib/module/credential/issuance/index.js.map +1 -1
- package/lib/module/credential/issuance/types.js +7 -0
- package/lib/module/credential/issuance/types.js.map +1 -1
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/trust/types.js +5 -3
- package/lib/module/trust/types.js.map +1 -1
- package/lib/module/utils/decoder.js +28 -19
- package/lib/module/utils/decoder.js.map +1 -1
- package/lib/typescript/cie/component.d.ts +46 -0
- package/lib/typescript/cie/component.d.ts.map +1 -0
- package/lib/typescript/cie/error.d.ts +31 -0
- package/lib/typescript/cie/error.d.ts.map +1 -0
- package/lib/typescript/cie/index.d.ts +4 -0
- package/lib/typescript/cie/index.d.ts.map +1 -0
- package/lib/typescript/cie/manager.d.ts +5 -0
- package/lib/typescript/cie/manager.d.ts.map +1 -0
- package/lib/typescript/client/index.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +48 -1
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts +1 -0
- package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/index.d.ts +3 -3
- package/lib/typescript/credential/issuance/index.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/types.d.ts +10 -0
- package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/trust/index.d.ts +14 -14
- package/lib/typescript/trust/types.d.ts +142 -142
- package/lib/typescript/trust/types.d.ts.map +1 -1
- package/lib/typescript/utils/decoder.d.ts.map +1 -1
- package/package.json +6 -2
- package/src/cie/component.tsx +216 -0
- package/src/cie/error.ts +58 -0
- package/src/cie/index.ts +4 -0
- package/src/cie/manager.ts +183 -0
- package/src/client/index.ts +4 -1
- package/src/credential/issuance/04-complete-user-authorization.ts +216 -21
- package/src/credential/issuance/07-verify-and-parse-credential.ts +14 -6
- package/src/credential/issuance/index.ts +10 -0
- package/src/credential/issuance/types.ts +7 -0
- package/src/index.ts +2 -0
- package/src/trust/types.ts +8 -6
- package/src/utils/decoder.ts +28 -19
- package/lib/commonjs/credential/issuance/03-start-credential-issuance.js +0 -287
- package/lib/commonjs/credential/issuance/03-start-credential-issuance.js.map +0 -1
- package/lib/module/credential/issuance/03-start-credential-issuance.js +0 -276
- package/lib/module/credential/issuance/03-start-credential-issuance.js.map +0 -1
- package/lib/typescript/credential/issuance/03-start-credential-issuance.d.ts +0 -41
- package/lib/typescript/credential/issuance/03-start-credential-issuance.d.ts.map +0 -1
- package/src/credential/issuance/03-start-credential-issuance.ts +0 -407
@@ -4,12 +4,26 @@ import {
|
|
4
4
|
type AuthorizationContext,
|
5
5
|
type AuthorizationResult,
|
6
6
|
} from "../../utils/auth";
|
7
|
-
import { until, type Out } from "../../utils/misc";
|
7
|
+
import { hasStatus, until, type Out } from "../../utils/misc";
|
8
8
|
import type { StartUserAuthorization } from "./03-start-user-authorization";
|
9
9
|
import parseUrl from "parse-url";
|
10
|
-
import {
|
10
|
+
import {
|
11
|
+
AuthorizationError,
|
12
|
+
AuthorizationIdpError,
|
13
|
+
ValidationFailed,
|
14
|
+
} from "../../utils/errors";
|
11
15
|
import type { EvaluateIssuerTrust } from "./02-evaluate-issuer-trust";
|
12
16
|
import { Linking } from "react-native";
|
17
|
+
import {
|
18
|
+
decode,
|
19
|
+
encodeBase64,
|
20
|
+
SignJWT,
|
21
|
+
type CryptoContext,
|
22
|
+
} from "@pagopa/io-react-native-jwt";
|
23
|
+
import { RequestObject } from "../presentation/types";
|
24
|
+
import uuid from "react-native-uuid";
|
25
|
+
import { ResponseUriResultShape } from "./types";
|
26
|
+
import { getJwtFromFormPost } from "../../../src/utils/decoder";
|
13
27
|
|
14
28
|
/**
|
15
29
|
* The interface of the phase to complete User authorization via strong identification when the response mode is "query" and the request credential is a PersonIdentificationData.
|
@@ -23,6 +37,24 @@ export type CompleteUserAuthorizationWithQueryMode = (
|
|
23
37
|
authorizationContext?: AuthorizationContext
|
24
38
|
) => Promise<AuthorizationResult>;
|
25
39
|
|
40
|
+
export type CompleteUserAuthorizationWithFormPostJwtMode = (
|
41
|
+
requestObject: Out<GetRequestedCredentialToBePresented>,
|
42
|
+
context: {
|
43
|
+
wiaCryptoContext: CryptoContext;
|
44
|
+
pidCryptoContext: CryptoContext;
|
45
|
+
pid: string;
|
46
|
+
walletInstanceAttestation: string;
|
47
|
+
appFetch?: GlobalFetch["fetch"];
|
48
|
+
}
|
49
|
+
) => Promise<AuthorizationResult>;
|
50
|
+
|
51
|
+
export type GetRequestedCredentialToBePresented = (
|
52
|
+
issuerRequestUri: Out<StartUserAuthorization>["issuerRequestUri"],
|
53
|
+
clientId: Out<StartUserAuthorization>["clientId"],
|
54
|
+
issuerConf: Out<EvaluateIssuerTrust>["issuerConf"],
|
55
|
+
appFetch?: GlobalFetch["fetch"]
|
56
|
+
) => Promise<RequestObject>;
|
57
|
+
|
26
58
|
/**
|
27
59
|
* WARNING: This function must be called after {@link startUserAuthorization}. The next function to be called is {@link authorizeAccess}.
|
28
60
|
* The interface of the phase to complete User authorization via strong identification when the response mode is "query" and the request credential is a PersonIdentificationData.
|
@@ -49,11 +81,6 @@ export const completeUserAuthorizationWithQueryMode: CompleteUserAuthorizationWi
|
|
49
81
|
redirectUri,
|
50
82
|
authorizationContext
|
51
83
|
) => {
|
52
|
-
/**
|
53
|
-
* Starts the authorization flow which dependes on the response mode and the request credential.
|
54
|
-
* If the response mode is "query" the authorization flow is handled differently via the authorization context which opens an in-app browser capable of catching the redirectSchema.
|
55
|
-
* The form_post.jwt mode is not currently supported.
|
56
|
-
*/
|
57
84
|
const authzRequestEndpoint =
|
58
85
|
issuerConf.oauth_authorization_server.authorization_endpoint;
|
59
86
|
const params = new URLSearchParams({
|
@@ -97,22 +124,190 @@ export const completeUserAuthorizationWithQueryMode: CompleteUserAuthorizationWi
|
|
97
124
|
}
|
98
125
|
}
|
99
126
|
|
100
|
-
const
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
127
|
+
const query = parseUrl(authRedirectUrl).query;
|
128
|
+
return parseAuthroizationResponse(query);
|
129
|
+
};
|
130
|
+
|
131
|
+
/**
|
132
|
+
* WARNING: This function must be called after {@link startUserAuthorization}. The next function to be called is {@link completeUserAuthorizationWithFormPostJwtMode}.
|
133
|
+
* The interface of the phase to complete User authorization via presentation of existing credentials when the response mode is "form_post.jwt".
|
134
|
+
* It is used as a first step to complete the user authorization by obtaining the requested credential to be presented from the authorization server.
|
135
|
+
* The information is obtained by performing a GET request to the authorization endpoint with request_uri and client_id parameters.
|
136
|
+
* @param issuerRequestUri the URI of the issuer where the request is sent
|
137
|
+
* @param clientId Identifies the current client across all the requests of the issuing flow returned by {@link startUserAuthorization}
|
138
|
+
* @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
|
139
|
+
* @param appFetch (optional) fetch api implementation. Default: built-in fetch
|
140
|
+
* @throws {ValidationFailed} if an error while validating the response
|
141
|
+
* @returns the request object which contains the credential to be presented in order to obtain the requested credential
|
142
|
+
*/
|
143
|
+
export const getRequestedCredentialToBePresented: GetRequestedCredentialToBePresented =
|
144
|
+
async (issuerRequestUri, clientId, issuerConf, appFetch = fetch) => {
|
145
|
+
const authzRequestEndpoint =
|
146
|
+
issuerConf.oauth_authorization_server.authorization_endpoint;
|
147
|
+
const params = new URLSearchParams({
|
148
|
+
client_id: clientId,
|
149
|
+
request_uri: issuerRequestUri,
|
150
|
+
});
|
151
|
+
|
152
|
+
const requestObject = await appFetch(
|
153
|
+
`${authzRequestEndpoint}?${params.toString()}`,
|
154
|
+
{ method: "GET" }
|
155
|
+
)
|
156
|
+
.then(hasStatus(200))
|
157
|
+
.then((res) => res.text())
|
158
|
+
.then((jws) => decode(jws))
|
159
|
+
.then((reqObj) => RequestObject.safeParse(reqObj.payload));
|
160
|
+
|
161
|
+
if (!requestObject.success) {
|
162
|
+
throw new ValidationFailed(
|
163
|
+
"Request Object validation failed",
|
164
|
+
requestObject.error.message
|
110
165
|
);
|
111
166
|
}
|
112
|
-
return
|
167
|
+
return requestObject.data;
|
113
168
|
};
|
114
169
|
|
115
|
-
|
116
|
-
|
117
|
-
|
170
|
+
/**
|
171
|
+
* WARNING: This function must be called after {@link startUserAuthorization}. The next function to be called is {@link completeUserAuthorizationWithFormPostJwtMode}.
|
172
|
+
* The interface of the phase to complete User authorization via presentation of existing credentials when the response mode is "form_post.jwt".
|
173
|
+
* It is used as a first step to complete the user authorization by obtaining the requested credential to be presented from the authorization server.
|
174
|
+
* The information is obtained by performing a GET request to the authorization endpoint with request_uri and client_id parameters.
|
175
|
+
* @param issuerRequestUri the URI of the issuer where the request is sent
|
176
|
+
* @param clientId Identifies the current client across all the requests of the issuing flow returned by {@link startUserAuthorization}
|
177
|
+
* @param issuerConf The issuer configuration returned by {@link evaluateIssuerTrust}
|
178
|
+
* @param context.walletInstanceAccestation the Wallet Instance's attestation to be presented
|
179
|
+
* @param context.pid the PID to be presented
|
180
|
+
* @param context.wiaCryptoContext The Wallet Instance's crypto context associated with the walletInstanceAttestation parameter
|
181
|
+
* @param context.pidCryptoContext The PID crypto context associated with the pid parameter
|
182
|
+
* @param context.appFetch (optional) fetch api implementation. Default: built-in fetch
|
183
|
+
* @throws {ValidationFailed} if an error while validating the response
|
184
|
+
* @returns the authorization response which contains code, state and iss
|
185
|
+
*/
|
186
|
+
export const completeUserAuthorizationWithFormPostJwtMode: CompleteUserAuthorizationWithFormPostJwtMode =
|
187
|
+
async (requestObject, ctx) => {
|
188
|
+
const {
|
189
|
+
wiaCryptoContext,
|
190
|
+
pidCryptoContext,
|
191
|
+
pid,
|
192
|
+
walletInstanceAttestation,
|
193
|
+
appFetch = fetch,
|
194
|
+
} = ctx;
|
195
|
+
|
196
|
+
const wiaWpToken = await new SignJWT(wiaCryptoContext)
|
197
|
+
.setProtectedHeader({
|
198
|
+
alg: "ES256",
|
199
|
+
typ: "JWT",
|
200
|
+
})
|
201
|
+
.setPayload({
|
202
|
+
vp: walletInstanceAttestation,
|
203
|
+
jti: uuid.v4().toString(),
|
204
|
+
nonce: requestObject.nonce,
|
205
|
+
})
|
206
|
+
.setIssuedAt()
|
207
|
+
.setExpirationTime("5m")
|
208
|
+
.setAudience(requestObject.response_uri)
|
209
|
+
.sign();
|
210
|
+
|
211
|
+
const pidWpToken = await new SignJWT(pidCryptoContext)
|
212
|
+
.setProtectedHeader({
|
213
|
+
alg: "ES256",
|
214
|
+
typ: "JWT",
|
215
|
+
})
|
216
|
+
.setPayload({
|
217
|
+
vp: pid,
|
218
|
+
jti: uuid.v4().toString(),
|
219
|
+
nonce: requestObject.nonce,
|
220
|
+
})
|
221
|
+
.setIssuedAt()
|
222
|
+
.setExpirationTime("5m")
|
223
|
+
.setAudience(requestObject.response_uri)
|
224
|
+
.sign();
|
225
|
+
|
226
|
+
/* The path parameter refers to the vp_token variable of the authzResponsePayload and must point to the plain credential which
|
227
|
+
* is cointaned in the `vp` property of the signed jwt token payload
|
228
|
+
*/
|
229
|
+
const presentationSubmission = {
|
230
|
+
definition_id: `${uuid.v4()}`,
|
231
|
+
id: `${uuid.v4()}`,
|
232
|
+
descriptor_map: [
|
233
|
+
{
|
234
|
+
id: "PersonIdentificationData",
|
235
|
+
path: "$.vp_token[0].vp",
|
236
|
+
format: "vc+sd-jwt",
|
237
|
+
},
|
238
|
+
{
|
239
|
+
id: "WalletAttestation",
|
240
|
+
path: "$.vp_token[1].vp",
|
241
|
+
format: "jwt",
|
242
|
+
},
|
243
|
+
],
|
244
|
+
};
|
245
|
+
|
246
|
+
const authzResponsePayload = encodeBase64(
|
247
|
+
JSON.stringify({
|
248
|
+
state: requestObject.state,
|
249
|
+
presentation_submission: presentationSubmission,
|
250
|
+
vp_token: [pidWpToken, wiaWpToken],
|
251
|
+
})
|
252
|
+
);
|
253
|
+
|
254
|
+
// Note: according to the spec, the response should be encrypted with the public key of the RP however this is not implemented yet
|
255
|
+
// https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#name-signed-and-encrypted-response
|
256
|
+
// const rsaPublicJwk = chooseRSAPublicKeyToEncrypt(rpConf);
|
257
|
+
// const encrypted = await new EncryptJwe(authzResponsePayload, {
|
258
|
+
// alg: "RSA-OAEP-256",
|
259
|
+
// enc: "A256CBC-HS512",
|
260
|
+
// kid: rsaPublicJwk.kid,
|
261
|
+
// }).encrypt(rsaPublicJwk);
|
262
|
+
|
263
|
+
const body = new URLSearchParams({
|
264
|
+
response: authzResponsePayload,
|
265
|
+
}).toString();
|
266
|
+
const resUriRes = await appFetch(requestObject.response_uri, {
|
267
|
+
method: "POST",
|
268
|
+
headers: {
|
269
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
270
|
+
},
|
271
|
+
body,
|
272
|
+
})
|
273
|
+
.then(hasStatus(200))
|
274
|
+
.then((reqUri) => reqUri.json());
|
275
|
+
|
276
|
+
const responseUri = ResponseUriResultShape.safeParse(resUriRes);
|
277
|
+
if (!responseUri.success) {
|
278
|
+
throw new ValidationFailed(
|
279
|
+
"Response Uri validation failed",
|
280
|
+
responseUri.error.message
|
281
|
+
);
|
282
|
+
}
|
283
|
+
|
284
|
+
return await appFetch(responseUri.data.redirect_uri)
|
285
|
+
.then(hasStatus(200))
|
286
|
+
.then((res) => res.text())
|
287
|
+
.then(getJwtFromFormPost)
|
288
|
+
.then((cbRes) => parseAuthroizationResponse(cbRes.decodedJwt.payload));
|
289
|
+
};
|
290
|
+
|
291
|
+
/**
|
292
|
+
* Parse the authorization response and return the result which contains code, state and iss.
|
293
|
+
* @throws {AuthorizationError} if an error occurs during the parsing process
|
294
|
+
* @throws {AuthorizationIdpError} if an error occurs during the parsing process and the error is related to the IDP
|
295
|
+
* @param authRes the authorization response to be parsed
|
296
|
+
* @returns the authorization result which contains code, state and iss
|
297
|
+
*/
|
298
|
+
export const parseAuthroizationResponse = (
|
299
|
+
authRes: unknown
|
300
|
+
): AuthorizationResult => {
|
301
|
+
const authResParsed = AuthorizationResultShape.safeParse(authRes);
|
302
|
+
if (!authResParsed.success) {
|
303
|
+
const authErr = AuthorizationErrorShape.safeParse(authRes);
|
304
|
+
if (!authErr.success) {
|
305
|
+
throw new AuthorizationError(authResParsed.error.message); // an error occured while parsing the result and the error
|
306
|
+
}
|
307
|
+
throw new AuthorizationIdpError(
|
308
|
+
authErr.data.error,
|
309
|
+
authErr.data.error_description
|
310
|
+
);
|
311
|
+
}
|
312
|
+
return authResParsed.data;
|
118
313
|
};
|
@@ -13,6 +13,7 @@ export type VerifyAndParseCredential = (
|
|
13
13
|
format: Out<ObtainCredential>["format"],
|
14
14
|
context: {
|
15
15
|
credentialCryptoContext: CryptoContext;
|
16
|
+
ignoreMissingAttributes?: boolean;
|
16
17
|
}
|
17
18
|
) => Promise<{ parsedCredential: ParsedCredential }>;
|
18
19
|
|
@@ -42,7 +43,8 @@ type DecodedSdJwtCredential = Out<typeof verifySdJwt> & {
|
|
42
43
|
const parseCredentialSdJwt = (
|
43
44
|
// the list of supported credentials, as defined in the issuer configuration
|
44
45
|
credentials_supported: Out<EvaluateIssuerTrust>["issuerConf"]["openid_credential_issuer"]["credential_configurations_supported"],
|
45
|
-
{ sdJwt, disclosures }: DecodedSdJwtCredential
|
46
|
+
{ sdJwt, disclosures }: DecodedSdJwtCredential,
|
47
|
+
ignoreMissingAttributes: boolean = false
|
46
48
|
): ParsedCredential => {
|
47
49
|
const credentialSubject = credentials_supported[sdJwt.payload.vct];
|
48
50
|
|
@@ -57,6 +59,9 @@ const parseCredentialSdJwt = (
|
|
57
59
|
}
|
58
60
|
|
59
61
|
// transfrom a record { key: value } in an iterable of pairs [key, value]
|
62
|
+
if (!credentialSubject.claims) {
|
63
|
+
throw new IoWalletError("Missing claims in the credential subject"); // TODO [SIW-1268]: should not be optional
|
64
|
+
}
|
60
65
|
const attrDefinitions = Object.entries(credentialSubject.claims);
|
61
66
|
|
62
67
|
// the key of the attribute defintion must match the disclosure's name
|
@@ -66,9 +71,11 @@ const parseCredentialSdJwt = (
|
|
66
71
|
if (attrsNotInDisclosures.length > 0) {
|
67
72
|
const missing = attrsNotInDisclosures.map((_) => _[0 /* key */]).join(", ");
|
68
73
|
const received = disclosures.map((_) => _[1 /* name */]).join(", ");
|
69
|
-
|
70
|
-
|
71
|
-
|
74
|
+
if (!ignoreMissingAttributes) {
|
75
|
+
throw new IoWalletError(
|
76
|
+
`Some attributes are missing in the credential. Missing: [${missing}], received: [${received}]`
|
77
|
+
);
|
78
|
+
}
|
72
79
|
}
|
73
80
|
|
74
81
|
// attributes that are defined in the issuer configuration
|
@@ -169,7 +176,7 @@ const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
|
|
169
176
|
issuerConf,
|
170
177
|
credential,
|
171
178
|
_,
|
172
|
-
{ credentialCryptoContext }
|
179
|
+
{ credentialCryptoContext, ignoreMissingAttributes }
|
173
180
|
) => {
|
174
181
|
const decoded = await verifyCredentialSdJwt(
|
175
182
|
credential,
|
@@ -179,7 +186,8 @@ const verifyAndParseCredentialSdJwt: WithFormat<"vc+sd-jwt"> = async (
|
|
179
186
|
|
180
187
|
const parsedCredential = parseCredentialSdJwt(
|
181
188
|
issuerConf.openid_credential_issuer.credential_configurations_supported,
|
182
|
-
decoded
|
189
|
+
decoded,
|
190
|
+
ignoreMissingAttributes
|
183
191
|
);
|
184
192
|
|
185
193
|
return { parsedCredential };
|
@@ -9,7 +9,12 @@ import {
|
|
9
9
|
} from "./03-start-user-authorization";
|
10
10
|
import {
|
11
11
|
completeUserAuthorizationWithQueryMode,
|
12
|
+
completeUserAuthorizationWithFormPostJwtMode,
|
13
|
+
parseAuthroizationResponse,
|
12
14
|
type CompleteUserAuthorizationWithQueryMode,
|
15
|
+
type CompleteUserAuthorizationWithFormPostJwtMode,
|
16
|
+
type GetRequestedCredentialToBePresented,
|
17
|
+
getRequestedCredentialToBePresented,
|
13
18
|
} from "./04-complete-user-authorization";
|
14
19
|
import { authorizeAccess, type AuthorizeAccess } from "./05-authorize-access";
|
15
20
|
import {
|
@@ -25,15 +30,20 @@ export {
|
|
25
30
|
evaluateIssuerTrust,
|
26
31
|
startUserAuthorization,
|
27
32
|
completeUserAuthorizationWithQueryMode,
|
33
|
+
getRequestedCredentialToBePresented,
|
34
|
+
completeUserAuthorizationWithFormPostJwtMode,
|
28
35
|
authorizeAccess,
|
29
36
|
obtainCredential,
|
30
37
|
verifyAndParseCredential,
|
38
|
+
parseAuthroizationResponse,
|
31
39
|
};
|
32
40
|
export type {
|
33
41
|
StartFlow,
|
34
42
|
EvaluateIssuerTrust,
|
35
43
|
StartUserAuthorization,
|
36
44
|
CompleteUserAuthorizationWithQueryMode,
|
45
|
+
GetRequestedCredentialToBePresented,
|
46
|
+
CompleteUserAuthorizationWithFormPostJwtMode,
|
37
47
|
AuthorizeAccess,
|
38
48
|
ObtainCredential,
|
39
49
|
VerifyAndParseCredential,
|
@@ -22,4 +22,11 @@ export const CredentialResponse = z.object({
|
|
22
22
|
format: SupportedCredentialFormat,
|
23
23
|
});
|
24
24
|
|
25
|
+
/**
|
26
|
+
* Shape from parsing a response given by a request uri during the EAA credential issuance flow with response mode "form_post.jwt".
|
27
|
+
*/
|
28
|
+
export const ResponseUriResultShape = z.object({
|
29
|
+
redirect_uri: z.string(),
|
30
|
+
});
|
31
|
+
|
25
32
|
export type ResponseMode = "query" | "form_post.jwt";
|
package/src/index.ts
CHANGED
@@ -11,6 +11,7 @@ import * as Errors from "./utils/errors";
|
|
11
11
|
import * as WalletInstanceAttestation from "./wallet-instance-attestation";
|
12
12
|
import * as Trust from "./trust";
|
13
13
|
import * as WalletInstance from "./wallet-instance";
|
14
|
+
import * as Cie from "./cie";
|
14
15
|
import { AuthorizationDetail, AuthorizationDetails } from "./utils/par";
|
15
16
|
import { createCryptoContextFor } from "./utils/crypto";
|
16
17
|
import type { IntegrityContext } from "./utils/integrity";
|
@@ -27,6 +28,7 @@ export {
|
|
27
28
|
AuthorizationDetail,
|
28
29
|
AuthorizationDetails,
|
29
30
|
fixBase64EncodingOnKey,
|
31
|
+
Cie,
|
30
32
|
};
|
31
33
|
|
32
34
|
export type { IntegrityContext, AuthorizationContext };
|
package/src/trust/types.ts
CHANGED
@@ -37,10 +37,12 @@ type CredentialIssuerDisplayMetadata = z.infer<
|
|
37
37
|
const CredentialIssuerDisplayMetadata = z.object({
|
38
38
|
name: z.string(),
|
39
39
|
locale: z.string(),
|
40
|
-
logo: z
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
logo: z
|
41
|
+
.object({
|
42
|
+
url: z.string(),
|
43
|
+
alt_text: z.string(),
|
44
|
+
})
|
45
|
+
.optional(), // TODO [SIW-1268]: should not be optional
|
44
46
|
});
|
45
47
|
|
46
48
|
type ClaimsMetadata = z.infer<typeof ClaimsMetadata>;
|
@@ -57,7 +59,7 @@ const SupportedCredentialMetadata = z.object({
|
|
57
59
|
format: z.union([z.literal("vc+sd-jwt"), z.literal("vc+mdoc-cbor")]),
|
58
60
|
scope: z.string(),
|
59
61
|
display: z.array(CredentialDisplayMetadata),
|
60
|
-
claims: ClaimsMetadata,
|
62
|
+
claims: ClaimsMetadata.optional(), // TODO [SIW-1268]: should not be optional
|
61
63
|
cryptographic_binding_methods_supported: z.array(z.string()),
|
62
64
|
credential_signing_alg_values_supported: z.array(z.string()),
|
63
65
|
});
|
@@ -180,7 +182,7 @@ export const CredentialIssuerEntityConfiguration = BaseEntityConfiguration.and(
|
|
180
182
|
/** Credential Issuers act as Relying Party
|
181
183
|
when they require the presentation of other credentials.
|
182
184
|
This does not apply for PID issuance, which requires CIE authz. */
|
183
|
-
|
185
|
+
wallet_relying_party: RelyingPartyMetadata.optional(),
|
184
186
|
}),
|
185
187
|
}),
|
186
188
|
})
|
package/src/utils/decoder.ts
CHANGED
@@ -6,34 +6,43 @@ import { ValidationFailed } from "./errors";
|
|
6
6
|
* Decode a form_post.jwt and return the final JWT.
|
7
7
|
* The formData here is in form_post.jwt format as defined in
|
8
8
|
* JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
9
|
+
<!DOCTYPE html>
|
10
|
+
<html>
|
11
|
+
<head>
|
12
|
+
<meta charset="utf-8" />
|
13
|
+
</head>
|
14
|
+
<body onload="document.forms[0].submit()">
|
15
|
+
<noscript>
|
16
|
+
<p>
|
17
|
+
<strong>Note:</strong> Since your browser does not support JavaScript, you must press the Continue button once to proceed.
|
18
|
+
</p>
|
19
|
+
</noscript>
|
20
|
+
<form action="iowalletexample//cb" method="post">
|
21
|
+
<div>
|
22
|
+
<input type="hidden" name="response" value="somevalue" />
|
23
|
+
</div>
|
24
|
+
<noscript>
|
25
|
+
<div>
|
26
|
+
<input type="submit" value="Continue" />
|
27
|
+
</div>
|
28
|
+
</noscript>
|
29
|
+
</form>
|
30
|
+
</body>
|
31
|
+
</html>
|
23
32
|
*/
|
24
33
|
export const getJwtFromFormPost = async (
|
25
34
|
formData: string
|
26
35
|
): Promise<{ jwt: string; decodedJwt: JWTDecodeResult }> => {
|
27
|
-
const formPostRegex = /<input
|
36
|
+
const formPostRegex = /<input[^>]*name="response"[^>]*value="([^"]*)"/i;
|
28
37
|
const lineExpressionRegex = /\r\n|\n\r|\n|\r|\s+/g;
|
29
38
|
|
30
|
-
const
|
31
|
-
if (
|
32
|
-
const responseJwt =
|
39
|
+
const match = formPostRegex.exec(formData);
|
40
|
+
if (match && match[1]) {
|
41
|
+
const responseJwt = match[1];
|
33
42
|
|
34
43
|
if (responseJwt) {
|
35
44
|
const jwt = responseJwt.replace(lineExpressionRegex, "");
|
36
|
-
const decodedJwt =
|
45
|
+
const decodedJwt = decodeJwt(jwt);
|
37
46
|
return { jwt, decodedJwt };
|
38
47
|
}
|
39
48
|
}
|