@owf/eudi-wrprc 0.0.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/README.md +264 -0
- package/dist/index.d.mts +1302 -0
- package/dist/index.mjs +892 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,892 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { IdentityException, base64urlEncode, decodeJwt } from "@owf/identity-common";
|
|
3
|
+
import { pemToDer } from "@owf/crypto";
|
|
4
|
+
//#region src/schemas.ts
|
|
5
|
+
/**
|
|
6
|
+
* WRPRC Zod Schemas
|
|
7
|
+
*
|
|
8
|
+
* Zod schemas for ETSI TS 119 475 (Wallet-Relying Party Registration Certificates).
|
|
9
|
+
* Types are derived from these schemas via z.infer<>.
|
|
10
|
+
*
|
|
11
|
+
* @see https://www.etsi.org/deliver/etsi_ts/119400_119499/119475/01.02.01_60/ts_119475v010201p.pdf
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Multilingual string schema (B.2.6 Class MultiLangString)
|
|
15
|
+
*/
|
|
16
|
+
const MultiLangStringSchema = z.object({
|
|
17
|
+
lang: z.string().min(2),
|
|
18
|
+
value: z.string().min(1)
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Supervisory Authority schema for Data Protection Authority
|
|
22
|
+
*/
|
|
23
|
+
const SupervisoryAuthoritySchema = z.object({
|
|
24
|
+
email: z.string().email().optional(),
|
|
25
|
+
phone: z.string().optional(),
|
|
26
|
+
uri: z.string().url().optional()
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Claim schema for credential attribute specification (B.2.10 Class Claim)
|
|
30
|
+
*/
|
|
31
|
+
const ClaimSchema = z.object({
|
|
32
|
+
path: z.array(z.string()).min(1),
|
|
33
|
+
values: z.array(z.union([
|
|
34
|
+
z.string(),
|
|
35
|
+
z.number(),
|
|
36
|
+
z.boolean()
|
|
37
|
+
])).optional()
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Credential schema for attestations (B.2.9 Class Credential)
|
|
41
|
+
*/
|
|
42
|
+
const CredentialSchema = z.object({
|
|
43
|
+
format: z.string().min(1),
|
|
44
|
+
meta: z.record(z.unknown()),
|
|
45
|
+
claim: z.array(ClaimSchema).optional()
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Status list reference for certificate validity
|
|
49
|
+
*/
|
|
50
|
+
const StatusListSchema = z.object({
|
|
51
|
+
idx: z.number().int().nonnegative(),
|
|
52
|
+
uri: z.string().url()
|
|
53
|
+
});
|
|
54
|
+
/**
|
|
55
|
+
* Status schema for WRPRC validity
|
|
56
|
+
*/
|
|
57
|
+
const StatusSchema = z.object({ status_list: StatusListSchema });
|
|
58
|
+
/**
|
|
59
|
+
* Intermediary information when WRP acts through an intermediary
|
|
60
|
+
*/
|
|
61
|
+
const IntermediarySchema = z.object({
|
|
62
|
+
sub: z.string().min(1),
|
|
63
|
+
name: z.string().min(1)
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* WRPRC Payload schema according to ETSI TS 119 475 clause 5.2.4
|
|
67
|
+
*/
|
|
68
|
+
const WRPRCPayloadSchema = z.object({
|
|
69
|
+
name: z.string().min(1),
|
|
70
|
+
sub_ln: z.string().optional(),
|
|
71
|
+
sub_gn: z.string().optional(),
|
|
72
|
+
sub_fn: z.string().optional(),
|
|
73
|
+
sub: z.string().min(1),
|
|
74
|
+
country: z.string().length(2),
|
|
75
|
+
registry_uri: z.string().url(),
|
|
76
|
+
srv_description: z.array(z.array(MultiLangStringSchema)).optional(),
|
|
77
|
+
entitlements: z.array(z.string().url()).min(1),
|
|
78
|
+
privacy_policy: z.string().url().optional(),
|
|
79
|
+
info_uri: z.string().url().optional(),
|
|
80
|
+
support_uri: z.string().url().optional(),
|
|
81
|
+
supervisory_authority: SupervisoryAuthoritySchema.optional(),
|
|
82
|
+
policy_id: z.array(z.string()).optional(),
|
|
83
|
+
certificate_policy: z.string().url().optional(),
|
|
84
|
+
iat: z.number().int().positive(),
|
|
85
|
+
status: StatusSchema.optional(),
|
|
86
|
+
purpose: z.array(MultiLangStringSchema).optional(),
|
|
87
|
+
credentials: z.array(CredentialSchema).optional(),
|
|
88
|
+
provides_attestations: z.array(CredentialSchema).optional(),
|
|
89
|
+
intermediary: IntermediarySchema.optional()
|
|
90
|
+
});
|
|
91
|
+
/**
|
|
92
|
+
* JWT Header schema according to ETSI TS 119 475 clause 5.2.2
|
|
93
|
+
*/
|
|
94
|
+
const WRPRCJWTHeaderSchema = z.object({
|
|
95
|
+
typ: z.literal("rc-wrp+jwt"),
|
|
96
|
+
alg: z.enum([
|
|
97
|
+
"ES256",
|
|
98
|
+
"ES384",
|
|
99
|
+
"ES512",
|
|
100
|
+
"RS256",
|
|
101
|
+
"RS384",
|
|
102
|
+
"RS512"
|
|
103
|
+
]),
|
|
104
|
+
x5c: z.array(z.string()).min(1),
|
|
105
|
+
kid: z.string().optional()
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* CWT Header schema according to ETSI TS 119 475 clause 5.2.3
|
|
109
|
+
*/
|
|
110
|
+
const WRPRCCWTHeaderSchema = z.object({
|
|
111
|
+
typ: z.literal("rc-wrp+cwt"),
|
|
112
|
+
alg: z.number().int(),
|
|
113
|
+
x5chain: z.array(z.instanceof(Uint8Array)).min(1)
|
|
114
|
+
});
|
|
115
|
+
z.object({
|
|
116
|
+
header: WRPRCJWTHeaderSchema,
|
|
117
|
+
payload: WRPRCPayloadSchema
|
|
118
|
+
});
|
|
119
|
+
z.object({
|
|
120
|
+
header: WRPRCCWTHeaderSchema,
|
|
121
|
+
payload: WRPRCPayloadSchema
|
|
122
|
+
});
|
|
123
|
+
/**
|
|
124
|
+
* Schema for legal person WRPRC subject
|
|
125
|
+
*/
|
|
126
|
+
const LegalPersonSubjectSchema = WRPRCPayloadSchema.extend({ sub_ln: z.string().min(1) }).omit({
|
|
127
|
+
sub_gn: true,
|
|
128
|
+
sub_fn: true
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* Schema for natural person WRPRC subject
|
|
132
|
+
*/
|
|
133
|
+
const NaturalPersonSubjectSchema = WRPRCPayloadSchema.extend({
|
|
134
|
+
sub_gn: z.string().min(1),
|
|
135
|
+
sub_fn: z.string().min(1)
|
|
136
|
+
}).omit({ sub_ln: true });
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/entitlements.ts
|
|
139
|
+
/**
|
|
140
|
+
* WRPRC Entitlement Constants
|
|
141
|
+
*
|
|
142
|
+
* Entitlement identifiers as defined in ETSI TS 119 475 Annex A.
|
|
143
|
+
* These identifiers define the roles and capabilities of Wallet-Relying Parties.
|
|
144
|
+
*
|
|
145
|
+
* @see https://www.etsi.org/deliver/etsi_ts/119400_119499/119475/01.02.01_60/ts_119475v010201p.pdf
|
|
146
|
+
*/
|
|
147
|
+
/**
|
|
148
|
+
* Base OID for ETSI WRPA entitlements: 0.4.0.19475
|
|
149
|
+
* id-etsi-wrpa OBJECT IDENTIFIER ::= { itu-t(0) identified-organization(4) etsi(0) 19475 }
|
|
150
|
+
*/
|
|
151
|
+
const ETSI_WRPA_BASE_OID = "0.4.0.19475";
|
|
152
|
+
`${ETSI_WRPA_BASE_OID}`;
|
|
153
|
+
/**
|
|
154
|
+
* Service_Provider - General service provider (A.2.1)
|
|
155
|
+
* OID: id-etsi-wrpa-entitlement 1
|
|
156
|
+
*/
|
|
157
|
+
const ENTITLEMENT_SERVICE_PROVIDER = "https://uri.etsi.org/19475/Entitlement/Service_Provider";
|
|
158
|
+
/**
|
|
159
|
+
* QEAA_Provider - Qualified trust service provider issuing qualified electronic attestations of attributes (A.2.2)
|
|
160
|
+
* OID: id-etsi-wrpa-entitlement 2
|
|
161
|
+
*/
|
|
162
|
+
const ENTITLEMENT_QEAA_PROVIDER = "https://uri.etsi.org/19475/Entitlement/QEAA_Provider";
|
|
163
|
+
/**
|
|
164
|
+
* Non_Q_EAA_Provider - Trust service provider issuing non-qualified electronic attestations of attributes (A.2.3)
|
|
165
|
+
* OID: id-etsi-wrpa-entitlement 3
|
|
166
|
+
*/
|
|
167
|
+
const ENTITLEMENT_NON_Q_EAA_PROVIDER = "https://uri.etsi.org/19475/Entitlement/Non_Q_EAA_Provider";
|
|
168
|
+
/**
|
|
169
|
+
* PUB_EAA_Provider - Public sector body or its agent issuing electronic attestations of attributes from authentic sources (A.2.4)
|
|
170
|
+
* OID: id-etsi-wrpa-entitlement 4
|
|
171
|
+
*/
|
|
172
|
+
const ENTITLEMENT_PUB_EAA_PROVIDER = "https://uri.etsi.org/19475/Entitlement/PUB_EAA_Provider";
|
|
173
|
+
/**
|
|
174
|
+
* PID_Provider - Provider of person identification data (A.2.5)
|
|
175
|
+
* OID: id-etsi-wrpa-entitlement 5
|
|
176
|
+
*/
|
|
177
|
+
const ENTITLEMENT_PID_PROVIDER = "https://uri.etsi.org/19475/Entitlement/PID_Provider";
|
|
178
|
+
/**
|
|
179
|
+
* All standard WRP entitlements defined in ETSI TS 119 475
|
|
180
|
+
*/
|
|
181
|
+
const WRP_ENTITLEMENTS = {
|
|
182
|
+
SERVICE_PROVIDER: ENTITLEMENT_SERVICE_PROVIDER,
|
|
183
|
+
QEAA_PROVIDER: ENTITLEMENT_QEAA_PROVIDER,
|
|
184
|
+
NON_Q_EAA_PROVIDER: ENTITLEMENT_NON_Q_EAA_PROVIDER,
|
|
185
|
+
PUB_EAA_PROVIDER: ENTITLEMENT_PUB_EAA_PROVIDER,
|
|
186
|
+
PID_PROVIDER: ENTITLEMENT_PID_PROVIDER,
|
|
187
|
+
QCERT_FOR_ESEAL_PROVIDER: "https://uri.etsi.org/19475/Entitlement/QCert_for_ESeal_Provider",
|
|
188
|
+
QCERT_FOR_ESIG_PROVIDER: "https://uri.etsi.org/19475/Entitlement/QCert_for_ESig_Provider",
|
|
189
|
+
RQSEALCDS_PROVIDER: "https://uri.etsi.org/19475/Entitlement/rQSealCDs_Provider",
|
|
190
|
+
RQSIGCDS_PROVIDER: "https://uri.etsi.org/19475/Entitlement/rQSigCDs_Provider",
|
|
191
|
+
ESIG_ESEAL_CREATION_PROVIDER: "https://uri.etsi.org/19475/Entitlement/ESig_ESeal_Creation_Provider"
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* List of all standard entitlement URIs
|
|
195
|
+
*/
|
|
196
|
+
const ALL_ENTITLEMENTS = Object.values(WRP_ENTITLEMENTS);
|
|
197
|
+
/**
|
|
198
|
+
* Entitlements for attestation providers (QEAA, Non-Q EAA, PUB EAA, PID)
|
|
199
|
+
*/
|
|
200
|
+
const ATTESTATION_PROVIDER_ENTITLEMENTS = [
|
|
201
|
+
ENTITLEMENT_QEAA_PROVIDER,
|
|
202
|
+
ENTITLEMENT_NON_Q_EAA_PROVIDER,
|
|
203
|
+
ENTITLEMENT_PUB_EAA_PROVIDER,
|
|
204
|
+
ENTITLEMENT_PID_PROVIDER
|
|
205
|
+
];
|
|
206
|
+
/**
|
|
207
|
+
* Payment Service Provider Sub-entitlements (A.3.1)
|
|
208
|
+
* As defined in ETSI TS 119 495
|
|
209
|
+
*/
|
|
210
|
+
const PSP_SUB_ENTITLEMENTS = {
|
|
211
|
+
ACCOUNT_SERVICING: "https://uri.etsi.org/19475/SubEntitlement/psp/psp-as",
|
|
212
|
+
PAYMENT_INITIATION: "https://uri.etsi.org/19475/SubEntitlement/psp/psp-pi",
|
|
213
|
+
ACCOUNT_INFORMATION: "https://uri.etsi.org/19475/SubEntitlement/psp/psp-ai",
|
|
214
|
+
CARD_BASED: "https://uri.etsi.org/19475/SubEntitlement/psp/psp-ic",
|
|
215
|
+
UNSPECIFIED: "https://uri.etsi.org/19475/SubEntitlement/psp/unspecified"
|
|
216
|
+
};
|
|
217
|
+
/**
|
|
218
|
+
* All PSP sub-entitlement URIs
|
|
219
|
+
*/
|
|
220
|
+
const ALL_PSP_SUB_ENTITLEMENTS = Object.values(PSP_SUB_ENTITLEMENTS);
|
|
221
|
+
/**
|
|
222
|
+
* Identifier type URIs for legal person semantic identifiers
|
|
223
|
+
*/
|
|
224
|
+
const IDENTIFIER_TYPES = {
|
|
225
|
+
EORI: "http://data.europa.eu/eudi/id/EORI-No",
|
|
226
|
+
LEI: "http://data.europa.eu/eudi/id/LEI",
|
|
227
|
+
EUID: "http://data.europa.eu/eudi/id/EUID",
|
|
228
|
+
VATIN: "http://data.europa.eu/eudi/id/VATIN",
|
|
229
|
+
TIN: "http://data.europa.eu/eudi/id/TIN",
|
|
230
|
+
EXCISE: "http://data.europa.eu/eudi/id/Excise"
|
|
231
|
+
};
|
|
232
|
+
IDENTIFIER_TYPES.EORI, IDENTIFIER_TYPES.LEI, IDENTIFIER_TYPES.EUID, IDENTIFIER_TYPES.VATIN, IDENTIFIER_TYPES.TIN, IDENTIFIER_TYPES.EXCISE;
|
|
233
|
+
`${ETSI_WRPA_BASE_OID}`;
|
|
234
|
+
/**
|
|
235
|
+
* Check if a given URI is a valid WRP entitlement
|
|
236
|
+
*/
|
|
237
|
+
function isValidEntitlement(uri) {
|
|
238
|
+
return ALL_ENTITLEMENTS.includes(uri);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Check if a given URI is a PSP sub-entitlement
|
|
242
|
+
*/
|
|
243
|
+
function isPSPSubEntitlement(uri) {
|
|
244
|
+
return ALL_PSP_SUB_ENTITLEMENTS.includes(uri);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Check if entitlements include an attestation provider role
|
|
248
|
+
*/
|
|
249
|
+
function hasAttestationProviderEntitlement(entitlements) {
|
|
250
|
+
return entitlements.some((e) => ATTESTATION_PROVIDER_ENTITLEMENTS.includes(e));
|
|
251
|
+
}
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/wrprc-exception.ts
|
|
254
|
+
/**
|
|
255
|
+
* WRPRCException is a custom error class for WRPRC-related exceptions.
|
|
256
|
+
*/
|
|
257
|
+
var WRPRCException = class WRPRCException extends IdentityException {
|
|
258
|
+
constructor(message, details) {
|
|
259
|
+
super(message, details);
|
|
260
|
+
Object.setPrototypeOf(this, WRPRCException.prototype);
|
|
261
|
+
this.name = "WRPRCException";
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
//#endregion
|
|
265
|
+
//#region src/validator.ts
|
|
266
|
+
/**
|
|
267
|
+
* WRPRC Validator
|
|
268
|
+
*
|
|
269
|
+
* Validation functions for ETSI TS 119 475 Wallet-Relying Party Registration Certificates.
|
|
270
|
+
*
|
|
271
|
+
* @see https://www.etsi.org/deliver/etsi_ts/119400_119499/119475/01.02.01_60/ts_119475v010201p.pdf
|
|
272
|
+
*/
|
|
273
|
+
/**
|
|
274
|
+
* Validate a WRPRC payload against the schema
|
|
275
|
+
*/
|
|
276
|
+
function validateWRPRCPayload(payload) {
|
|
277
|
+
const result = WRPRCPayloadSchema.safeParse(payload);
|
|
278
|
+
const errors = [];
|
|
279
|
+
const warnings = [];
|
|
280
|
+
if (!result.success) {
|
|
281
|
+
for (const issue of result.error.issues) errors.push({
|
|
282
|
+
path: issue.path.map(String),
|
|
283
|
+
message: issue.message,
|
|
284
|
+
code: issue.code
|
|
285
|
+
});
|
|
286
|
+
return {
|
|
287
|
+
valid: false,
|
|
288
|
+
errors,
|
|
289
|
+
warnings
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const validPayload = result.data;
|
|
293
|
+
for (const entitlement of validPayload.entitlements) if (!ALL_ENTITLEMENTS.includes(entitlement)) {
|
|
294
|
+
if (!ALL_PSP_SUB_ENTITLEMENTS.includes(entitlement)) warnings.push({
|
|
295
|
+
path: ["entitlements"],
|
|
296
|
+
message: `Unknown entitlement URI: ${entitlement}. This may be a national or EU-defined extension.`,
|
|
297
|
+
code: "unknown_entitlement"
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
if (validPayload.entitlements.length === 0) errors.push({
|
|
301
|
+
path: ["entitlements"],
|
|
302
|
+
message: "At least one entitlement must be specified (GEN-5.2.4-03)",
|
|
303
|
+
code: "missing_entitlement"
|
|
304
|
+
});
|
|
305
|
+
const hasSubEntitlement = validPayload.entitlements.some((e) => ALL_PSP_SUB_ENTITLEMENTS.includes(e));
|
|
306
|
+
const hasServiceProvider = validPayload.entitlements.includes("https://uri.etsi.org/19475/Entitlement/Service_Provider");
|
|
307
|
+
if (hasSubEntitlement && !hasServiceProvider) errors.push({
|
|
308
|
+
path: ["entitlements"],
|
|
309
|
+
message: "Service provider sub-entitlements require Service_Provider entitlement (GEN-5.2.4-04)",
|
|
310
|
+
code: "missing_base_entitlement"
|
|
311
|
+
});
|
|
312
|
+
if (validPayload.entitlements.some((e) => ATTESTATION_PROVIDER_ENTITLEMENTS.includes(e)) && !validPayload.provides_attestations) warnings.push({
|
|
313
|
+
path: ["provides_attestations"],
|
|
314
|
+
message: "Attestation providers should include provides_attestations field (GEN-5.2.4-05). This is recommended but not required.",
|
|
315
|
+
code: "missing_provides_attestations"
|
|
316
|
+
});
|
|
317
|
+
const subResult = validateSemanticIdentifier(validPayload.sub);
|
|
318
|
+
if (!subResult.valid) errors.push({
|
|
319
|
+
path: ["sub"],
|
|
320
|
+
message: subResult.message,
|
|
321
|
+
code: "invalid_semantic_identifier"
|
|
322
|
+
});
|
|
323
|
+
return {
|
|
324
|
+
valid: errors.length === 0,
|
|
325
|
+
errors,
|
|
326
|
+
warnings
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Validate a JWT header for WRPRC
|
|
331
|
+
*/
|
|
332
|
+
function validateWRPRCJWTHeader(header) {
|
|
333
|
+
const result = WRPRCJWTHeaderSchema.safeParse(header);
|
|
334
|
+
const errors = [];
|
|
335
|
+
const warnings = [];
|
|
336
|
+
if (!result.success) for (const issue of result.error.issues) errors.push({
|
|
337
|
+
path: issue.path.map(String),
|
|
338
|
+
message: issue.message,
|
|
339
|
+
code: issue.code
|
|
340
|
+
});
|
|
341
|
+
return {
|
|
342
|
+
valid: errors.length === 0,
|
|
343
|
+
errors,
|
|
344
|
+
warnings
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Validate a complete WRPRC (header + payload)
|
|
349
|
+
*/
|
|
350
|
+
function validateWRPRC(header, payload) {
|
|
351
|
+
const headerResult = validateWRPRCJWTHeader(header);
|
|
352
|
+
const payloadResult = validateWRPRCPayload(payload);
|
|
353
|
+
const errors = [...headerResult.errors.map((e) => ({
|
|
354
|
+
...e,
|
|
355
|
+
path: ["header", ...e.path]
|
|
356
|
+
})), ...payloadResult.errors.map((e) => ({
|
|
357
|
+
...e,
|
|
358
|
+
path: ["payload", ...e.path]
|
|
359
|
+
}))];
|
|
360
|
+
const warnings = [...headerResult.warnings.map((w) => ({
|
|
361
|
+
...w,
|
|
362
|
+
path: ["header", ...w.path]
|
|
363
|
+
})), ...payloadResult.warnings.map((w) => ({
|
|
364
|
+
...w,
|
|
365
|
+
path: ["payload", ...w.path]
|
|
366
|
+
}))];
|
|
367
|
+
return {
|
|
368
|
+
valid: errors.length === 0,
|
|
369
|
+
errors,
|
|
370
|
+
warnings
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Check if payload represents a legal person
|
|
375
|
+
*/
|
|
376
|
+
function isLegalPersonWRPRC(payload) {
|
|
377
|
+
return typeof payload.sub_ln === "string" && payload.sub_ln.length > 0;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Check if payload represents a natural person
|
|
381
|
+
*/
|
|
382
|
+
function isNaturalPersonWRPRC(payload) {
|
|
383
|
+
return typeof payload.sub_gn === "string" && payload.sub_gn.length > 0 && typeof payload.sub_fn === "string" && payload.sub_fn.length > 0;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Validate as legal person WRPRC
|
|
387
|
+
*/
|
|
388
|
+
function validateLegalPersonWRPRC(payload) {
|
|
389
|
+
const result = LegalPersonSubjectSchema.safeParse(payload);
|
|
390
|
+
const errors = [];
|
|
391
|
+
const warnings = [];
|
|
392
|
+
if (!result.success) for (const issue of result.error.issues) errors.push({
|
|
393
|
+
path: issue.path.map(String),
|
|
394
|
+
message: issue.message,
|
|
395
|
+
code: issue.code
|
|
396
|
+
});
|
|
397
|
+
if (result.success) {
|
|
398
|
+
const sub = result.data.sub;
|
|
399
|
+
if (!/^[A-Z]{3}[A-Z]{2}-.+$/.test(sub)) warnings.push({
|
|
400
|
+
path: ["sub"],
|
|
401
|
+
message: "Legal person identifier should follow format: PREFIX + COUNTRY + \"-\" + ID (e.g., \"LEIXG-529900T8BM49AURSDO55\")",
|
|
402
|
+
code: "identifier_format_warning"
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
valid: errors.length === 0,
|
|
407
|
+
errors,
|
|
408
|
+
warnings
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Validate as natural person WRPRC
|
|
413
|
+
*/
|
|
414
|
+
function validateNaturalPersonWRPRC(payload) {
|
|
415
|
+
const result = NaturalPersonSubjectSchema.safeParse(payload);
|
|
416
|
+
const errors = [];
|
|
417
|
+
const warnings = [];
|
|
418
|
+
if (!result.success) for (const issue of result.error.issues) errors.push({
|
|
419
|
+
path: issue.path.map(String),
|
|
420
|
+
message: issue.message,
|
|
421
|
+
code: issue.code
|
|
422
|
+
});
|
|
423
|
+
if (result.success) {
|
|
424
|
+
const sub = result.data.sub;
|
|
425
|
+
if (!/^[A-Z]{3}[A-Z]{2}-.+$/.test(sub)) warnings.push({
|
|
426
|
+
path: ["sub"],
|
|
427
|
+
message: "Natural person identifier should follow format: PREFIX + COUNTRY + \"-\" + ID (e.g., \"TINIT-RSSMRA85T10A562S\")",
|
|
428
|
+
code: "identifier_format_warning"
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
valid: errors.length === 0,
|
|
433
|
+
errors,
|
|
434
|
+
warnings
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Valid semantic identifier prefixes for legal persons (ETSI EN 319 412-1 clause 5.1.4)
|
|
439
|
+
*/
|
|
440
|
+
const LEGAL_PERSON_PREFIXES = [
|
|
441
|
+
"EOR",
|
|
442
|
+
"LEI",
|
|
443
|
+
"NTR",
|
|
444
|
+
"VAT",
|
|
445
|
+
"TIN",
|
|
446
|
+
"EXC"
|
|
447
|
+
];
|
|
448
|
+
/**
|
|
449
|
+
* Valid semantic identifier prefixes for natural persons (ETSI EN 319 412-1 clause 5.1.3)
|
|
450
|
+
*/
|
|
451
|
+
const NATURAL_PERSON_PREFIXES = [
|
|
452
|
+
"TIN",
|
|
453
|
+
"PAS",
|
|
454
|
+
"IDC",
|
|
455
|
+
"PNO",
|
|
456
|
+
"TAX"
|
|
457
|
+
];
|
|
458
|
+
/**
|
|
459
|
+
* Validate a semantic identifier format
|
|
460
|
+
*/
|
|
461
|
+
function validateSemanticIdentifier(identifier) {
|
|
462
|
+
const match = identifier.match(/^([A-Z]{3})([A-Z]{2})-(.+)$/);
|
|
463
|
+
if (!match) return {
|
|
464
|
+
valid: false,
|
|
465
|
+
message: "Semantic identifier must follow format: PREFIX (3 chars) + COUNTRY (2 chars) + \"-\" + ID"
|
|
466
|
+
};
|
|
467
|
+
const [, prefix, , id] = match;
|
|
468
|
+
if (![...LEGAL_PERSON_PREFIXES, ...NATURAL_PERSON_PREFIXES].includes(prefix)) {}
|
|
469
|
+
if (!id || id.length === 0) return {
|
|
470
|
+
valid: false,
|
|
471
|
+
message: "Semantic identifier must have a non-empty ID part after the hyphen"
|
|
472
|
+
};
|
|
473
|
+
return {
|
|
474
|
+
valid: true,
|
|
475
|
+
message: ""
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Assert that a WRPRC payload is valid, throws WRPRCException if not
|
|
480
|
+
*/
|
|
481
|
+
function assertValidWRPRCPayload(payload) {
|
|
482
|
+
const result = validateWRPRCPayload(payload);
|
|
483
|
+
if (!result.valid) throw new WRPRCException(`Invalid WRPRC payload:\n${result.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join("\n")}`, result.errors);
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Assert that a WRPRC is valid (header + payload), throws WRPRCException if not
|
|
487
|
+
*/
|
|
488
|
+
function assertValidWRPRC(header, payload) {
|
|
489
|
+
const result = validateWRPRC(header, payload);
|
|
490
|
+
if (!result.valid) throw new WRPRCException(`Invalid WRPRC:\n${result.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join("\n")}`, result.errors);
|
|
491
|
+
}
|
|
492
|
+
//#endregion
|
|
493
|
+
//#region src/builders.ts
|
|
494
|
+
/**
|
|
495
|
+
* WRPRC Builders
|
|
496
|
+
*
|
|
497
|
+
* Fluent builders for creating ETSI TS 119 475 Wallet-Relying Party Registration Certificates.
|
|
498
|
+
*
|
|
499
|
+
* @see https://www.etsi.org/deliver/etsi_ts/119400_119499/119475/01.02.01_60/ts_119475v010201p.pdf
|
|
500
|
+
*/
|
|
501
|
+
/**
|
|
502
|
+
* Builder for creating WRPRC payloads with a fluent API
|
|
503
|
+
*/
|
|
504
|
+
var WRPRCBuilder = class {
|
|
505
|
+
constructor() {
|
|
506
|
+
this.payload = {};
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Set the trade name (display name) of the WRP
|
|
510
|
+
*/
|
|
511
|
+
name(value) {
|
|
512
|
+
this.payload.name = value;
|
|
513
|
+
return this;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Set the legal name for a legal person WRP
|
|
517
|
+
*/
|
|
518
|
+
legalName(value) {
|
|
519
|
+
this.payload.sub_ln = value;
|
|
520
|
+
return this;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Set the given name for a natural person WRP
|
|
524
|
+
*/
|
|
525
|
+
givenName(value) {
|
|
526
|
+
this.payload.sub_gn = value;
|
|
527
|
+
return this;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Set the family name for a natural person WRP
|
|
531
|
+
*/
|
|
532
|
+
familyName(value) {
|
|
533
|
+
this.payload.sub_fn = value;
|
|
534
|
+
return this;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Set the WRP identifier (semantic identifier)
|
|
538
|
+
*
|
|
539
|
+
* @param identifier - The semantic identifier following ETSI EN 319 412-1
|
|
540
|
+
* Format: PREFIX (3 chars) + COUNTRY (2 chars) + "-" + ID
|
|
541
|
+
* Examples: "LEIXG-529900T8BM49AURSDO55", "TINIT-RSSMRA85T10A562S"
|
|
542
|
+
*/
|
|
543
|
+
identifier(identifier) {
|
|
544
|
+
this.payload.sub = identifier;
|
|
545
|
+
return this;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Set the country code (ISO 3166-1 Alpha-2)
|
|
549
|
+
*/
|
|
550
|
+
country(code) {
|
|
551
|
+
this.payload.country = code;
|
|
552
|
+
return this;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Set the URL to the national registry API endpoint
|
|
556
|
+
*/
|
|
557
|
+
registryUri(uri) {
|
|
558
|
+
this.payload.registry_uri = uri;
|
|
559
|
+
return this;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Add a service description in a specific language
|
|
563
|
+
*/
|
|
564
|
+
serviceDescription(description, lang = "en") {
|
|
565
|
+
this.payload.srv_description = this.payload.srv_description ?? [];
|
|
566
|
+
const existing = this.payload.srv_description.find((group) => group.some((d) => d.lang === lang));
|
|
567
|
+
if (existing) existing.push({
|
|
568
|
+
lang,
|
|
569
|
+
value: description
|
|
570
|
+
});
|
|
571
|
+
else this.payload.srv_description.push([{
|
|
572
|
+
lang,
|
|
573
|
+
value: description
|
|
574
|
+
}]);
|
|
575
|
+
return this;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Add multiple service descriptions (one array per service, with multiple languages)
|
|
579
|
+
*/
|
|
580
|
+
addServiceDescriptions(descriptions) {
|
|
581
|
+
this.payload.srv_description = this.payload.srv_description ?? [];
|
|
582
|
+
this.payload.srv_description.push(descriptions);
|
|
583
|
+
return this;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Add an entitlement
|
|
587
|
+
*
|
|
588
|
+
* @param entitlement - The entitlement URI or key from WRP_ENTITLEMENTS
|
|
589
|
+
*/
|
|
590
|
+
addEntitlement(entitlement) {
|
|
591
|
+
this.payload.entitlements = this.payload.entitlements ?? [];
|
|
592
|
+
if (!this.payload.entitlements.includes(entitlement)) this.payload.entitlements.push(entitlement);
|
|
593
|
+
return this;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Set all entitlements (replaces existing)
|
|
597
|
+
*/
|
|
598
|
+
entitlements(entitlements) {
|
|
599
|
+
this.payload.entitlements = [...entitlements];
|
|
600
|
+
return this;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Set the privacy policy URL
|
|
604
|
+
*/
|
|
605
|
+
privacyPolicy(uri) {
|
|
606
|
+
this.payload.privacy_policy = uri;
|
|
607
|
+
return this;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Set the info URI (general-purpose web address)
|
|
611
|
+
*/
|
|
612
|
+
infoUri(uri) {
|
|
613
|
+
this.payload.info_uri = uri;
|
|
614
|
+
return this;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Set the support URI for data requests
|
|
618
|
+
*/
|
|
619
|
+
supportUri(uri) {
|
|
620
|
+
this.payload.support_uri = uri;
|
|
621
|
+
return this;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Set the supervisory authority (Data Protection Authority)
|
|
625
|
+
*/
|
|
626
|
+
supervisoryAuthority(authority) {
|
|
627
|
+
this.payload.supervisory_authority = authority;
|
|
628
|
+
return this;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Set the policy ID(s)
|
|
632
|
+
*/
|
|
633
|
+
policyId(ids) {
|
|
634
|
+
this.payload.policy_id = ids;
|
|
635
|
+
return this;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Set the certificate policy URL
|
|
639
|
+
*/
|
|
640
|
+
certificatePolicy(uri) {
|
|
641
|
+
this.payload.certificate_policy = uri;
|
|
642
|
+
return this;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Set the issued-at timestamp (Unix timestamp)
|
|
646
|
+
* If not set, will default to current time when building
|
|
647
|
+
*/
|
|
648
|
+
issuedAt(timestamp) {
|
|
649
|
+
this.payload.iat = typeof timestamp === "number" ? timestamp : Math.floor(timestamp.getTime() / 1e3);
|
|
650
|
+
return this;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Set the status reference for certificate validity
|
|
654
|
+
*/
|
|
655
|
+
status(status) {
|
|
656
|
+
this.payload.status = status;
|
|
657
|
+
return this;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Add a purpose description
|
|
661
|
+
*/
|
|
662
|
+
addPurpose(description, lang = "en") {
|
|
663
|
+
this.payload.purpose = this.payload.purpose ?? [];
|
|
664
|
+
this.payload.purpose.push({
|
|
665
|
+
lang,
|
|
666
|
+
value: description
|
|
667
|
+
});
|
|
668
|
+
return this;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Set all purposes (replaces existing)
|
|
672
|
+
*/
|
|
673
|
+
purposes(purposes) {
|
|
674
|
+
this.payload.purpose = purposes;
|
|
675
|
+
return this;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Add a credential that the WRP intends to request
|
|
679
|
+
*/
|
|
680
|
+
addCredential(credential) {
|
|
681
|
+
this.payload.credentials = this.payload.credentials ?? [];
|
|
682
|
+
this.payload.credentials.push(credential);
|
|
683
|
+
return this;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Add a credential the WRP provides (for attestation providers)
|
|
687
|
+
*/
|
|
688
|
+
addProvidedAttestation(credential) {
|
|
689
|
+
this.payload.provides_attestations = this.payload.provides_attestations ?? [];
|
|
690
|
+
this.payload.provides_attestations.push(credential);
|
|
691
|
+
return this;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Set intermediary information
|
|
695
|
+
*/
|
|
696
|
+
intermediary(intermediary) {
|
|
697
|
+
this.payload.intermediary = intermediary;
|
|
698
|
+
return this;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Build the WRPRC payload
|
|
702
|
+
*
|
|
703
|
+
* @throws WRPRCException if the payload is invalid
|
|
704
|
+
*/
|
|
705
|
+
build() {
|
|
706
|
+
if (!this.payload.iat) this.payload.iat = Math.floor(Date.now() / 1e3);
|
|
707
|
+
const result = WRPRCPayloadSchema.safeParse(this.payload);
|
|
708
|
+
if (!result.success) throw new WRPRCException(`Invalid WRPRC payload:\n${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("\n")}`, result.error.issues);
|
|
709
|
+
return result.data;
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
/**
|
|
713
|
+
* Builder for creating Credential objects
|
|
714
|
+
*/
|
|
715
|
+
var CredentialBuilder = class {
|
|
716
|
+
constructor() {
|
|
717
|
+
this.credential = {};
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Set the credential format
|
|
721
|
+
*
|
|
722
|
+
* @param format - The format identifier (e.g., "dc+sd-jwt", "mso_mdoc")
|
|
723
|
+
*/
|
|
724
|
+
format(format) {
|
|
725
|
+
this.credential.format = format;
|
|
726
|
+
return this;
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Set the credential metadata
|
|
730
|
+
*
|
|
731
|
+
* @param meta - Metadata object per credential format specification
|
|
732
|
+
*/
|
|
733
|
+
meta(meta) {
|
|
734
|
+
this.credential.meta = meta;
|
|
735
|
+
return this;
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Set SD-JWT credential metadata (vct_values)
|
|
739
|
+
*/
|
|
740
|
+
sdJwtMeta(vctValues) {
|
|
741
|
+
this.credential.format = "dc+sd-jwt";
|
|
742
|
+
this.credential.meta = { vct_values: vctValues };
|
|
743
|
+
return this;
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Set mDL/mDoc credential metadata (doctype_value)
|
|
747
|
+
*/
|
|
748
|
+
mdocMeta(doctypeValue) {
|
|
749
|
+
this.credential.format = "mso_mdoc";
|
|
750
|
+
this.credential.meta = { doctype_value: doctypeValue };
|
|
751
|
+
return this;
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Add a claim to request
|
|
755
|
+
*/
|
|
756
|
+
addClaim(claim) {
|
|
757
|
+
this.credential.claim = this.credential.claim ?? [];
|
|
758
|
+
this.credential.claim.push(claim);
|
|
759
|
+
return this;
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Add a simple path claim
|
|
763
|
+
*/
|
|
764
|
+
addPathClaim(...path) {
|
|
765
|
+
this.credential.claim = this.credential.claim ?? [];
|
|
766
|
+
this.credential.claim.push({ path });
|
|
767
|
+
return this;
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Build the Credential object
|
|
771
|
+
*/
|
|
772
|
+
build() {
|
|
773
|
+
if (!this.credential.format) throw new WRPRCException("Credential format is required");
|
|
774
|
+
if (!this.credential.meta) throw new WRPRCException("Credential meta is required");
|
|
775
|
+
return this.credential;
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
/**
|
|
779
|
+
* Create a new WRPRCBuilder
|
|
780
|
+
*/
|
|
781
|
+
function wrprc() {
|
|
782
|
+
return new WRPRCBuilder();
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Create a new CredentialBuilder
|
|
786
|
+
*/
|
|
787
|
+
function credential() {
|
|
788
|
+
return new CredentialBuilder();
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Create a WRPRC payload for a legal person
|
|
792
|
+
*/
|
|
793
|
+
function createLegalPersonWRPRC(input) {
|
|
794
|
+
return wrprc().name(input.name).legalName(input.legalName).identifier(input.identifier).country(input.country).registryUri(input.registryUri).entitlements(input.entitlements).build();
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Create a WRPRC payload for a natural person
|
|
798
|
+
*/
|
|
799
|
+
function createNaturalPersonWRPRC(input) {
|
|
800
|
+
return wrprc().name(input.name).givenName(input.givenName).familyName(input.familyName).identifier(input.identifier).country(input.country).registryUri(input.registryUri).entitlements(input.entitlements).build();
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Create a simple service provider WRPRC
|
|
804
|
+
*/
|
|
805
|
+
function createServiceProviderWRPRC(name, legalName, identifier, country, registryUri) {
|
|
806
|
+
return wrprc().name(name).legalName(legalName).identifier(identifier).country(country).registryUri(registryUri).addEntitlement(ENTITLEMENT_SERVICE_PROVIDER).build();
|
|
807
|
+
}
|
|
808
|
+
//#endregion
|
|
809
|
+
//#region src/signer.ts
|
|
810
|
+
/**
|
|
811
|
+
* WRPRC Signer
|
|
812
|
+
*
|
|
813
|
+
* Functions for creating and signing ETSI TS 119 475 Wallet-Relying Party Registration Certificates.
|
|
814
|
+
*
|
|
815
|
+
* @see https://www.etsi.org/deliver/etsi_ts/119400_119499/119475/01.02.01_60/ts_119475v010201p.pdf
|
|
816
|
+
*/
|
|
817
|
+
/**
|
|
818
|
+
* Sign a WRPRC payload to create a JWT
|
|
819
|
+
*
|
|
820
|
+
* @param options - Signing options including payload, algorithm, certificates, and signer
|
|
821
|
+
* @returns Signed WRPRC with JWS string and decoded parts
|
|
822
|
+
*/
|
|
823
|
+
async function signWRPRC(options) {
|
|
824
|
+
const { payload, algorithm = "ES256", certificates, keyId, signer } = options;
|
|
825
|
+
assertValidWRPRCPayload(payload);
|
|
826
|
+
if (!certificates || certificates.length === 0) throw new WRPRCException("At least one certificate is required for x5c header");
|
|
827
|
+
const header = {
|
|
828
|
+
typ: "rc-wrp+jwt",
|
|
829
|
+
alg: algorithm,
|
|
830
|
+
x5c: certificates.map((cert) => {
|
|
831
|
+
const content = pemToDer(cert);
|
|
832
|
+
if (!content) throw new WRPRCException("Invalid PEM certificate format");
|
|
833
|
+
return content;
|
|
834
|
+
}),
|
|
835
|
+
...keyId && { kid: keyId }
|
|
836
|
+
};
|
|
837
|
+
const signingInput = `${base64urlEncode(JSON.stringify(header))}.${base64urlEncode(JSON.stringify(payload))}`;
|
|
838
|
+
return {
|
|
839
|
+
jws: `${signingInput}.${await signer(signingInput)}`,
|
|
840
|
+
header,
|
|
841
|
+
payload
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Decode a signed WRPRC JWT (without verification)
|
|
846
|
+
*
|
|
847
|
+
* @param jws - The compact JWS string
|
|
848
|
+
* @returns Decoded WRPRC with header and payload
|
|
849
|
+
*/
|
|
850
|
+
function decodeWRPRC(jws) {
|
|
851
|
+
const decoded = decodeJwt(jws);
|
|
852
|
+
if (decoded.header.typ !== "rc-wrp+jwt") throw new WRPRCException(`Invalid WRPRC type: expected "rc-wrp+jwt", got "${decoded.header.typ}"`);
|
|
853
|
+
assertValidWRPRCPayload(decoded.payload);
|
|
854
|
+
return {
|
|
855
|
+
jws,
|
|
856
|
+
header: decoded.header,
|
|
857
|
+
payload: decoded.payload
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Parse a WRPRC JWT without validation (for inspection purposes)
|
|
862
|
+
*
|
|
863
|
+
* @param jws - The compact JWS string
|
|
864
|
+
* @returns Decoded parts without validation
|
|
865
|
+
*/
|
|
866
|
+
function parseWRPRC(jws) {
|
|
867
|
+
const decoded = decodeJwt(jws);
|
|
868
|
+
const parts = jws.split(".");
|
|
869
|
+
return {
|
|
870
|
+
header: decoded.header,
|
|
871
|
+
payload: decoded.payload,
|
|
872
|
+
signature: parts[2]
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Create a WRPRC with automatic timestamp
|
|
877
|
+
*
|
|
878
|
+
* @param payload - Partial payload (iat will be set automatically if not provided)
|
|
879
|
+
* @returns Complete payload with timestamp
|
|
880
|
+
*/
|
|
881
|
+
function createWRPRCPayload(payload) {
|
|
882
|
+
const completePayload = {
|
|
883
|
+
...payload,
|
|
884
|
+
iat: payload.iat ?? Math.floor(Date.now() / 1e3)
|
|
885
|
+
};
|
|
886
|
+
assertValidWRPRCPayload(completePayload);
|
|
887
|
+
return completePayload;
|
|
888
|
+
}
|
|
889
|
+
//#endregion
|
|
890
|
+
export { ClaimSchema, CredentialBuilder, CredentialSchema, IDENTIFIER_TYPES, IntermediarySchema, LegalPersonSubjectSchema, MultiLangStringSchema, NaturalPersonSubjectSchema, PSP_SUB_ENTITLEMENTS, StatusSchema, SupervisoryAuthoritySchema, WRPRCBuilder, WRPRCCWTHeaderSchema, WRPRCException, WRPRCJWTHeaderSchema, WRPRCPayloadSchema, WRP_ENTITLEMENTS, assertValidWRPRC, assertValidWRPRCPayload, createLegalPersonWRPRC, createNaturalPersonWRPRC, createServiceProviderWRPRC, createWRPRCPayload, credential, decodeWRPRC, hasAttestationProviderEntitlement, isLegalPersonWRPRC, isNaturalPersonWRPRC, isPSPSubEntitlement, isValidEntitlement, parseWRPRC, signWRPRC, validateLegalPersonWRPRC, validateNaturalPersonWRPRC, validateWRPRC, validateWRPRCJWTHeader, validateWRPRCPayload, wrprc };
|
|
891
|
+
|
|
892
|
+
//# sourceMappingURL=index.mjs.map
|