@pagopa/io-wallet-oid4vci 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +4449 -419
- package/dist/index.d.ts +4449 -419
- package/dist/index.js +449 -217
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +402 -164
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -196,7 +196,12 @@ async function sendAuthorizationResponseAndExtractCode(options) {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
// src/credential-offer/extract-grant-details.ts
|
|
199
|
-
|
|
199
|
+
import {
|
|
200
|
+
ItWalletSpecsVersion,
|
|
201
|
+
ItWalletSpecsVersionError,
|
|
202
|
+
createVersionDispatcher
|
|
203
|
+
} from "@pagopa/io-wallet-utils";
|
|
204
|
+
function requireAuthorizationCodeGrant(credentialOffer) {
|
|
200
205
|
if (!credentialOffer.grants) {
|
|
201
206
|
throw new CredentialOfferError("No grants found in credential offer");
|
|
202
207
|
}
|
|
@@ -204,6 +209,10 @@ function extractGrantDetails(credentialOffer) {
|
|
|
204
209
|
if (!authCodeGrant) {
|
|
205
210
|
throw new CredentialOfferError("authorization_code grant not found");
|
|
206
211
|
}
|
|
212
|
+
return authCodeGrant;
|
|
213
|
+
}
|
|
214
|
+
function extractGrantDetailsV1_3(options) {
|
|
215
|
+
const authCodeGrant = requireAuthorizationCodeGrant(options.credentialOffer);
|
|
207
216
|
return {
|
|
208
217
|
authorizationCodeGrant: {
|
|
209
218
|
authorizationServer: authCodeGrant.authorization_server,
|
|
@@ -213,10 +222,37 @@ function extractGrantDetails(credentialOffer) {
|
|
|
213
222
|
grantType: "authorization_code"
|
|
214
223
|
};
|
|
215
224
|
}
|
|
225
|
+
function extractGrantDetailsV1_4(options) {
|
|
226
|
+
const authCodeGrant = requireAuthorizationCodeGrant(options.credentialOffer);
|
|
227
|
+
return {
|
|
228
|
+
authorizationCodeGrant: {
|
|
229
|
+
authorizationServer: authCodeGrant.authorization_server,
|
|
230
|
+
issuerState: authCodeGrant.issuer_state
|
|
231
|
+
},
|
|
232
|
+
grantType: "authorization_code"
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
var dispatchExtractGrantDetails = createVersionDispatcher({
|
|
236
|
+
[ItWalletSpecsVersion.V1_0]: () => {
|
|
237
|
+
throw new ItWalletSpecsVersionError(
|
|
238
|
+
"extractGrantDetails",
|
|
239
|
+
ItWalletSpecsVersion.V1_0,
|
|
240
|
+
[ItWalletSpecsVersion.V1_3, ItWalletSpecsVersion.V1_4]
|
|
241
|
+
);
|
|
242
|
+
},
|
|
243
|
+
[ItWalletSpecsVersion.V1_3]: (o) => extractGrantDetailsV1_3(o),
|
|
244
|
+
[ItWalletSpecsVersion.V1_4]: (o) => extractGrantDetailsV1_4(o)
|
|
245
|
+
});
|
|
246
|
+
function extractGrantDetails(options) {
|
|
247
|
+
return dispatchExtractGrantDetails(options);
|
|
248
|
+
}
|
|
216
249
|
|
|
217
250
|
// src/credential-offer/z-credential-offer.ts
|
|
251
|
+
import { z as z4 } from "zod";
|
|
252
|
+
|
|
253
|
+
// src/credential-offer/v1.3/z-credential-offer.ts
|
|
218
254
|
import { z as z2 } from "zod";
|
|
219
|
-
var
|
|
255
|
+
var zAuthorizationCodeGrantV1_3 = z2.object({
|
|
220
256
|
/**
|
|
221
257
|
* CONDITIONALLY REQUIRED. HTTPS URL of the Authorization Server.
|
|
222
258
|
* REQUIRED only when the Credential Issuer uses multiple Authorization Servers.
|
|
@@ -234,14 +270,14 @@ var zAuthorizationCodeGrant = z2.object({
|
|
|
234
270
|
*/
|
|
235
271
|
scope: z2.string()
|
|
236
272
|
});
|
|
237
|
-
var
|
|
273
|
+
var zCredentialOfferGrantsV1_3 = z2.object({
|
|
238
274
|
/**
|
|
239
275
|
* REQUIRED. Authorization Code grant details.
|
|
240
276
|
* IT-Wallet v1.3 only supports authorization_code grant.
|
|
241
277
|
*/
|
|
242
|
-
authorization_code:
|
|
278
|
+
authorization_code: zAuthorizationCodeGrantV1_3
|
|
243
279
|
});
|
|
244
|
-
var
|
|
280
|
+
var zCredentialOfferV1_3 = z2.object({
|
|
245
281
|
/**
|
|
246
282
|
* REQUIRED. Array of credential configuration identifiers.
|
|
247
283
|
* References the types of credentials offered as defined in the Credential Issuer metadata.
|
|
@@ -256,24 +292,66 @@ var zCredentialOffer = z2.object({
|
|
|
256
292
|
* REQUIRED. Grant information for the credential offer.
|
|
257
293
|
* IT-Wallet v1.3 requires authorization_code grant.
|
|
258
294
|
*/
|
|
259
|
-
grants:
|
|
295
|
+
grants: zCredentialOfferGrantsV1_3
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// src/credential-offer/v1.4/z-credential-offer.ts
|
|
299
|
+
import { z as z3 } from "zod";
|
|
300
|
+
var zAuthorizationCodeGrantV1_4 = z3.object({
|
|
301
|
+
/**
|
|
302
|
+
* CONDITIONALLY REQUIRED. HTTPS URL of the Authorization Server.
|
|
303
|
+
* REQUIRED only when the Credential Issuer uses multiple Authorization Servers.
|
|
304
|
+
* If present, MUST match one of the authorization_servers in the Credential Issuer metadata.
|
|
305
|
+
*/
|
|
306
|
+
authorization_server: z3.url().optional(),
|
|
307
|
+
/**
|
|
308
|
+
* OPTIONAL. String value representing the issuer state.
|
|
309
|
+
* Used to correlate the authorization request with the credential offer.
|
|
310
|
+
*/
|
|
311
|
+
issuer_state: z3.string().optional()
|
|
260
312
|
});
|
|
261
|
-
var
|
|
313
|
+
var zCredentialOfferGrantsV1_4 = z3.object({
|
|
314
|
+
/**
|
|
315
|
+
* REQUIRED. Authorization Code grant details.
|
|
316
|
+
* IT-Wallet v1.4 only supports authorization_code grant.
|
|
317
|
+
*/
|
|
318
|
+
authorization_code: zAuthorizationCodeGrantV1_4
|
|
319
|
+
});
|
|
320
|
+
var zCredentialOfferV1_4 = z3.object({
|
|
321
|
+
/**
|
|
322
|
+
* REQUIRED. Array of credential configuration identifiers.
|
|
323
|
+
* References the types of credentials offered as defined in the Credential Issuer metadata.
|
|
324
|
+
*/
|
|
325
|
+
credential_configuration_ids: z3.array(z3.string()).min(1),
|
|
326
|
+
/**
|
|
327
|
+
* REQUIRED. HTTPS URL of the Credential Issuer.
|
|
328
|
+
* The Credential Issuer from which the wallet will request credentials.
|
|
329
|
+
*/
|
|
330
|
+
credential_issuer: z3.url(),
|
|
331
|
+
/**
|
|
332
|
+
* REQUIRED. Grant information for the credential offer.
|
|
333
|
+
* IT-Wallet v1.4 requires authorization_code grant.
|
|
334
|
+
*/
|
|
335
|
+
grants: zCredentialOfferGrantsV1_4
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// src/credential-offer/z-credential-offer.ts
|
|
339
|
+
var zCredentialOfferUri = z4.object({
|
|
262
340
|
/**
|
|
263
341
|
* OPTIONAL. Inline credential offer JSON (by value).
|
|
264
342
|
* URL-encoded JSON string containing the credential offer.
|
|
265
343
|
*/
|
|
266
|
-
credential_offer:
|
|
344
|
+
credential_offer: z4.string().optional(),
|
|
267
345
|
/**
|
|
268
346
|
* OPTIONAL. URL pointing to the credential offer JSON (by reference).
|
|
269
347
|
* HTTPS URL where the credential offer can be fetched.
|
|
270
348
|
*/
|
|
271
|
-
credential_offer_uri:
|
|
349
|
+
credential_offer_uri: z4.url().optional(),
|
|
272
350
|
/**
|
|
273
351
|
* URL scheme used for the credential offer.
|
|
274
352
|
* Determines the invocation method.
|
|
275
353
|
*/
|
|
276
|
-
scheme:
|
|
354
|
+
scheme: z4.enum(["openid-credential-offer", "haip-vci", "https"])
|
|
277
355
|
}).refine((data) => data.credential_offer || data.credential_offer_uri, {
|
|
278
356
|
message: "Either credential_offer or credential_offer_uri must be present"
|
|
279
357
|
});
|
|
@@ -312,19 +390,35 @@ async function parseCredentialOfferUri(options) {
|
|
|
312
390
|
|
|
313
391
|
// src/credential-offer/resolve-credential-offer.ts
|
|
314
392
|
import {
|
|
393
|
+
ItWalletSpecsVersion as ItWalletSpecsVersion2,
|
|
394
|
+
ItWalletSpecsVersionError as ItWalletSpecsVersionError2,
|
|
315
395
|
UnexpectedStatusCodeError as UnexpectedStatusCodeError2,
|
|
316
396
|
createFetcher as createFetcher2,
|
|
317
397
|
hasStatusOrThrow as hasStatusOrThrow2
|
|
318
398
|
} from "@pagopa/io-wallet-utils";
|
|
399
|
+
function parseCredentialOfferForVersion(config, data) {
|
|
400
|
+
switch (config.itWalletSpecsVersion) {
|
|
401
|
+
case ItWalletSpecsVersion2.V1_3:
|
|
402
|
+
return zCredentialOfferV1_3.parse(data);
|
|
403
|
+
case ItWalletSpecsVersion2.V1_4:
|
|
404
|
+
return zCredentialOfferV1_4.parse(data);
|
|
405
|
+
default:
|
|
406
|
+
throw new ItWalletSpecsVersionError2(
|
|
407
|
+
"resolveCredentialOffer",
|
|
408
|
+
config.itWalletSpecsVersion,
|
|
409
|
+
[ItWalletSpecsVersion2.V1_3, ItWalletSpecsVersion2.V1_4]
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
319
413
|
async function resolveCredentialOffer(options) {
|
|
320
|
-
const { callbacks, credentialOffer } = options;
|
|
414
|
+
const { callbacks, config, credentialOffer } = options;
|
|
321
415
|
try {
|
|
322
416
|
if (credentialOffer.startsWith("openid-credential-offer://") || credentialOffer.startsWith("haip-vci://") || credentialOffer.startsWith("https://")) {
|
|
323
417
|
const parsed = await parseCredentialOfferUri({ uri: credentialOffer });
|
|
324
418
|
if (parsed.credential_offer) {
|
|
325
419
|
const decoded = decodeURIComponent(parsed.credential_offer);
|
|
326
420
|
const offerJson2 = JSON.parse(decoded);
|
|
327
|
-
return
|
|
421
|
+
return parseCredentialOfferForVersion(config, offerJson2);
|
|
328
422
|
}
|
|
329
423
|
if (parsed.credential_offer_uri) {
|
|
330
424
|
const fetch = createFetcher2(callbacks.fetch);
|
|
@@ -336,13 +430,13 @@ async function resolveCredentialOffer(options) {
|
|
|
336
430
|
});
|
|
337
431
|
await hasStatusOrThrow2(200, UnexpectedStatusCodeError2)(response);
|
|
338
432
|
const offerJson2 = await response.json();
|
|
339
|
-
return
|
|
433
|
+
return parseCredentialOfferForVersion(config, offerJson2);
|
|
340
434
|
}
|
|
341
435
|
}
|
|
342
436
|
const offerJson = JSON.parse(credentialOffer);
|
|
343
|
-
return
|
|
437
|
+
return parseCredentialOfferForVersion(config, offerJson);
|
|
344
438
|
} catch (error) {
|
|
345
|
-
if (error instanceof CredentialOfferError || error instanceof UnexpectedStatusCodeError2) {
|
|
439
|
+
if (error instanceof CredentialOfferError || error instanceof UnexpectedStatusCodeError2 || error instanceof ItWalletSpecsVersionError2) {
|
|
346
440
|
throw error;
|
|
347
441
|
}
|
|
348
442
|
throw new CredentialOfferError(
|
|
@@ -352,8 +446,38 @@ async function resolveCredentialOffer(options) {
|
|
|
352
446
|
}
|
|
353
447
|
|
|
354
448
|
// src/credential-offer/validate-credential-offer.ts
|
|
355
|
-
|
|
356
|
-
|
|
449
|
+
import {
|
|
450
|
+
ItWalletSpecsVersion as ItWalletSpecsVersion3,
|
|
451
|
+
ItWalletSpecsVersionError as ItWalletSpecsVersionError3,
|
|
452
|
+
createVersionDispatcher as createVersionDispatcher2
|
|
453
|
+
} from "@pagopa/io-wallet-utils";
|
|
454
|
+
function assertAuthorizationServerAllowed(authorizationServer, authorizationServers) {
|
|
455
|
+
if (!authorizationServer) {
|
|
456
|
+
if (authorizationServers && authorizationServers.length > 1) {
|
|
457
|
+
throw new CredentialOfferError(
|
|
458
|
+
"authorization_server is REQUIRED when Credential Issuer uses multiple Authorization Servers"
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (!authorizationServers) {
|
|
464
|
+
throw new CredentialOfferError(
|
|
465
|
+
"credential offer specified an `authorization_server` but issuer metadata doesn't contain `authorization_servers`"
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
if (authorizationServers.length === 1) {
|
|
469
|
+
throw new CredentialOfferError(
|
|
470
|
+
"credential offer specified an `authorization_server` but issuer metadata's `authorization_servers` contains only an element"
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
if (!authorizationServers.includes(authorizationServer)) {
|
|
474
|
+
throw new CredentialOfferError(
|
|
475
|
+
`authorization_server '${authorizationServer}' does not match Credential Issuer metadata. Valid servers: ${authorizationServers.join(", ")}`
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function validateBaseCredentialOffer(options) {
|
|
480
|
+
const { credentialIssuerMetadata, credentialOffer, versionLabel } = options;
|
|
357
481
|
if (!credentialOffer.credential_issuer.startsWith("https://")) {
|
|
358
482
|
throw new CredentialOfferError("credential_issuer must be an HTTPS URL");
|
|
359
483
|
}
|
|
@@ -363,38 +487,57 @@ async function validateCredentialOffer(options) {
|
|
|
363
487
|
);
|
|
364
488
|
}
|
|
365
489
|
if (!credentialOffer.grants) {
|
|
366
|
-
throw new CredentialOfferError(
|
|
490
|
+
throw new CredentialOfferError(
|
|
491
|
+
`grants is REQUIRED for IT-Wallet ${versionLabel}`
|
|
492
|
+
);
|
|
367
493
|
}
|
|
368
494
|
const authCodeGrant = credentialOffer.grants.authorization_code;
|
|
369
495
|
if (!authCodeGrant) {
|
|
370
496
|
throw new CredentialOfferError(
|
|
371
|
-
|
|
497
|
+
`authorization_code grant is REQUIRED for IT-Wallet ${versionLabel}`
|
|
372
498
|
);
|
|
373
499
|
}
|
|
374
|
-
|
|
500
|
+
assertAuthorizationServerAllowed(
|
|
501
|
+
authCodeGrant.authorization_server,
|
|
502
|
+
credentialIssuerMetadata?.authorization_servers
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
async function validateCredentialOfferV1_3(options) {
|
|
506
|
+
validateBaseCredentialOffer({
|
|
507
|
+
credentialIssuerMetadata: options.credentialIssuerMetadata,
|
|
508
|
+
credentialOffer: options.credentialOffer,
|
|
509
|
+
versionLabel: "v1.3"
|
|
510
|
+
});
|
|
511
|
+
if (!options.credentialOffer.grants.authorization_code.scope) {
|
|
375
512
|
throw new CredentialOfferError("authorization_code.scope is REQUIRED");
|
|
376
513
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
514
|
+
}
|
|
515
|
+
async function validateCredentialOfferV1_4(options) {
|
|
516
|
+
validateBaseCredentialOffer({
|
|
517
|
+
credentialIssuerMetadata: options.credentialIssuerMetadata,
|
|
518
|
+
credentialOffer: options.credentialOffer,
|
|
519
|
+
versionLabel: "v1.4"
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
var dispatchValidateCredentialOffer = createVersionDispatcher2({
|
|
523
|
+
[ItWalletSpecsVersion3.V1_0]: () => {
|
|
524
|
+
throw new ItWalletSpecsVersionError3(
|
|
525
|
+
"validateCredentialOffer",
|
|
526
|
+
ItWalletSpecsVersion3.V1_0,
|
|
527
|
+
[ItWalletSpecsVersion3.V1_3, ItWalletSpecsVersion3.V1_4]
|
|
528
|
+
);
|
|
529
|
+
},
|
|
530
|
+
[ItWalletSpecsVersion3.V1_3]: (o) => validateCredentialOfferV1_3(o),
|
|
531
|
+
[ItWalletSpecsVersion3.V1_4]: (o) => validateCredentialOfferV1_4(o)
|
|
532
|
+
});
|
|
533
|
+
async function validateCredentialOffer(options) {
|
|
534
|
+
return dispatchValidateCredentialOffer(options);
|
|
392
535
|
}
|
|
393
536
|
|
|
394
537
|
// src/credential-request/create-credential-request.ts
|
|
395
538
|
import {
|
|
396
|
-
ItWalletSpecsVersion as
|
|
397
|
-
createVersionDispatcher
|
|
539
|
+
ItWalletSpecsVersion as ItWalletSpecsVersion6,
|
|
540
|
+
createVersionDispatcher as createVersionDispatcher3
|
|
398
541
|
} from "@pagopa/io-wallet-utils";
|
|
399
542
|
|
|
400
543
|
// src/credential-request/v1.0/create-credential-request.ts
|
|
@@ -405,18 +548,18 @@ import {
|
|
|
405
548
|
} from "@pagopa/io-wallet-utils";
|
|
406
549
|
|
|
407
550
|
// src/credential-request/v1.0/z-credential.ts
|
|
408
|
-
import { z as
|
|
551
|
+
import { z as z6 } from "zod";
|
|
409
552
|
|
|
410
553
|
// src/credential-request/z-base-credential-request.ts
|
|
411
|
-
import { z as
|
|
412
|
-
var zBaseCredentialRequest =
|
|
413
|
-
credential_configuration_id:
|
|
554
|
+
import { z as z5 } from "zod";
|
|
555
|
+
var zBaseCredentialRequest = z5.object({
|
|
556
|
+
credential_configuration_id: z5.string().optional().describe(
|
|
414
557
|
"REQUIRED if credential_identifier param is absent. MUST NOT be used otherwise."
|
|
415
558
|
),
|
|
416
|
-
credential_identifier:
|
|
559
|
+
credential_identifier: z5.string().optional().describe(
|
|
417
560
|
"REQUIRED when Authorization Details of type openid_credential was returned. MUST NOT be used if credential_configuration_id is present."
|
|
418
561
|
),
|
|
419
|
-
transaction_id:
|
|
562
|
+
transaction_id: z5.string().optional().describe(
|
|
420
563
|
"REQUIRED only in case of deferred flow. MUST NOT be present in immediate flow."
|
|
421
564
|
)
|
|
422
565
|
});
|
|
@@ -438,9 +581,9 @@ function credentialRequestRefiner(data, ctx) {
|
|
|
438
581
|
}
|
|
439
582
|
|
|
440
583
|
// src/credential-request/v1.0/z-credential.ts
|
|
441
|
-
var zCredentialRequestProof =
|
|
442
|
-
jwt:
|
|
443
|
-
proof_type:
|
|
584
|
+
var zCredentialRequestProof = z6.object({
|
|
585
|
+
jwt: z6.string().min(1, "JWT must not be empty"),
|
|
586
|
+
proof_type: z6.literal("jwt")
|
|
444
587
|
// MUST be "jwt"
|
|
445
588
|
});
|
|
446
589
|
var zCredentialRequestV1_0 = zBaseCredentialRequest.extend({
|
|
@@ -497,10 +640,10 @@ import {
|
|
|
497
640
|
} from "@pagopa/io-wallet-utils";
|
|
498
641
|
|
|
499
642
|
// src/credential-request/v1.3/z-credential.ts
|
|
500
|
-
import { z as
|
|
501
|
-
var zCredentialRequestProofJwt =
|
|
502
|
-
var zCredentialRequestProofs =
|
|
503
|
-
jwt:
|
|
643
|
+
import { z as z7 } from "zod";
|
|
644
|
+
var zCredentialRequestProofJwt = z7.string().min(1, "JWT must not be empty in credential request proofs array");
|
|
645
|
+
var zCredentialRequestProofs = z7.object({
|
|
646
|
+
jwt: z7.tuple([zCredentialRequestProofJwt], zCredentialRequestProofJwt)
|
|
504
647
|
});
|
|
505
648
|
var zCredentialRequestV1_3 = zBaseCredentialRequest.extend({
|
|
506
649
|
proofs: zCredentialRequestProofs.describe(
|
|
@@ -583,10 +726,10 @@ var createCredentialRequest2 = async (options) => {
|
|
|
583
726
|
};
|
|
584
727
|
|
|
585
728
|
// src/credential-request/create-credential-request.ts
|
|
586
|
-
var dispatchCreateCredentialRequest =
|
|
587
|
-
[
|
|
588
|
-
[
|
|
589
|
-
[
|
|
729
|
+
var dispatchCreateCredentialRequest = createVersionDispatcher3({
|
|
730
|
+
[ItWalletSpecsVersion6.V1_0]: (o) => createCredentialRequest(o),
|
|
731
|
+
[ItWalletSpecsVersion6.V1_3]: (o) => createCredentialRequest2(o),
|
|
732
|
+
[ItWalletSpecsVersion6.V1_4]: (o) => (
|
|
590
733
|
// V1_4 reuses V1_3 credential request schema — no breaking changes between versions.
|
|
591
734
|
// Verified against compare/1.3.3...1.4.1: credential request parameters (format, proofs, key_attestation) identical.
|
|
592
735
|
createCredentialRequest2(o)
|
|
@@ -604,30 +747,32 @@ import {
|
|
|
604
747
|
} from "@pagopa/io-wallet-oauth2";
|
|
605
748
|
import {
|
|
606
749
|
HEADERS,
|
|
607
|
-
|
|
608
|
-
|
|
750
|
+
HashAlgorithm as HashAlgorithm2,
|
|
751
|
+
ItWalletSpecsVersion as ItWalletSpecsVersion7,
|
|
752
|
+
ItWalletSpecsVersionError as ItWalletSpecsVersionError4,
|
|
609
753
|
ValidationError as ValidationError4,
|
|
610
|
-
|
|
754
|
+
calculateJwkThumbprint as calculateJwkThumbprint2,
|
|
755
|
+
createVersionDispatcher as createVersionDispatcher4,
|
|
611
756
|
parseWithErrorHandling as parseWithErrorHandling3
|
|
612
757
|
} from "@pagopa/io-wallet-utils";
|
|
613
758
|
|
|
614
759
|
// src/credential-request/z-proof-jwt.ts
|
|
615
760
|
import { zJwk } from "@pagopa/io-wallet-oauth2";
|
|
616
|
-
import { z as
|
|
617
|
-
var zBaseProofJwtHeader =
|
|
618
|
-
alg:
|
|
761
|
+
import { z as z8 } from "zod";
|
|
762
|
+
var zBaseProofJwtHeader = z8.object({
|
|
763
|
+
alg: z8.string().min(1),
|
|
619
764
|
jwk: zJwk,
|
|
620
|
-
typ:
|
|
765
|
+
typ: z8.literal("openid4vci-proof+jwt")
|
|
621
766
|
});
|
|
622
767
|
var zProofJwtHeaderV1_0 = zBaseProofJwtHeader.loose();
|
|
623
768
|
var zProofJwtHeaderV1_3 = zBaseProofJwtHeader.extend({
|
|
624
|
-
key_attestation:
|
|
769
|
+
key_attestation: z8.string().min(1)
|
|
625
770
|
}).loose();
|
|
626
|
-
var zProofJwtPayload =
|
|
627
|
-
aud:
|
|
628
|
-
iat:
|
|
629
|
-
iss:
|
|
630
|
-
nonce:
|
|
771
|
+
var zProofJwtPayload = z8.looseObject({
|
|
772
|
+
aud: z8.string().min(1),
|
|
773
|
+
iat: z8.number(),
|
|
774
|
+
iss: z8.string().min(1).optional(),
|
|
775
|
+
nonce: z8.string().min(1)
|
|
631
776
|
});
|
|
632
777
|
|
|
633
778
|
// src/credential-request/parse-credential-request.ts
|
|
@@ -692,7 +837,7 @@ function parseProofJwt(options) {
|
|
|
692
837
|
errorMessagePrefix: "Error decoding credential request proof JWT:",
|
|
693
838
|
jwt: options.jwt
|
|
694
839
|
});
|
|
695
|
-
const headerValidation = options.itWalletSpecsVersion ===
|
|
840
|
+
const headerValidation = options.itWalletSpecsVersion === ItWalletSpecsVersion7.V1_3 || options.itWalletSpecsVersion === ItWalletSpecsVersion7.V1_4 ? zProofJwtHeaderV1_3.safeParse(decoded.header) : zProofJwtHeaderV1_0.safeParse(decoded.header);
|
|
696
841
|
if (!headerValidation.success) {
|
|
697
842
|
throw new ValidationError4(
|
|
698
843
|
"Credential proof JWT header is invalid or missing required claims"
|
|
@@ -717,7 +862,27 @@ function parseProofJwt(options) {
|
|
|
717
862
|
proofType: "jwt"
|
|
718
863
|
};
|
|
719
864
|
}
|
|
720
|
-
function
|
|
865
|
+
async function validateProofJwkUniqueness(options) {
|
|
866
|
+
if (options.proofs.length <= 1) {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
const thumbprints = await Promise.all(
|
|
870
|
+
options.proofs.map(
|
|
871
|
+
(proof) => calculateJwkThumbprint2({
|
|
872
|
+
hashAlgorithm: HashAlgorithm2.Sha256,
|
|
873
|
+
hashCallback: options.callbacks.hash,
|
|
874
|
+
jwk: proof.header.jwk
|
|
875
|
+
})
|
|
876
|
+
)
|
|
877
|
+
);
|
|
878
|
+
const uniqueThumbprints = new Set(thumbprints);
|
|
879
|
+
if (uniqueThumbprints.size !== thumbprints.length) {
|
|
880
|
+
throw new ValidationError4(
|
|
881
|
+
"Credential request proofs must use unique jwk header values"
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
async function normalizeProofs(options) {
|
|
721
886
|
if ("proof" in options.credentialRequest) {
|
|
722
887
|
return [
|
|
723
888
|
parseProofJwt({
|
|
@@ -728,7 +893,7 @@ function normalizeProofs(options) {
|
|
|
728
893
|
})
|
|
729
894
|
];
|
|
730
895
|
}
|
|
731
|
-
|
|
896
|
+
const proofs = options.credentialRequest.proofs.jwt.map(
|
|
732
897
|
(jwt) => parseProofJwt({
|
|
733
898
|
expected: options.expected,
|
|
734
899
|
grantType: options.grantType,
|
|
@@ -736,14 +901,20 @@ function normalizeProofs(options) {
|
|
|
736
901
|
jwt
|
|
737
902
|
})
|
|
738
903
|
);
|
|
904
|
+
await validateProofJwkUniqueness({
|
|
905
|
+
callbacks: options.callbacks,
|
|
906
|
+
proofs
|
|
907
|
+
});
|
|
908
|
+
return proofs;
|
|
739
909
|
}
|
|
740
|
-
function toResult(options) {
|
|
910
|
+
async function toResult(options) {
|
|
741
911
|
validateExpectedValues(options.credentialRequest, options.expected);
|
|
742
912
|
validateTransactionContext({
|
|
743
913
|
credentialRequest: options.credentialRequest,
|
|
744
914
|
isDeferredFlow: options.isDeferredFlow
|
|
745
915
|
});
|
|
746
|
-
const proofs = normalizeProofs({
|
|
916
|
+
const proofs = await normalizeProofs({
|
|
917
|
+
callbacks: options.callbacks,
|
|
747
918
|
credentialRequest: options.credentialRequest,
|
|
748
919
|
expected: options.expected,
|
|
749
920
|
grantType: options.grantType,
|
|
@@ -802,12 +973,13 @@ function parseCredentialRequestV1_0(options) {
|
|
|
802
973
|
);
|
|
803
974
|
return toResult({
|
|
804
975
|
accessToken: options.accessToken,
|
|
976
|
+
callbacks: options.callbacks,
|
|
805
977
|
credentialRequest,
|
|
806
978
|
dpopProof: options.dpopProof,
|
|
807
979
|
expected: options.expected,
|
|
808
980
|
grantType: options.grantType,
|
|
809
981
|
isDeferredFlow: options.isDeferredFlow,
|
|
810
|
-
itWalletSpecsVersion:
|
|
982
|
+
itWalletSpecsVersion: ItWalletSpecsVersion7.V1_0
|
|
811
983
|
});
|
|
812
984
|
}
|
|
813
985
|
function parseCredentialRequestV1_3(options) {
|
|
@@ -818,12 +990,13 @@ function parseCredentialRequestV1_3(options) {
|
|
|
818
990
|
);
|
|
819
991
|
return toResult({
|
|
820
992
|
accessToken: options.accessToken,
|
|
993
|
+
callbacks: options.callbacks,
|
|
821
994
|
credentialRequest,
|
|
822
995
|
dpopProof: options.dpopProof,
|
|
823
996
|
expected: options.expected,
|
|
824
997
|
grantType: options.grantType,
|
|
825
998
|
isDeferredFlow: options.isDeferredFlow,
|
|
826
|
-
itWalletSpecsVersion:
|
|
999
|
+
itWalletSpecsVersion: ItWalletSpecsVersion7.V1_3
|
|
827
1000
|
});
|
|
828
1001
|
}
|
|
829
1002
|
function parseCredentialRequestV1_4(options) {
|
|
@@ -834,27 +1007,28 @@ function parseCredentialRequestV1_4(options) {
|
|
|
834
1007
|
);
|
|
835
1008
|
return toResult({
|
|
836
1009
|
accessToken: options.accessToken,
|
|
1010
|
+
callbacks: options.callbacks,
|
|
837
1011
|
credentialRequest,
|
|
838
1012
|
dpopProof: options.dpopProof,
|
|
839
1013
|
expected: options.expected,
|
|
840
1014
|
grantType: options.grantType,
|
|
841
1015
|
isDeferredFlow: options.isDeferredFlow,
|
|
842
|
-
itWalletSpecsVersion:
|
|
1016
|
+
itWalletSpecsVersion: ItWalletSpecsVersion7.V1_4
|
|
843
1017
|
// V1_4 reuses V1_3 proof schema
|
|
844
1018
|
});
|
|
845
1019
|
}
|
|
846
|
-
var dispatchParseCredentialRequest =
|
|
847
|
-
[
|
|
848
|
-
[
|
|
849
|
-
[
|
|
1020
|
+
var dispatchParseCredentialRequest = createVersionDispatcher4({
|
|
1021
|
+
[ItWalletSpecsVersion7.V1_0]: parseCredentialRequestV1_0,
|
|
1022
|
+
[ItWalletSpecsVersion7.V1_3]: parseCredentialRequestV1_3,
|
|
1023
|
+
[ItWalletSpecsVersion7.V1_4]: parseCredentialRequestV1_4
|
|
850
1024
|
});
|
|
851
|
-
function parseCredentialRequest(options) {
|
|
1025
|
+
async function parseCredentialRequest(options) {
|
|
852
1026
|
const grantType = options.grantType ?? "authorization_code";
|
|
853
1027
|
const isDeferredFlow = options.isDeferredFlow ?? false;
|
|
854
1028
|
try {
|
|
855
1029
|
const accessToken = parseAuthorizationHeader(options.headers);
|
|
856
1030
|
const dpopProof = parseDpopProof(options.headers);
|
|
857
|
-
return dispatchParseCredentialRequest({
|
|
1031
|
+
return await dispatchParseCredentialRequest({
|
|
858
1032
|
...options,
|
|
859
1033
|
accessToken,
|
|
860
1034
|
dpopProof,
|
|
@@ -862,7 +1036,7 @@ function parseCredentialRequest(options) {
|
|
|
862
1036
|
isDeferredFlow
|
|
863
1037
|
});
|
|
864
1038
|
} catch (error) {
|
|
865
|
-
if (error instanceof
|
|
1039
|
+
if (error instanceof ItWalletSpecsVersionError4 || error instanceof Oauth2JwtParseError || error instanceof ValidationError4 || error instanceof CredentialAuthorizationHeaderError || error instanceof MissingDpopProofError) {
|
|
866
1040
|
throw error;
|
|
867
1041
|
}
|
|
868
1042
|
throw new ParseCredentialRequestError(
|
|
@@ -873,18 +1047,18 @@ function parseCredentialRequest(options) {
|
|
|
873
1047
|
}
|
|
874
1048
|
|
|
875
1049
|
// src/credential-request/verify-credential-request-jwt-proof.ts
|
|
876
|
-
import { calculateJwkThumbprint as
|
|
1050
|
+
import { calculateJwkThumbprint as calculateJwkThumbprint3, jwtSignerFromJwt as jwtSignerFromJwt3 } from "@openid4vc/oauth2";
|
|
877
1051
|
import {
|
|
878
|
-
HashAlgorithm as
|
|
1052
|
+
HashAlgorithm as HashAlgorithm3,
|
|
879
1053
|
Oauth2JwtParseError as Oauth2JwtParseError3,
|
|
880
1054
|
decodeJwt as decodeJwt3,
|
|
881
1055
|
verifyJwt as verifyJwt3
|
|
882
1056
|
} from "@pagopa/io-wallet-oauth2";
|
|
883
1057
|
import {
|
|
884
|
-
ItWalletSpecsVersion as
|
|
885
|
-
ItWalletSpecsVersionError as
|
|
1058
|
+
ItWalletSpecsVersion as ItWalletSpecsVersion8,
|
|
1059
|
+
ItWalletSpecsVersionError as ItWalletSpecsVersionError5,
|
|
886
1060
|
ValidationError as ValidationError6,
|
|
887
|
-
createVersionDispatcher as
|
|
1061
|
+
createVersionDispatcher as createVersionDispatcher5,
|
|
888
1062
|
verifyJwtIatOrThrow
|
|
889
1063
|
} from "@pagopa/io-wallet-utils";
|
|
890
1064
|
|
|
@@ -901,33 +1075,33 @@ import { ValidationError as ValidationError5 } from "@pagopa/io-wallet-utils";
|
|
|
901
1075
|
import { zCertificateChain, zJwk as zJwk2, zTrustChain } from "@pagopa/io-wallet-oauth2";
|
|
902
1076
|
import { zKeyStorageLevelV1_3 } from "@pagopa/io-wallet-oid-federation";
|
|
903
1077
|
import { zItwSupportedSignatureAlg } from "@pagopa/io-wallet-utils";
|
|
904
|
-
import { z as
|
|
905
|
-
var zStatusList =
|
|
906
|
-
idx:
|
|
907
|
-
uri:
|
|
1078
|
+
import { z as z9 } from "zod";
|
|
1079
|
+
var zStatusList = z9.object({
|
|
1080
|
+
idx: z9.number(),
|
|
1081
|
+
uri: z9.url()
|
|
908
1082
|
});
|
|
909
|
-
var zKeyAttestationStatus =
|
|
1083
|
+
var zKeyAttestationStatus = z9.object({
|
|
910
1084
|
status_list: zStatusList
|
|
911
1085
|
});
|
|
912
1086
|
var zKeyAttestationAlg = zItwSupportedSignatureAlg;
|
|
913
|
-
var zKeyAttestationHeader =
|
|
1087
|
+
var zKeyAttestationHeader = z9.object({
|
|
914
1088
|
alg: zKeyAttestationAlg,
|
|
915
|
-
kid:
|
|
1089
|
+
kid: z9.string(),
|
|
916
1090
|
trust_chain: zTrustChain.optional(),
|
|
917
|
-
typ:
|
|
1091
|
+
typ: z9.literal("key-attestation+jwt"),
|
|
918
1092
|
x5c: zCertificateChain
|
|
919
1093
|
});
|
|
920
|
-
var zKeyAttestationPayload =
|
|
921
|
-
attested_keys:
|
|
922
|
-
certification:
|
|
923
|
-
exp:
|
|
924
|
-
iat:
|
|
925
|
-
iss:
|
|
926
|
-
key_storage:
|
|
1094
|
+
var zKeyAttestationPayload = z9.object({
|
|
1095
|
+
attested_keys: z9.array(zJwk2).nonempty(),
|
|
1096
|
+
certification: z9.string().optional(),
|
|
1097
|
+
exp: z9.number(),
|
|
1098
|
+
iat: z9.number(),
|
|
1099
|
+
iss: z9.string(),
|
|
1100
|
+
key_storage: z9.array(zKeyStorageLevelV1_3).nonempty(),
|
|
927
1101
|
status: zKeyAttestationStatus,
|
|
928
|
-
user_authentication:
|
|
1102
|
+
user_authentication: z9.array(zKeyStorageLevelV1_3).nonempty()
|
|
929
1103
|
});
|
|
930
|
-
var zKeyAttestationTypeHeader =
|
|
1104
|
+
var zKeyAttestationTypeHeader = z9.literal("key-attestation+jwt");
|
|
931
1105
|
var keyAttestationTypeHeader = zKeyAttestationTypeHeader.value;
|
|
932
1106
|
|
|
933
1107
|
// src/credential-request/verify-key-attestation-jwt.ts
|
|
@@ -974,15 +1148,15 @@ async function verifyKeyAttestationJwt(options) {
|
|
|
974
1148
|
|
|
975
1149
|
// src/credential-request/verify-credential-request-jwt-proof.ts
|
|
976
1150
|
async function isJwkInSet(options) {
|
|
977
|
-
const targetThumbprint = await
|
|
978
|
-
hashAlgorithm:
|
|
1151
|
+
const targetThumbprint = await calculateJwkThumbprint3({
|
|
1152
|
+
hashAlgorithm: HashAlgorithm3.Sha256,
|
|
979
1153
|
hashCallback: options.callbacks.hash,
|
|
980
1154
|
jwk: options.jwk
|
|
981
1155
|
});
|
|
982
1156
|
const thumbprints = await Promise.all(
|
|
983
1157
|
options.jwks.map(
|
|
984
|
-
(jwk) =>
|
|
985
|
-
hashAlgorithm:
|
|
1158
|
+
(jwk) => calculateJwkThumbprint3({
|
|
1159
|
+
hashAlgorithm: HashAlgorithm3.Sha256,
|
|
986
1160
|
hashCallback: options.callbacks.hash,
|
|
987
1161
|
jwk
|
|
988
1162
|
})
|
|
@@ -1077,10 +1251,10 @@ async function verifyProofV1_3(options) {
|
|
|
1077
1251
|
}
|
|
1078
1252
|
return { header, keyAttestation: keyAttestationResult, payload, signer };
|
|
1079
1253
|
}
|
|
1080
|
-
var dispatchVerifyProof =
|
|
1081
|
-
[
|
|
1082
|
-
[
|
|
1083
|
-
[
|
|
1254
|
+
var dispatchVerifyProof = createVersionDispatcher5({
|
|
1255
|
+
[ItWalletSpecsVersion8.V1_0]: (o) => verifyProofV1_0(o),
|
|
1256
|
+
[ItWalletSpecsVersion8.V1_3]: (o) => verifyProofV1_3(o),
|
|
1257
|
+
[ItWalletSpecsVersion8.V1_4]: (o) => verifyProofV1_3(o)
|
|
1084
1258
|
});
|
|
1085
1259
|
async function verifyCredentialRequestJwtProof(options) {
|
|
1086
1260
|
try {
|
|
@@ -1092,7 +1266,7 @@ async function verifyCredentialRequestJwtProof(options) {
|
|
|
1092
1266
|
}
|
|
1093
1267
|
return await dispatchVerifyProof({ ...options, now });
|
|
1094
1268
|
} catch (error) {
|
|
1095
|
-
if (error instanceof VerifyCredentialRequestJwtProofError || error instanceof VerifyKeyAttestationJwtError || error instanceof
|
|
1269
|
+
if (error instanceof VerifyCredentialRequestJwtProofError || error instanceof VerifyKeyAttestationJwtError || error instanceof ItWalletSpecsVersionError5 || error instanceof ValidationError6 || error instanceof Oauth2JwtParseError3) {
|
|
1096
1270
|
throw error;
|
|
1097
1271
|
}
|
|
1098
1272
|
throw new VerifyCredentialRequestJwtProofError(
|
|
@@ -1104,39 +1278,39 @@ async function verifyCredentialRequestJwtProof(options) {
|
|
|
1104
1278
|
|
|
1105
1279
|
// src/credential-response/create-credential-response.ts
|
|
1106
1280
|
import {
|
|
1107
|
-
ItWalletSpecsVersion as
|
|
1281
|
+
ItWalletSpecsVersion as ItWalletSpecsVersion9,
|
|
1108
1282
|
ValidationError as ValidationError7,
|
|
1109
|
-
createVersionDispatcher as
|
|
1283
|
+
createVersionDispatcher as createVersionDispatcher6
|
|
1110
1284
|
} from "@pagopa/io-wallet-utils";
|
|
1111
1285
|
|
|
1112
1286
|
// src/credential-response/v1.0/create-credential-response.ts
|
|
1113
1287
|
import { parseWithErrorHandling as parseWithErrorHandling4 } from "@pagopa/io-wallet-utils";
|
|
1114
1288
|
|
|
1115
1289
|
// src/credential-response/v1.0/z-credential-response.ts
|
|
1116
|
-
import { z as
|
|
1290
|
+
import { z as z11 } from "zod";
|
|
1117
1291
|
|
|
1118
1292
|
// src/credential-response/z-immediate-credential-response.ts
|
|
1119
|
-
import { z as
|
|
1120
|
-
var zCredentialObject =
|
|
1121
|
-
credential:
|
|
1293
|
+
import { z as z10 } from "zod";
|
|
1294
|
+
var zCredentialObject = z10.object({
|
|
1295
|
+
credential: z10.string()
|
|
1122
1296
|
});
|
|
1123
|
-
var zImmediateCredentialResponse =
|
|
1124
|
-
credentials:
|
|
1297
|
+
var zImmediateCredentialResponse = z10.strictObject({
|
|
1298
|
+
credentials: z10.array(zCredentialObject).nonempty().describe(
|
|
1125
1299
|
"Conditional. Array of issued Digital Credentials as JSON objects with `credential` member containing encoded credential string. Present for immediate issuance (HTTP 200)."
|
|
1126
1300
|
),
|
|
1127
|
-
notification_id:
|
|
1301
|
+
notification_id: z10.string().optional().describe(
|
|
1128
1302
|
"OPTIONAL. Identifier for notification requests. Only present with credentials parameter."
|
|
1129
1303
|
)
|
|
1130
1304
|
});
|
|
1131
1305
|
|
|
1132
1306
|
// src/credential-response/v1.0/z-credential-response.ts
|
|
1133
|
-
var zDeferredCredentialResponseV1_0 =
|
|
1134
|
-
lead_time:
|
|
1307
|
+
var zDeferredCredentialResponseV1_0 = z11.strictObject({
|
|
1308
|
+
lead_time: z11.number().int().positive().describe(
|
|
1135
1309
|
"REQUIRED if credentials is not present, otherwise it MUST NOT be present. The amount of time (in seconds) required before making a Deferred Credential Request."
|
|
1136
1310
|
),
|
|
1137
|
-
transaction_id:
|
|
1311
|
+
transaction_id: z11.string().nonempty()
|
|
1138
1312
|
});
|
|
1139
|
-
var zCredentialResponseV1_0 =
|
|
1313
|
+
var zCredentialResponseV1_0 = z11.union([
|
|
1140
1314
|
zImmediateCredentialResponse,
|
|
1141
1315
|
zDeferredCredentialResponseV1_0
|
|
1142
1316
|
]);
|
|
@@ -1169,14 +1343,14 @@ function createCredentialResponseV1_0(flow) {
|
|
|
1169
1343
|
import { parseWithErrorHandling as parseWithErrorHandling5 } from "@pagopa/io-wallet-utils";
|
|
1170
1344
|
|
|
1171
1345
|
// src/credential-response/v1.3/z-credential-response.ts
|
|
1172
|
-
import { z as
|
|
1173
|
-
var zDeferredCredentialResponseV1_3 =
|
|
1174
|
-
interval:
|
|
1346
|
+
import { z as z12 } from "zod";
|
|
1347
|
+
var zDeferredCredentialResponseV1_3 = z12.strictObject({
|
|
1348
|
+
interval: z12.number().int().positive().describe(
|
|
1175
1349
|
"REQUIRED if transaction_id is present, otherwise it MUST NOT be present. The amount of time (in seconds) required before making a Deferred Credential Request"
|
|
1176
1350
|
),
|
|
1177
|
-
transaction_id:
|
|
1351
|
+
transaction_id: z12.string().nonempty()
|
|
1178
1352
|
});
|
|
1179
|
-
var zCredentialResponseV1_3 =
|
|
1353
|
+
var zCredentialResponseV1_3 = z12.union([
|
|
1180
1354
|
zImmediateCredentialResponse,
|
|
1181
1355
|
zDeferredCredentialResponseV1_3
|
|
1182
1356
|
]);
|
|
@@ -1206,14 +1380,14 @@ function createCredentialResponseV1_3(flow) {
|
|
|
1206
1380
|
}
|
|
1207
1381
|
|
|
1208
1382
|
// src/credential-response/create-credential-response.ts
|
|
1209
|
-
var dispatchBuildVersionedResponse =
|
|
1210
|
-
[
|
|
1383
|
+
var dispatchBuildVersionedResponse = createVersionDispatcher6({
|
|
1384
|
+
[ItWalletSpecsVersion9.V1_0]: (o) => createCredentialResponseV1_0(
|
|
1211
1385
|
o.flow
|
|
1212
1386
|
),
|
|
1213
|
-
[
|
|
1387
|
+
[ItWalletSpecsVersion9.V1_3]: (o) => createCredentialResponseV1_3(
|
|
1214
1388
|
o.flow
|
|
1215
1389
|
),
|
|
1216
|
-
[
|
|
1390
|
+
[ItWalletSpecsVersion9.V1_4]: (o) => createCredentialResponseV1_3(
|
|
1217
1391
|
o.flow
|
|
1218
1392
|
// V1_4 reuses V1_3 credential response schema — no breaking changes between versions.
|
|
1219
1393
|
// Verified against compare/1.3.3...1.4.1: credential response parameters identical.
|
|
@@ -1274,10 +1448,10 @@ import {
|
|
|
1274
1448
|
|
|
1275
1449
|
// src/credential-response/z-credential-response.ts
|
|
1276
1450
|
import { zAlgValueNotNone, zJwk as zJwk3 } from "@pagopa/io-wallet-oauth2";
|
|
1277
|
-
import { z as
|
|
1278
|
-
var zCredentialResponseEncryption =
|
|
1451
|
+
import { z as z13 } from "zod";
|
|
1452
|
+
var zCredentialResponseEncryption = z13.looseObject({
|
|
1279
1453
|
alg: zAlgValueNotNone,
|
|
1280
|
-
enc:
|
|
1454
|
+
enc: z13.string(),
|
|
1281
1455
|
jwk: zJwk3
|
|
1282
1456
|
});
|
|
1283
1457
|
|
|
@@ -1325,16 +1499,16 @@ async function fetchCredentialResponse(options) {
|
|
|
1325
1499
|
import { decodeJwt as decodeJwt4 } from "@pagopa/io-wallet-oauth2";
|
|
1326
1500
|
import { itWalletEntityStatementClaimsSchema as itWalletEntityStatementClaimsSchema2 } from "@pagopa/io-wallet-oid-federation";
|
|
1327
1501
|
import {
|
|
1328
|
-
ItWalletSpecsVersion as
|
|
1329
|
-
ItWalletSpecsVersionError as
|
|
1502
|
+
ItWalletSpecsVersion as ItWalletSpecsVersion10,
|
|
1503
|
+
ItWalletSpecsVersionError as ItWalletSpecsVersionError6,
|
|
1330
1504
|
UnexpectedStatusCodeError as UnexpectedStatusCodeError4,
|
|
1331
1505
|
ValidationError as ValidationError9,
|
|
1332
1506
|
createFetcher as createFetcher4,
|
|
1333
|
-
createVersionDispatcher as
|
|
1507
|
+
createVersionDispatcher as createVersionDispatcher7,
|
|
1334
1508
|
hasStatusOrThrow as hasStatusOrThrow4,
|
|
1335
1509
|
parseWithErrorHandling as parseWithErrorHandling7
|
|
1336
1510
|
} from "@pagopa/io-wallet-utils";
|
|
1337
|
-
import
|
|
1511
|
+
import z15 from "zod";
|
|
1338
1512
|
|
|
1339
1513
|
// src/metadata/z-metadata-response.ts
|
|
1340
1514
|
import {
|
|
@@ -1342,23 +1516,29 @@ import {
|
|
|
1342
1516
|
itWalletMetadataV1_0,
|
|
1343
1517
|
itWalletMetadataV1_3
|
|
1344
1518
|
} from "@pagopa/io-wallet-oid-federation";
|
|
1345
|
-
import { z as
|
|
1346
|
-
var zMetadataResponseV1_0 =
|
|
1347
|
-
discoveredVia:
|
|
1519
|
+
import { z as z14 } from "zod";
|
|
1520
|
+
var zMetadataResponseV1_0 = z14.object({
|
|
1521
|
+
discoveredVia: z14.enum(["federation"]),
|
|
1348
1522
|
metadata: itWalletMetadataV1_0,
|
|
1349
1523
|
openid_federation_claims: itWalletEntityStatementClaimsSchema
|
|
1350
1524
|
});
|
|
1351
|
-
var zMetadataResponseV1_3 =
|
|
1352
|
-
|
|
1525
|
+
var zMetadataResponseV1_3 = z14.object({
|
|
1526
|
+
/**
|
|
1527
|
+
* Entity statement claims of the Authorization Server, present only when the
|
|
1528
|
+
* selected authorization server was resolved through a federation entity
|
|
1529
|
+
* distinct from the Credential Issuer.
|
|
1530
|
+
*/
|
|
1531
|
+
authorization_server_federation_claims: itWalletEntityStatementClaimsSchema.optional(),
|
|
1532
|
+
discoveredVia: z14.enum(["federation", "oid4vci"]),
|
|
1353
1533
|
metadata: itWalletMetadataV1_3,
|
|
1354
1534
|
openid_federation_claims: itWalletEntityStatementClaimsSchema.optional()
|
|
1355
1535
|
});
|
|
1356
|
-
var zMetadataResponse =
|
|
1536
|
+
var zMetadataResponse = z14.union([
|
|
1357
1537
|
zMetadataResponseV1_0,
|
|
1358
1538
|
zMetadataResponseV1_3
|
|
1359
1539
|
]);
|
|
1360
|
-
var zPartialIssuerMetadata =
|
|
1361
|
-
authorization_servers:
|
|
1540
|
+
var zPartialIssuerMetadata = z14.looseObject({
|
|
1541
|
+
authorization_servers: z14.tuple([z14.url()], z14.url()).optional()
|
|
1362
1542
|
});
|
|
1363
1543
|
|
|
1364
1544
|
// src/metadata/fetch-metadata.ts
|
|
@@ -1410,7 +1590,48 @@ async function tryFederationDiscovery(fetch, baseUrl, verifyJwt4) {
|
|
|
1410
1590
|
return void 0;
|
|
1411
1591
|
}
|
|
1412
1592
|
}
|
|
1413
|
-
async function
|
|
1593
|
+
async function applyFederationAuthorizationServerSelection(fetch, federationResult, authorizationServer, verifyJwt4) {
|
|
1594
|
+
const credentialIssuer = federationResult.metadata?.openid_credential_issuer?.credential_issuer;
|
|
1595
|
+
const authorizationServers = federationResult.metadata?.openid_credential_issuer?.authorization_servers;
|
|
1596
|
+
let selectedAuthorizationServer;
|
|
1597
|
+
if (authorizationServer) {
|
|
1598
|
+
assertAuthorizationServerAllowed(authorizationServer, authorizationServers);
|
|
1599
|
+
selectedAuthorizationServer = authorizationServer;
|
|
1600
|
+
} else if (authorizationServers && authorizationServers.length > 0) {
|
|
1601
|
+
selectedAuthorizationServer = credentialIssuer && authorizationServers.includes(credentialIssuer) ? credentialIssuer : authorizationServers[0];
|
|
1602
|
+
} else {
|
|
1603
|
+
selectedAuthorizationServer = credentialIssuer;
|
|
1604
|
+
}
|
|
1605
|
+
if (!selectedAuthorizationServer || selectedAuthorizationServer === credentialIssuer) {
|
|
1606
|
+
return federationResult;
|
|
1607
|
+
}
|
|
1608
|
+
const parsedSelectedAuthorizationServer = z15.url().safeParse(selectedAuthorizationServer);
|
|
1609
|
+
if (!parsedSelectedAuthorizationServer.success || !parsedSelectedAuthorizationServer.data.startsWith("https://")) {
|
|
1610
|
+
throw new ValidationError9(
|
|
1611
|
+
"selected authorization server is not a valid HTTPS URL"
|
|
1612
|
+
);
|
|
1613
|
+
}
|
|
1614
|
+
const authorizationServerResult = await tryFederationDiscovery(
|
|
1615
|
+
fetch,
|
|
1616
|
+
parsedSelectedAuthorizationServer.data,
|
|
1617
|
+
verifyJwt4
|
|
1618
|
+
);
|
|
1619
|
+
const resolvedAuthorizationServer = authorizationServerResult?.metadata?.oauth_authorization_server;
|
|
1620
|
+
if (!resolvedAuthorizationServer) {
|
|
1621
|
+
throw new ValidationError9(
|
|
1622
|
+
`Federation discovery did not yield oauth_authorization_server metadata for authorization server '${selectedAuthorizationServer}'`
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
return {
|
|
1626
|
+
...federationResult,
|
|
1627
|
+
authorization_server_federation_claims: authorizationServerResult.openid_federation_claims,
|
|
1628
|
+
metadata: {
|
|
1629
|
+
...federationResult.metadata,
|
|
1630
|
+
oauth_authorization_server: resolvedAuthorizationServer
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
async function fallbackDiscovery(fetch, baseUrl, authorizationServer) {
|
|
1414
1635
|
const issuerUrl = new URL(
|
|
1415
1636
|
".well-known/openid-credential-issuer",
|
|
1416
1637
|
ensureTrailingSlash(baseUrl)
|
|
@@ -1423,12 +1644,14 @@ async function fallbackDiscovery(fetch, baseUrl) {
|
|
|
1423
1644
|
"Failed to parse credential issuer metadata"
|
|
1424
1645
|
);
|
|
1425
1646
|
const authorizationServers = issuerJson.authorization_servers;
|
|
1647
|
+
assertAuthorizationServerAllowed(authorizationServer, authorizationServers);
|
|
1426
1648
|
let oauthAuthorizationServer;
|
|
1427
1649
|
if (authorizationServers && authorizationServers.length > 0) {
|
|
1428
|
-
const
|
|
1650
|
+
const selectedAuthorizationServer = authorizationServer ?? authorizationServers[0];
|
|
1651
|
+
const parsedUrl = z15.url().safeParse(selectedAuthorizationServer);
|
|
1429
1652
|
if (!parsedUrl.success || !parsedUrl.data.startsWith("https://")) {
|
|
1430
1653
|
throw new ValidationError9(
|
|
1431
|
-
"
|
|
1654
|
+
"selected authorization server is not a valid HTTPS URL"
|
|
1432
1655
|
);
|
|
1433
1656
|
}
|
|
1434
1657
|
const authServerUrl = new URL(
|
|
@@ -1474,22 +1697,31 @@ async function fetchMetadataV1_3(options) {
|
|
|
1474
1697
|
options.credentialIssuerUrl,
|
|
1475
1698
|
options.callbacks.verifyJwt
|
|
1476
1699
|
);
|
|
1477
|
-
const raw = federationResult
|
|
1700
|
+
const raw = federationResult ? await applyFederationAuthorizationServerSelection(
|
|
1701
|
+
fetch,
|
|
1702
|
+
federationResult,
|
|
1703
|
+
options.authorizationServer,
|
|
1704
|
+
options.callbacks.verifyJwt
|
|
1705
|
+
) : await fallbackDiscovery(
|
|
1706
|
+
fetch,
|
|
1707
|
+
options.credentialIssuerUrl,
|
|
1708
|
+
options.authorizationServer
|
|
1709
|
+
);
|
|
1478
1710
|
return parseWithErrorHandling7(
|
|
1479
1711
|
zMetadataResponseV1_3,
|
|
1480
1712
|
raw,
|
|
1481
1713
|
"Failed to parse v1.3 metadata response"
|
|
1482
1714
|
);
|
|
1483
1715
|
}
|
|
1484
|
-
var dispatchFetchMetadata =
|
|
1485
|
-
[
|
|
1486
|
-
[
|
|
1716
|
+
var dispatchFetchMetadata = createVersionDispatcher7({
|
|
1717
|
+
[ItWalletSpecsVersion10.V1_0]: (o) => fetchMetadataV1_0(o),
|
|
1718
|
+
[ItWalletSpecsVersion10.V1_3]: (o) => fetchMetadataV1_3(o),
|
|
1487
1719
|
// V1_4 reuses V1_3 metadata schema — no breaking changes between versions.
|
|
1488
|
-
[
|
|
1720
|
+
[ItWalletSpecsVersion10.V1_4]: (o) => fetchMetadataV1_3(o)
|
|
1489
1721
|
});
|
|
1490
1722
|
async function fetchMetadata(options) {
|
|
1491
1723
|
try {
|
|
1492
|
-
const urlValidation =
|
|
1724
|
+
const urlValidation = z15.url().safeParse(options.credentialIssuerUrl);
|
|
1493
1725
|
if (!urlValidation.success || !urlValidation.data.startsWith("https://")) {
|
|
1494
1726
|
throw new ValidationError9(
|
|
1495
1727
|
"credentialIssuerUrl must be a valid HTTPS URL"
|
|
@@ -1497,7 +1729,7 @@ async function fetchMetadata(options) {
|
|
|
1497
1729
|
}
|
|
1498
1730
|
return await dispatchFetchMetadata(options);
|
|
1499
1731
|
} catch (error) {
|
|
1500
|
-
if (error instanceof UnexpectedStatusCodeError4 || error instanceof ValidationError9 || error instanceof
|
|
1732
|
+
if (error instanceof UnexpectedStatusCodeError4 || error instanceof ValidationError9 || error instanceof ItWalletSpecsVersionError6 || error instanceof CredentialOfferError || error instanceof FetchMetadataError) {
|
|
1501
1733
|
throw error;
|
|
1502
1734
|
}
|
|
1503
1735
|
throw new FetchMetadataError("Unexpected error during metadata fetch", {
|
|
@@ -1513,7 +1745,7 @@ import {
|
|
|
1513
1745
|
createWalletAttestationJwtV1_4
|
|
1514
1746
|
} from "@pagopa/io-wallet-oauth2";
|
|
1515
1747
|
import {
|
|
1516
|
-
ItWalletSpecsVersion as
|
|
1748
|
+
ItWalletSpecsVersion as ItWalletSpecsVersion11,
|
|
1517
1749
|
addSecondsToDate,
|
|
1518
1750
|
dateToSeconds as dateToSeconds3,
|
|
1519
1751
|
dispatchByVersion
|
|
@@ -1682,7 +1914,7 @@ var WalletProvider = class {
|
|
|
1682
1914
|
*/
|
|
1683
1915
|
async createItWalletAttestationJwt(options) {
|
|
1684
1916
|
return dispatchByVersion(this.specVersion, {
|
|
1685
|
-
[
|
|
1917
|
+
[ItWalletSpecsVersion11.V1_0]: () => {
|
|
1686
1918
|
assertV1_0Options(options);
|
|
1687
1919
|
return createWalletAttestationJwtV1_0({
|
|
1688
1920
|
authenticatorAssuranceLevel: options.authenticatorAssuranceLevel,
|
|
@@ -1695,7 +1927,7 @@ var WalletProvider = class {
|
|
|
1695
1927
|
walletName: options.walletName
|
|
1696
1928
|
});
|
|
1697
1929
|
},
|
|
1698
|
-
[
|
|
1930
|
+
[ItWalletSpecsVersion11.V1_3]: () => {
|
|
1699
1931
|
assertV1_3Options(options);
|
|
1700
1932
|
return createWalletAttestationJwtV1_3({
|
|
1701
1933
|
callbacks: options.callbacks,
|
|
@@ -1709,7 +1941,7 @@ var WalletProvider = class {
|
|
|
1709
1941
|
walletName: options.walletName
|
|
1710
1942
|
});
|
|
1711
1943
|
},
|
|
1712
|
-
[
|
|
1944
|
+
[ItWalletSpecsVersion11.V1_4]: () => {
|
|
1713
1945
|
assertV1_4Options(options);
|
|
1714
1946
|
return createWalletAttestationJwtV1_4({
|
|
1715
1947
|
callbacks: options.callbacks,
|
|
@@ -1756,8 +1988,14 @@ export {
|
|
|
1756
1988
|
verifyAuthorizationResponseFormPostJWT,
|
|
1757
1989
|
verifyCredentialRequestJwtProof,
|
|
1758
1990
|
verifyKeyAttestationJwt,
|
|
1991
|
+
zAuthorizationCodeGrantV1_3,
|
|
1992
|
+
zAuthorizationCodeGrantV1_4,
|
|
1759
1993
|
zAuthorizationResponse,
|
|
1760
1994
|
zCredentialObject,
|
|
1995
|
+
zCredentialOfferGrantsV1_3,
|
|
1996
|
+
zCredentialOfferGrantsV1_4,
|
|
1997
|
+
zCredentialOfferV1_3,
|
|
1998
|
+
zCredentialOfferV1_4,
|
|
1761
1999
|
zCredentialRequestV1_0,
|
|
1762
2000
|
zCredentialRequestV1_3,
|
|
1763
2001
|
zCredentialResponseEncryption,
|