@sphereon/ssi-sdk.vc-status-list 0.34.1-next.3 → 0.34.1-next.322
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.cjs +703 -125
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +164 -37
- package/dist/index.d.ts +164 -37
- package/dist/index.js +707 -129
- package/dist/index.js.map +1 -1
- package/package.json +14 -10
- package/src/functions.ts +126 -47
- package/src/impl/BitstringStatusListImplementation.ts +496 -0
- package/src/impl/IStatusList.ts +102 -8
- package/src/impl/OAuthStatusList.ts +133 -38
- package/src/impl/StatusList2021.ts +120 -34
- package/src/impl/StatusListFactory.ts +2 -0
- package/src/impl/encoding/cbor.ts +14 -12
- package/src/index.ts +1 -0
- package/src/types/BitstringStatusList.ts +4 -0
- package/src/types/index.ts +57 -34
- package/src/utils.ts +82 -20
package/dist/index.js
CHANGED
|
@@ -2,20 +2,20 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
4
|
// src/types/index.ts
|
|
5
|
-
var StatusOAuth = /* @__PURE__ */ function(StatusOAuth2) {
|
|
5
|
+
var StatusOAuth = /* @__PURE__ */ (function(StatusOAuth2) {
|
|
6
6
|
StatusOAuth2[StatusOAuth2["Valid"] = 0] = "Valid";
|
|
7
7
|
StatusOAuth2[StatusOAuth2["Invalid"] = 1] = "Invalid";
|
|
8
8
|
StatusOAuth2[StatusOAuth2["Suspended"] = 2] = "Suspended";
|
|
9
9
|
return StatusOAuth2;
|
|
10
|
-
}({});
|
|
11
|
-
var Status2021 = /* @__PURE__ */ function(Status20212) {
|
|
10
|
+
})({});
|
|
11
|
+
var Status2021 = /* @__PURE__ */ (function(Status20212) {
|
|
12
12
|
Status20212[Status20212["Valid"] = 0] = "Valid";
|
|
13
13
|
Status20212[Status20212["Invalid"] = 1] = "Invalid";
|
|
14
14
|
return Status20212;
|
|
15
|
-
}({});
|
|
15
|
+
})({});
|
|
16
16
|
|
|
17
17
|
// src/functions.ts
|
|
18
|
-
import { CredentialMapper as
|
|
18
|
+
import { CredentialMapper as CredentialMapper4, StatusListType as StatusListType6 } from "@sphereon/ssi-types";
|
|
19
19
|
import { checkStatus } from "@sphereon/vc-status-list";
|
|
20
20
|
|
|
21
21
|
// src/utils.ts
|
|
@@ -25,7 +25,8 @@ function getAssertedStatusListType(type) {
|
|
|
25
25
|
const assertedType = type ?? StatusListType.StatusList2021;
|
|
26
26
|
if (![
|
|
27
27
|
StatusListType.StatusList2021,
|
|
28
|
-
StatusListType.OAuthStatusList
|
|
28
|
+
StatusListType.OAuthStatusList,
|
|
29
|
+
StatusListType.BitstringStatusList
|
|
29
30
|
].includes(assertedType)) {
|
|
30
31
|
throw Error(`StatusList type ${assertedType} is not supported (yet)`);
|
|
31
32
|
}
|
|
@@ -62,8 +63,7 @@ var ValidProofTypeMap = /* @__PURE__ */ new Map([
|
|
|
62
63
|
StatusListType.StatusList2021,
|
|
63
64
|
[
|
|
64
65
|
"jwt",
|
|
65
|
-
"lds"
|
|
66
|
-
"EthereumEip712Signature2021"
|
|
66
|
+
"lds"
|
|
67
67
|
]
|
|
68
68
|
],
|
|
69
69
|
[
|
|
@@ -72,6 +72,13 @@ var ValidProofTypeMap = /* @__PURE__ */ new Map([
|
|
|
72
72
|
"jwt",
|
|
73
73
|
"cbor"
|
|
74
74
|
]
|
|
75
|
+
],
|
|
76
|
+
[
|
|
77
|
+
StatusListType.BitstringStatusList,
|
|
78
|
+
[
|
|
79
|
+
"lds",
|
|
80
|
+
"vc+jwt"
|
|
81
|
+
]
|
|
75
82
|
]
|
|
76
83
|
]);
|
|
77
84
|
function assertValidProofType(type, proofFormat) {
|
|
@@ -85,29 +92,50 @@ function determineStatusListType(credential) {
|
|
|
85
92
|
const proofFormat = determineProofFormat(credential);
|
|
86
93
|
switch (proofFormat) {
|
|
87
94
|
case "jwt":
|
|
88
|
-
|
|
89
|
-
const keys = Object.keys(payload);
|
|
90
|
-
if (keys.includes("status_list")) {
|
|
91
|
-
return StatusListType.OAuthStatusList;
|
|
92
|
-
} else if (keys.includes("vc")) {
|
|
93
|
-
return StatusListType.StatusList2021;
|
|
94
|
-
}
|
|
95
|
-
break;
|
|
95
|
+
return determineJwtStatusListType(credential);
|
|
96
96
|
case "lds":
|
|
97
|
-
|
|
98
|
-
const type = uniform.type.find((t) => {
|
|
99
|
-
return Object.values(StatusListType).some((statusType) => t.includes(statusType));
|
|
100
|
-
});
|
|
101
|
-
if (!type) {
|
|
102
|
-
throw new Error("Invalid status list credential type");
|
|
103
|
-
}
|
|
104
|
-
return type.replace("Credential", "");
|
|
97
|
+
return determineLdsStatusListType(credential);
|
|
105
98
|
case "cbor":
|
|
106
99
|
return StatusListType.OAuthStatusList;
|
|
100
|
+
default:
|
|
101
|
+
throw new Error("Cannot determine status list type from credential payload");
|
|
107
102
|
}
|
|
108
|
-
throw new Error("Cannot determine status list type from credential payload");
|
|
109
103
|
}
|
|
110
104
|
__name(determineStatusListType, "determineStatusListType");
|
|
105
|
+
function determineJwtStatusListType(credential) {
|
|
106
|
+
const payload = jwtDecode(credential);
|
|
107
|
+
if ("status_list" in payload) {
|
|
108
|
+
return StatusListType.OAuthStatusList;
|
|
109
|
+
}
|
|
110
|
+
if ("credentialSubject" in payload) {
|
|
111
|
+
return getStatusListTypeFromSubject(payload.credentialSubject);
|
|
112
|
+
}
|
|
113
|
+
if ("vc" in payload && "credentialSubject" in payload.vc) {
|
|
114
|
+
return getStatusListTypeFromSubject(payload.vc.credentialSubject);
|
|
115
|
+
}
|
|
116
|
+
throw new Error("Invalid status list credential: credentialSubject not found");
|
|
117
|
+
}
|
|
118
|
+
__name(determineJwtStatusListType, "determineJwtStatusListType");
|
|
119
|
+
function determineLdsStatusListType(credential) {
|
|
120
|
+
const uniform = CredentialMapper.toUniformCredential(credential);
|
|
121
|
+
const statusListType = uniform.type.find((type) => Object.values(StatusListType).some((statusType) => type.includes(statusType)));
|
|
122
|
+
if (!statusListType) {
|
|
123
|
+
throw new Error("Invalid status list credential type");
|
|
124
|
+
}
|
|
125
|
+
return statusListType.replace("Credential", "");
|
|
126
|
+
}
|
|
127
|
+
__name(determineLdsStatusListType, "determineLdsStatusListType");
|
|
128
|
+
function getStatusListTypeFromSubject(credentialSubject) {
|
|
129
|
+
switch (credentialSubject.type) {
|
|
130
|
+
case "StatusList2021":
|
|
131
|
+
return StatusListType.StatusList2021;
|
|
132
|
+
case "BitstringStatusList":
|
|
133
|
+
return StatusListType.BitstringStatusList;
|
|
134
|
+
default:
|
|
135
|
+
throw new Error(`Unknown credential subject type: ${credentialSubject.type}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
__name(getStatusListTypeFromSubject, "getStatusListTypeFromSubject");
|
|
111
139
|
function determineProofFormat(credential) {
|
|
112
140
|
const type = CredentialMapper.detectDocumentType(credential);
|
|
113
141
|
switch (type) {
|
|
@@ -122,9 +150,29 @@ function determineProofFormat(credential) {
|
|
|
122
150
|
}
|
|
123
151
|
}
|
|
124
152
|
__name(determineProofFormat, "determineProofFormat");
|
|
153
|
+
function ensureDate(value) {
|
|
154
|
+
if (value === void 0 || value === null) {
|
|
155
|
+
return void 0;
|
|
156
|
+
}
|
|
157
|
+
if (value instanceof Date) {
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
if (typeof value === "string") {
|
|
161
|
+
if (value.trim() === "") {
|
|
162
|
+
return void 0;
|
|
163
|
+
}
|
|
164
|
+
const date = new Date(value);
|
|
165
|
+
if (isNaN(date.getTime())) {
|
|
166
|
+
return void 0;
|
|
167
|
+
}
|
|
168
|
+
return date;
|
|
169
|
+
}
|
|
170
|
+
return void 0;
|
|
171
|
+
}
|
|
172
|
+
__name(ensureDate, "ensureDate");
|
|
125
173
|
|
|
126
174
|
// src/impl/StatusList2021.ts
|
|
127
|
-
import { CredentialMapper as CredentialMapper2, DocumentFormat as DocumentFormat2, StatusListType as StatusListType2 } from "@sphereon/ssi-types";
|
|
175
|
+
import { CredentialMapper as CredentialMapper2, DocumentFormat as DocumentFormat2, StatusListCredentialIdMode, StatusListType as StatusListType2 } from "@sphereon/ssi-types";
|
|
128
176
|
import { StatusList } from "@sphereon/vc-status-list";
|
|
129
177
|
var DEFAULT_LIST_LENGTH = 25e4;
|
|
130
178
|
var DEFAULT_PROOF_FORMAT = "lds";
|
|
@@ -154,7 +202,8 @@ var StatusList2021Implementation = class {
|
|
|
154
202
|
statusListCredential,
|
|
155
203
|
statusList2021: {
|
|
156
204
|
statusPurpose,
|
|
157
|
-
indexingDirection: "rightToLeft"
|
|
205
|
+
indexingDirection: "rightToLeft",
|
|
206
|
+
credentialIdMode: StatusListCredentialIdMode.ISSUANCE
|
|
158
207
|
},
|
|
159
208
|
length,
|
|
160
209
|
type: StatusListType2.StatusList2021,
|
|
@@ -185,14 +234,16 @@ var StatusList2021Implementation = class {
|
|
|
185
234
|
encodedList,
|
|
186
235
|
proofFormat
|
|
187
236
|
}, context);
|
|
237
|
+
if (!("statusPurpose" in credentialSubject)) {
|
|
238
|
+
return Promise.reject(Error("statusPurpose is required in credentialSubject for StatusList2021"));
|
|
239
|
+
}
|
|
188
240
|
return {
|
|
189
241
|
statusListCredential: updatedCredential,
|
|
190
242
|
encodedList,
|
|
191
243
|
statusList2021: {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
indexingDirection: "rightToLeft"
|
|
244
|
+
statusPurpose: credentialSubject.statusPurpose,
|
|
245
|
+
indexingDirection: "rightToLeft",
|
|
246
|
+
credentialIdMode: StatusListCredentialIdMode.ISSUANCE
|
|
196
247
|
},
|
|
197
248
|
length: statusList.length - 1,
|
|
198
249
|
type: StatusListType2.StatusList2021,
|
|
@@ -214,7 +265,7 @@ var StatusList2021Implementation = class {
|
|
|
214
265
|
encodedList: args.encodedList
|
|
215
266
|
});
|
|
216
267
|
const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
217
|
-
statusList.setStatus(index, args.value);
|
|
268
|
+
statusList.setStatus(index, args.value !== 0);
|
|
218
269
|
const newEncodedList = await statusList.encode();
|
|
219
270
|
const credential = await this.createVerifiableCredential({
|
|
220
271
|
id,
|
|
@@ -229,7 +280,8 @@ var StatusList2021Implementation = class {
|
|
|
229
280
|
encodedList: newEncodedList,
|
|
230
281
|
statusList2021: {
|
|
231
282
|
statusPurpose: args.statusList2021.statusPurpose,
|
|
232
|
-
indexingDirection: "rightToLeft"
|
|
283
|
+
indexingDirection: "rightToLeft",
|
|
284
|
+
credentialIdMode: StatusListCredentialIdMode.ISSUANCE
|
|
233
285
|
},
|
|
234
286
|
length: statusList.length,
|
|
235
287
|
proofFormat: args.proofFormat ?? "lds",
|
|
@@ -248,36 +300,90 @@ var StatusList2021Implementation = class {
|
|
|
248
300
|
const status = statusList.getStatus(typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex));
|
|
249
301
|
return status ? Status2021.Invalid : Status2021.Valid;
|
|
250
302
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
303
|
+
/**
|
|
304
|
+
* Performs the initial parsing of a StatusListCredential.
|
|
305
|
+
* This method handles expensive operations like JWT/CWT decoding once.
|
|
306
|
+
* It extracts all details available from the credential payload itself.
|
|
307
|
+
*/
|
|
308
|
+
async extractCredentialDetails(credential) {
|
|
309
|
+
const uniform = CredentialMapper2.toUniformCredential(credential);
|
|
254
310
|
const { issuer, credentialSubject } = uniform;
|
|
255
|
-
const
|
|
256
|
-
const encodedList = getAssertedProperty("encodedList", credentialSubject);
|
|
257
|
-
const proofFormat = CredentialMapper2.detectDocumentType(statusListPayload) === DocumentFormat2.JWT ? "jwt" : "lds";
|
|
258
|
-
const statusPurpose = getAssertedProperty("statusPurpose", credentialSubject);
|
|
259
|
-
const list = await StatusList.decode({
|
|
260
|
-
encodedList
|
|
261
|
-
});
|
|
311
|
+
const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
|
|
262
312
|
return {
|
|
263
|
-
id,
|
|
264
|
-
encodedList,
|
|
313
|
+
id: getAssertedValue("id", uniform.id),
|
|
265
314
|
issuer,
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
315
|
+
encodedList: getAssertedProperty("encodedList", subject)
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
async toStatusListDetails(args) {
|
|
319
|
+
if ("statusListCredential" in args) {
|
|
320
|
+
const { statusListCredential, correlationId, driverType } = args;
|
|
321
|
+
const uniform = CredentialMapper2.toUniformCredential(statusListCredential);
|
|
322
|
+
const { issuer, credentialSubject } = uniform;
|
|
323
|
+
const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
|
|
324
|
+
const id = getAssertedValue("id", uniform.id);
|
|
325
|
+
const encodedList = getAssertedProperty("encodedList", subject);
|
|
326
|
+
const statusPurpose = getAssertedProperty("statusPurpose", subject);
|
|
327
|
+
const proofFormat = CredentialMapper2.detectDocumentType(statusListCredential) === DocumentFormat2.JWT ? "jwt" : "lds";
|
|
328
|
+
const list = await StatusList.decode({
|
|
329
|
+
encodedList
|
|
330
|
+
});
|
|
331
|
+
return {
|
|
332
|
+
id,
|
|
333
|
+
encodedList,
|
|
334
|
+
issuer,
|
|
335
|
+
type: StatusListType2.StatusList2021,
|
|
336
|
+
proofFormat,
|
|
337
|
+
length: list.length,
|
|
338
|
+
statusListCredential,
|
|
339
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
340
|
+
correlationId,
|
|
341
|
+
driverType,
|
|
272
342
|
indexingDirection: "rightToLeft",
|
|
273
|
-
statusPurpose
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
343
|
+
statusPurpose,
|
|
344
|
+
statusList2021: {
|
|
345
|
+
indexingDirection: "rightToLeft",
|
|
346
|
+
statusPurpose,
|
|
347
|
+
credentialIdMode: StatusListCredentialIdMode.ISSUANCE
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
} else {
|
|
351
|
+
const { extractedDetails, statusListEntity } = args;
|
|
352
|
+
const statusList2021Entity = statusListEntity;
|
|
353
|
+
const proofFormat = CredentialMapper2.detectDocumentType(statusListEntity.statusListCredential) === DocumentFormat2.JWT ? "jwt" : "lds";
|
|
354
|
+
const list = await StatusList.decode({
|
|
355
|
+
encodedList: extractedDetails.encodedList
|
|
356
|
+
});
|
|
357
|
+
return {
|
|
358
|
+
id: extractedDetails.id,
|
|
359
|
+
encodedList: extractedDetails.encodedList,
|
|
360
|
+
issuer: extractedDetails.issuer,
|
|
361
|
+
type: StatusListType2.StatusList2021,
|
|
362
|
+
proofFormat,
|
|
363
|
+
length: list.length,
|
|
364
|
+
statusListCredential: statusListEntity.statusListCredential,
|
|
365
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
366
|
+
correlationId: statusListEntity.correlationId,
|
|
367
|
+
driverType: statusListEntity.driverType,
|
|
368
|
+
indexingDirection: statusList2021Entity.indexingDirection,
|
|
369
|
+
statusPurpose: statusList2021Entity.statusPurpose,
|
|
370
|
+
statusList2021: {
|
|
371
|
+
indexingDirection: statusList2021Entity.indexingDirection,
|
|
372
|
+
statusPurpose: statusList2021Entity.statusPurpose,
|
|
373
|
+
credentialIdMode: StatusListCredentialIdMode.ISSUANCE
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async createCredentialStatus(args) {
|
|
379
|
+
const { statusList, statusListIndex } = args;
|
|
380
|
+
const statusList2021 = statusList;
|
|
381
|
+
return {
|
|
382
|
+
id: `${statusList.id}#${statusListIndex}`,
|
|
383
|
+
type: "StatusList2021Entry",
|
|
384
|
+
statusPurpose: statusList2021.statusPurpose ?? "revocation",
|
|
385
|
+
statusListIndex: "" + statusListIndex,
|
|
386
|
+
statusListCredential: statusList.id
|
|
281
387
|
};
|
|
282
388
|
}
|
|
283
389
|
async createVerifiableCredential(args, context) {
|
|
@@ -413,12 +519,12 @@ var getSigningAlgo = /* @__PURE__ */ __name((type) => {
|
|
|
413
519
|
// src/impl/encoding/cbor.ts
|
|
414
520
|
import { StatusList as StatusList3 } from "@sd-jwt/jwt-status-list";
|
|
415
521
|
import { deflate, inflate } from "pako";
|
|
416
|
-
import
|
|
522
|
+
import mdocPkg from "@sphereon/kmp-mdoc-core";
|
|
417
523
|
import base64url2 from "base64url";
|
|
418
|
-
var { com, kotlin } =
|
|
419
|
-
var CborByteString = com.sphereon.cbor.CborByteString;
|
|
420
|
-
var CborUInt = com.sphereon.cbor.CborUInt;
|
|
421
|
-
var CborString = com.sphereon.cbor.CborString;
|
|
524
|
+
var { com, kotlin } = mdocPkg;
|
|
525
|
+
var CborByteString = mdocPkg.com.sphereon.cbor.CborByteString;
|
|
526
|
+
var CborUInt = mdocPkg.com.sphereon.cbor.CborUInt;
|
|
527
|
+
var CborString = mdocPkg.com.sphereon.cbor.CborString;
|
|
422
528
|
var decompressRawStatusList = StatusList3.decodeStatusList.bind(StatusList3);
|
|
423
529
|
var CWT_CLAIMS = {
|
|
424
530
|
SUBJECT: 2,
|
|
@@ -572,7 +678,8 @@ var OAuthStatusListImplementation = class {
|
|
|
572
678
|
}
|
|
573
679
|
const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT2;
|
|
574
680
|
const { issuer, id, oauthStatusList, keyRef } = args;
|
|
575
|
-
const { bitsPerStatus
|
|
681
|
+
const { bitsPerStatus } = oauthStatusList;
|
|
682
|
+
const expiresAt = ensureDate(oauthStatusList.expiresAt);
|
|
576
683
|
const length = args.length ?? DEFAULT_LIST_LENGTH2;
|
|
577
684
|
const issuerString = typeof issuer === "string" ? issuer : issuer.id;
|
|
578
685
|
const correlationId = getAssertedValue("correlationId", args.correlationId);
|
|
@@ -595,7 +702,8 @@ var OAuthStatusListImplementation = class {
|
|
|
595
702
|
};
|
|
596
703
|
}
|
|
597
704
|
async updateStatusListIndex(args, context) {
|
|
598
|
-
const { statusListCredential, value,
|
|
705
|
+
const { statusListCredential, value, keyRef } = args;
|
|
706
|
+
const expiresAt = ensureDate(args.expiresAt);
|
|
599
707
|
if (typeof statusListCredential !== "string") {
|
|
600
708
|
return Promise.reject("statusListCredential in neither JWT nor CWT");
|
|
601
709
|
}
|
|
@@ -606,6 +714,9 @@ var OAuthStatusListImplementation = class {
|
|
|
606
714
|
if (index < 0 || index >= statusList.statusList.length) {
|
|
607
715
|
throw new Error("Status list index out of bounds");
|
|
608
716
|
}
|
|
717
|
+
if (typeof value !== "number") {
|
|
718
|
+
throw new Error("Status list values should be of type number");
|
|
719
|
+
}
|
|
609
720
|
statusList.setStatus(index, value);
|
|
610
721
|
const { statusListCredential: signedCredential, encodedList } = await this.createSignedStatusList(proofFormat, context, statusList, issuer, id, expiresAt, keyRef);
|
|
611
722
|
return {
|
|
@@ -628,12 +739,13 @@ var OAuthStatusListImplementation = class {
|
|
|
628
739
|
throw new Error("OAuthStatusList options are required for type OAuthStatusList");
|
|
629
740
|
}
|
|
630
741
|
const { proofFormat, oauthStatusList, keyRef } = args;
|
|
631
|
-
const { bitsPerStatus
|
|
742
|
+
const { bitsPerStatus } = oauthStatusList;
|
|
743
|
+
const expiresAt = ensureDate(oauthStatusList.expiresAt);
|
|
632
744
|
const { issuer, id } = getAssertedValues(args);
|
|
633
745
|
const issuerString = typeof issuer === "string" ? issuer : issuer.id;
|
|
634
746
|
const listToUpdate = StatusList4.decompressStatusList(args.encodedList, bitsPerStatus ?? DEFAULT_BITS_PER_STATUS);
|
|
635
747
|
const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
636
|
-
listToUpdate.setStatus(index, args.value
|
|
748
|
+
listToUpdate.setStatus(index, args.value);
|
|
637
749
|
const { statusListCredential, encodedList } = await this.createSignedStatusList(proofFormat ?? DEFAULT_PROOF_FORMAT2, context, listToUpdate, issuerString, id, expiresAt, keyRef);
|
|
638
750
|
return {
|
|
639
751
|
encodedList,
|
|
@@ -650,9 +762,6 @@ var OAuthStatusListImplementation = class {
|
|
|
650
762
|
statuslistContentType: this.buildContentType(proofFormat)
|
|
651
763
|
};
|
|
652
764
|
}
|
|
653
|
-
buildContentType(proofFormat) {
|
|
654
|
-
return `application/statuslist+${proofFormat === "cbor" ? "cwt" : "jwt"}`;
|
|
655
|
-
}
|
|
656
765
|
async checkStatusIndex(args) {
|
|
657
766
|
const { statusListCredential, statusListIndex } = args;
|
|
658
767
|
if (typeof statusListCredential !== "string") {
|
|
@@ -662,38 +771,105 @@ var OAuthStatusListImplementation = class {
|
|
|
662
771
|
const { statusList } = proofFormat === "jwt" ? decodeStatusListJWT(statusListCredential) : decodeStatusListCWT(statusListCredential);
|
|
663
772
|
const index = typeof statusListIndex === "number" ? statusListIndex : parseInt(statusListIndex);
|
|
664
773
|
if (index < 0 || index >= statusList.statusList.length) {
|
|
665
|
-
throw new Error(
|
|
774
|
+
throw new Error(`Status list index out of bounds, has ${statusList.statusList.length} items, requested ${index}`);
|
|
666
775
|
}
|
|
667
776
|
return statusList.getStatus(index);
|
|
668
777
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
778
|
+
/**
|
|
779
|
+
* Performs the initial parsing of a StatusListCredential.
|
|
780
|
+
* This method handles expensive operations like JWT/CWT decoding once.
|
|
781
|
+
* It extracts all details available from the credential payload itself.
|
|
782
|
+
*/
|
|
783
|
+
async extractCredentialDetails(credential) {
|
|
784
|
+
if (typeof credential !== "string") {
|
|
785
|
+
return Promise.reject("statusListCredential must be a JWT or CWT string");
|
|
786
|
+
}
|
|
787
|
+
const proofFormat = determineProofFormat(credential);
|
|
788
|
+
const decoded = proofFormat === "jwt" ? decodeStatusListJWT(credential) : decodeStatusListCWT(credential);
|
|
674
789
|
return {
|
|
675
|
-
id,
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
expiresAt: new Date(exp * 1e3)
|
|
687
|
-
}
|
|
688
|
-
},
|
|
689
|
-
...args.correlationId && {
|
|
690
|
-
correlationId: args.correlationId
|
|
691
|
-
},
|
|
692
|
-
...args.driverType && {
|
|
693
|
-
driverType: args.driverType
|
|
790
|
+
id: decoded.id,
|
|
791
|
+
issuer: decoded.issuer,
|
|
792
|
+
encodedList: decoded.statusList.compressStatusList(),
|
|
793
|
+
decodedPayload: decoded
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
async toStatusListDetails(args) {
|
|
797
|
+
if ("statusListCredential" in args) {
|
|
798
|
+
const { statusListCredential, bitsPerStatus, correlationId, driverType } = args;
|
|
799
|
+
if (!bitsPerStatus || bitsPerStatus < 1) {
|
|
800
|
+
return Promise.reject(Error("bitsPerStatus must be set for OAuth status lists and must be 1 or higher"));
|
|
694
801
|
}
|
|
802
|
+
const proofFormat = determineProofFormat(statusListCredential);
|
|
803
|
+
const decoded = proofFormat === "jwt" ? decodeStatusListJWT(statusListCredential) : decodeStatusListCWT(statusListCredential);
|
|
804
|
+
const { statusList, issuer, id, exp } = decoded;
|
|
805
|
+
const expiresAt = exp ? new Date(exp * 1e3) : void 0;
|
|
806
|
+
return {
|
|
807
|
+
id,
|
|
808
|
+
encodedList: statusList.compressStatusList(),
|
|
809
|
+
issuer,
|
|
810
|
+
type: StatusListType3.OAuthStatusList,
|
|
811
|
+
proofFormat,
|
|
812
|
+
length: statusList.statusList.length,
|
|
813
|
+
statusListCredential,
|
|
814
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
815
|
+
correlationId,
|
|
816
|
+
driverType,
|
|
817
|
+
bitsPerStatus,
|
|
818
|
+
...expiresAt && {
|
|
819
|
+
expiresAt
|
|
820
|
+
},
|
|
821
|
+
oauthStatusList: {
|
|
822
|
+
bitsPerStatus,
|
|
823
|
+
...expiresAt && {
|
|
824
|
+
expiresAt
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
} else {
|
|
829
|
+
const { extractedDetails, statusListEntity } = args;
|
|
830
|
+
const oauthEntity = statusListEntity;
|
|
831
|
+
const decoded = extractedDetails.decodedPayload;
|
|
832
|
+
const proofFormat = determineProofFormat(statusListEntity.statusListCredential);
|
|
833
|
+
const expiresAt = decoded.exp ? new Date(decoded.exp * 1e3) : void 0;
|
|
834
|
+
return {
|
|
835
|
+
id: extractedDetails.id,
|
|
836
|
+
encodedList: extractedDetails.encodedList,
|
|
837
|
+
issuer: extractedDetails.issuer,
|
|
838
|
+
type: StatusListType3.OAuthStatusList,
|
|
839
|
+
proofFormat,
|
|
840
|
+
length: decoded.statusList.statusList.length,
|
|
841
|
+
statusListCredential: statusListEntity.statusListCredential,
|
|
842
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
843
|
+
correlationId: statusListEntity.correlationId,
|
|
844
|
+
driverType: statusListEntity.driverType,
|
|
845
|
+
bitsPerStatus: oauthEntity.bitsPerStatus,
|
|
846
|
+
...expiresAt && {
|
|
847
|
+
expiresAt
|
|
848
|
+
},
|
|
849
|
+
oauthStatusList: {
|
|
850
|
+
bitsPerStatus: oauthEntity.bitsPerStatus,
|
|
851
|
+
...expiresAt && {
|
|
852
|
+
expiresAt
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
async createCredentialStatus(args) {
|
|
859
|
+
const { statusList, statusListIndex } = args;
|
|
860
|
+
const oauthStatusList = statusList;
|
|
861
|
+
return {
|
|
862
|
+
id: `${statusList.id}#${statusListIndex}`,
|
|
863
|
+
type: "OAuthStatusListEntry",
|
|
864
|
+
bitsPerStatus: oauthStatusList.bitsPerStatus,
|
|
865
|
+
statusListIndex: "" + statusListIndex,
|
|
866
|
+
statusListCredential: statusList.id,
|
|
867
|
+
expiresAt: oauthStatusList.expiresAt
|
|
695
868
|
};
|
|
696
869
|
}
|
|
870
|
+
buildContentType(proofFormat) {
|
|
871
|
+
return `application/statuslist+${proofFormat === "cbor" ? "cwt" : "jwt"}`;
|
|
872
|
+
}
|
|
697
873
|
async createSignedStatusList(proofFormat, context, statusList, issuerString, id, expiresAt, keyRef) {
|
|
698
874
|
switch (proofFormat) {
|
|
699
875
|
case "jwt": {
|
|
@@ -709,7 +885,405 @@ var OAuthStatusListImplementation = class {
|
|
|
709
885
|
};
|
|
710
886
|
|
|
711
887
|
// src/impl/StatusListFactory.ts
|
|
712
|
-
import { StatusListType as
|
|
888
|
+
import { StatusListType as StatusListType5 } from "@sphereon/ssi-types";
|
|
889
|
+
|
|
890
|
+
// src/impl/BitstringStatusListImplementation.ts
|
|
891
|
+
import { CredentialMapper as CredentialMapper3, DocumentFormat as DocumentFormat3, StatusListType as StatusListType4 } from "@sphereon/ssi-types";
|
|
892
|
+
import { BitstreamStatusList, createStatusListCredential } from "@4sure-tech/vc-bitstring-status-lists";
|
|
893
|
+
var DEFAULT_LIST_LENGTH3 = 131072;
|
|
894
|
+
var DEFAULT_PROOF_FORMAT3 = "vc+jwt";
|
|
895
|
+
var DEFAULT_STATUS_PURPOSE = "revocation";
|
|
896
|
+
var BitstringStatusListImplementation = class {
|
|
897
|
+
static {
|
|
898
|
+
__name(this, "BitstringStatusListImplementation");
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Creates a new bitstring status list with the specified configuration
|
|
902
|
+
*
|
|
903
|
+
* @param args - Configuration for the new status list including issuer, purpose, and size
|
|
904
|
+
* @param context - Veramo agent context for credential operations
|
|
905
|
+
* @returns Promise resolving to the created status list details
|
|
906
|
+
*/
|
|
907
|
+
async createNewStatusList(args, context) {
|
|
908
|
+
if (!args.bitstringStatusList) {
|
|
909
|
+
throw new Error("BitstringStatusList options are required for type BitstringStatusList");
|
|
910
|
+
}
|
|
911
|
+
const length = args?.length ?? DEFAULT_LIST_LENGTH3;
|
|
912
|
+
const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT3;
|
|
913
|
+
assertValidProofType(StatusListType4.BitstringStatusList, proofFormat);
|
|
914
|
+
const { issuer, id } = args;
|
|
915
|
+
const correlationId = getAssertedValue("correlationId", args.correlationId);
|
|
916
|
+
const { statusPurpose, bitsPerStatus, validFrom, validUntil, ttl } = args.bitstringStatusList;
|
|
917
|
+
const unsignedCredential = await createStatusListCredential({
|
|
918
|
+
id,
|
|
919
|
+
issuer,
|
|
920
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
921
|
+
validFrom: ensureDate(validFrom),
|
|
922
|
+
validUntil: ensureDate(validUntil),
|
|
923
|
+
ttl
|
|
924
|
+
});
|
|
925
|
+
const statusListCredential = await this.createVerifiableCredential({
|
|
926
|
+
unsignedCredential,
|
|
927
|
+
id,
|
|
928
|
+
issuer,
|
|
929
|
+
proofFormat,
|
|
930
|
+
keyRef: args.keyRef
|
|
931
|
+
}, context);
|
|
932
|
+
return {
|
|
933
|
+
encodedList: unsignedCredential.credentialSubject.encodedList,
|
|
934
|
+
statusListCredential,
|
|
935
|
+
bitstringStatusList: {
|
|
936
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
937
|
+
...unsignedCredential.validFrom && {
|
|
938
|
+
validFrom: new Date(unsignedCredential.validFrom)
|
|
939
|
+
},
|
|
940
|
+
...unsignedCredential.validUntil && {
|
|
941
|
+
validUntil: new Date(unsignedCredential.validUntil)
|
|
942
|
+
},
|
|
943
|
+
ttl,
|
|
944
|
+
bitsPerStatus
|
|
945
|
+
},
|
|
946
|
+
length,
|
|
947
|
+
type: StatusListType4.BitstringStatusList,
|
|
948
|
+
proofFormat,
|
|
949
|
+
id,
|
|
950
|
+
correlationId,
|
|
951
|
+
issuer,
|
|
952
|
+
statuslistContentType: this.buildContentType(proofFormat)
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Updates the status of a specific credential in an existing status list
|
|
957
|
+
*
|
|
958
|
+
* @param args - Update parameters including the status list credential, index, and new value
|
|
959
|
+
* @param context - Veramo agent context for credential operations
|
|
960
|
+
* @returns Promise resolving to the updated status list details
|
|
961
|
+
*/
|
|
962
|
+
async updateStatusListIndex(args, context) {
|
|
963
|
+
if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
|
|
964
|
+
return Promise.reject(Error("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListIndex)"));
|
|
965
|
+
}
|
|
966
|
+
const credential = args.statusListCredential;
|
|
967
|
+
const uniform = CredentialMapper3.toUniformCredential(credential);
|
|
968
|
+
const { issuer, credentialSubject } = uniform;
|
|
969
|
+
const id = getAssertedValue("id", uniform.id);
|
|
970
|
+
const origEncodedList = getAssertedProperty("encodedList", credentialSubject);
|
|
971
|
+
const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
972
|
+
const statusList = await BitstreamStatusList.decode({
|
|
973
|
+
encodedList: origEncodedList,
|
|
974
|
+
statusSize: args.bitsPerStatus
|
|
975
|
+
});
|
|
976
|
+
const bitstringStatusId = args.value;
|
|
977
|
+
statusList.setStatus(index, bitstringStatusId);
|
|
978
|
+
const proofFormat = CredentialMapper3.detectDocumentType(credential) === DocumentFormat3.JWT ? "vc+jwt" : "lds";
|
|
979
|
+
const credSubject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
|
|
980
|
+
const statusPurpose = getAssertedProperty("statusPurpose", credSubject);
|
|
981
|
+
const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : void 0;
|
|
982
|
+
const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : void 0;
|
|
983
|
+
const ttl = credSubject.ttl;
|
|
984
|
+
const unsignedCredential = await createStatusListCredential({
|
|
985
|
+
id,
|
|
986
|
+
issuer,
|
|
987
|
+
statusList,
|
|
988
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
989
|
+
validFrom: ensureDate(validFrom),
|
|
990
|
+
validUntil: ensureDate(validUntil),
|
|
991
|
+
ttl
|
|
992
|
+
});
|
|
993
|
+
const updatedCredential = await this.createVerifiableCredential({
|
|
994
|
+
unsignedCredential,
|
|
995
|
+
id,
|
|
996
|
+
issuer,
|
|
997
|
+
proofFormat,
|
|
998
|
+
keyRef: args.keyRef
|
|
999
|
+
}, context);
|
|
1000
|
+
return {
|
|
1001
|
+
statusListCredential: updatedCredential,
|
|
1002
|
+
encodedList: unsignedCredential.credentialSubject.encodedList,
|
|
1003
|
+
bitstringStatusList: {
|
|
1004
|
+
statusPurpose,
|
|
1005
|
+
...unsignedCredential.validFrom && {
|
|
1006
|
+
validFrom: new Date(unsignedCredential.validFrom)
|
|
1007
|
+
},
|
|
1008
|
+
...unsignedCredential.validUntil && {
|
|
1009
|
+
validUntil: new Date(unsignedCredential.validUntil)
|
|
1010
|
+
},
|
|
1011
|
+
bitsPerStatus: args.bitsPerStatus,
|
|
1012
|
+
ttl
|
|
1013
|
+
},
|
|
1014
|
+
length: statusList.getLength(),
|
|
1015
|
+
type: StatusListType4.BitstringStatusList,
|
|
1016
|
+
proofFormat,
|
|
1017
|
+
id,
|
|
1018
|
+
issuer,
|
|
1019
|
+
statuslistContentType: this.buildContentType(proofFormat)
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Updates a status list by decoding an encoded list, modifying it, and re-encoding
|
|
1024
|
+
*
|
|
1025
|
+
* @param args - Update parameters including encoded list, index, and new value
|
|
1026
|
+
* @param context - Veramo agent context for credential operations
|
|
1027
|
+
* @returns Promise resolving to the updated status list details
|
|
1028
|
+
*/
|
|
1029
|
+
async updateStatusListFromEncodedList(args, context) {
|
|
1030
|
+
if (!args.bitstringStatusList) {
|
|
1031
|
+
throw new Error("bitstringStatusList options required for type BitstringStatusList");
|
|
1032
|
+
}
|
|
1033
|
+
if (args.bitstringStatusList.bitsPerStatus < 1) {
|
|
1034
|
+
return Promise.reject(Error("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListFromEncodedList)"));
|
|
1035
|
+
}
|
|
1036
|
+
const { statusPurpose, bitsPerStatus, ttl, validFrom, validUntil } = args.bitstringStatusList;
|
|
1037
|
+
const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT3;
|
|
1038
|
+
assertValidProofType(StatusListType4.BitstringStatusList, proofFormat);
|
|
1039
|
+
const { issuer, id } = getAssertedValues(args);
|
|
1040
|
+
const statusList = await BitstreamStatusList.decode({
|
|
1041
|
+
encodedList: args.encodedList,
|
|
1042
|
+
statusSize: bitsPerStatus
|
|
1043
|
+
});
|
|
1044
|
+
const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
1045
|
+
statusList.setStatus(index, args.value);
|
|
1046
|
+
const unsignedCredential = await createStatusListCredential({
|
|
1047
|
+
id,
|
|
1048
|
+
issuer,
|
|
1049
|
+
statusList,
|
|
1050
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
1051
|
+
validFrom: ensureDate(validFrom),
|
|
1052
|
+
validUntil: ensureDate(validUntil),
|
|
1053
|
+
ttl
|
|
1054
|
+
});
|
|
1055
|
+
const credential = await this.createVerifiableCredential({
|
|
1056
|
+
unsignedCredential,
|
|
1057
|
+
id,
|
|
1058
|
+
issuer,
|
|
1059
|
+
proofFormat,
|
|
1060
|
+
keyRef: args.keyRef
|
|
1061
|
+
}, context);
|
|
1062
|
+
return {
|
|
1063
|
+
type: StatusListType4.BitstringStatusList,
|
|
1064
|
+
statusListCredential: credential,
|
|
1065
|
+
encodedList: unsignedCredential.credentialSubject.encodedList,
|
|
1066
|
+
bitstringStatusList: {
|
|
1067
|
+
statusPurpose,
|
|
1068
|
+
bitsPerStatus,
|
|
1069
|
+
...unsignedCredential.validFrom && {
|
|
1070
|
+
validFrom: new Date(unsignedCredential.validFrom)
|
|
1071
|
+
},
|
|
1072
|
+
...unsignedCredential.validUntil && {
|
|
1073
|
+
validUntil: new Date(unsignedCredential.validUntil)
|
|
1074
|
+
},
|
|
1075
|
+
ttl
|
|
1076
|
+
},
|
|
1077
|
+
length: statusList.getLength(),
|
|
1078
|
+
proofFormat: args.proofFormat ?? "lds",
|
|
1079
|
+
id,
|
|
1080
|
+
issuer,
|
|
1081
|
+
statuslistContentType: this.buildContentType(proofFormat)
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Checks the status of a specific credential by its index in the status list
|
|
1086
|
+
*
|
|
1087
|
+
* @param args - Check parameters including the status list credential and index
|
|
1088
|
+
* @returns Promise resolving to the status value at the specified index
|
|
1089
|
+
*/
|
|
1090
|
+
async checkStatusIndex(args) {
|
|
1091
|
+
if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
|
|
1092
|
+
return Promise.reject(Error("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (checkStatusIndex)"));
|
|
1093
|
+
}
|
|
1094
|
+
const uniform = CredentialMapper3.toUniformCredential(args.statusListCredential);
|
|
1095
|
+
const { credentialSubject } = uniform;
|
|
1096
|
+
const encodedList = getAssertedProperty("encodedList", credentialSubject);
|
|
1097
|
+
const statusList = await BitstreamStatusList.decode({
|
|
1098
|
+
encodedList,
|
|
1099
|
+
statusSize: args.bitsPerStatus
|
|
1100
|
+
});
|
|
1101
|
+
const numIndex = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
1102
|
+
if (statusList.getLength() <= numIndex) {
|
|
1103
|
+
throw new Error(`Status list index out of bounds, has ${statusList.getLength()} entries, requested ${numIndex}`);
|
|
1104
|
+
}
|
|
1105
|
+
return statusList.getStatus(numIndex);
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Performs the initial parsing of a StatusListCredential.
|
|
1109
|
+
* This method handles expensive operations like JWT/CWT decoding once.
|
|
1110
|
+
* It extracts all details available from the credential payload itself.
|
|
1111
|
+
*/
|
|
1112
|
+
async extractCredentialDetails(credential) {
|
|
1113
|
+
const uniform = CredentialMapper3.toUniformCredential(credential);
|
|
1114
|
+
const { issuer, credentialSubject } = uniform;
|
|
1115
|
+
const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
|
|
1116
|
+
return {
|
|
1117
|
+
id: getAssertedValue("id", uniform.id),
|
|
1118
|
+
issuer,
|
|
1119
|
+
encodedList: getAssertedProperty("encodedList", subject)
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
async toStatusListDetails(args) {
|
|
1123
|
+
if ("statusListCredential" in args) {
|
|
1124
|
+
const { statusListCredential, bitsPerStatus, correlationId, driverType } = args;
|
|
1125
|
+
if (!bitsPerStatus || bitsPerStatus < 1) {
|
|
1126
|
+
return Promise.reject(Error("bitsPerStatus must be set for bitstring status lists and must be 1 or higher"));
|
|
1127
|
+
}
|
|
1128
|
+
const uniform = CredentialMapper3.toUniformCredential(statusListCredential);
|
|
1129
|
+
const { issuer, credentialSubject } = uniform;
|
|
1130
|
+
const subject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
|
|
1131
|
+
const id = getAssertedValue("id", uniform.id);
|
|
1132
|
+
const encodedList = getAssertedProperty("encodedList", subject);
|
|
1133
|
+
const statusPurpose = getAssertedProperty("statusPurpose", subject);
|
|
1134
|
+
const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : void 0;
|
|
1135
|
+
const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : void 0;
|
|
1136
|
+
const ttl = subject.ttl;
|
|
1137
|
+
const proofFormat = CredentialMapper3.detectDocumentType(statusListCredential) === DocumentFormat3.JWT ? "vc+jwt" : "lds";
|
|
1138
|
+
const statuslistLength = BitstreamStatusList.getStatusListLength(encodedList, bitsPerStatus);
|
|
1139
|
+
return {
|
|
1140
|
+
id,
|
|
1141
|
+
encodedList,
|
|
1142
|
+
issuer,
|
|
1143
|
+
type: StatusListType4.BitstringStatusList,
|
|
1144
|
+
proofFormat,
|
|
1145
|
+
length: statuslistLength,
|
|
1146
|
+
statusListCredential,
|
|
1147
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
1148
|
+
correlationId,
|
|
1149
|
+
driverType,
|
|
1150
|
+
statusPurpose,
|
|
1151
|
+
bitsPerStatus,
|
|
1152
|
+
...validFrom && {
|
|
1153
|
+
validFrom
|
|
1154
|
+
},
|
|
1155
|
+
...validUntil && {
|
|
1156
|
+
validUntil
|
|
1157
|
+
},
|
|
1158
|
+
...ttl && {
|
|
1159
|
+
ttl
|
|
1160
|
+
},
|
|
1161
|
+
bitstringStatusList: {
|
|
1162
|
+
statusPurpose,
|
|
1163
|
+
bitsPerStatus,
|
|
1164
|
+
...validFrom && {
|
|
1165
|
+
validFrom
|
|
1166
|
+
},
|
|
1167
|
+
...validUntil && {
|
|
1168
|
+
validUntil
|
|
1169
|
+
},
|
|
1170
|
+
...ttl && {
|
|
1171
|
+
ttl
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
} else {
|
|
1176
|
+
const { extractedDetails, statusListEntity } = args;
|
|
1177
|
+
const bitstringEntity = statusListEntity;
|
|
1178
|
+
if (!bitstringEntity.bitsPerStatus) {
|
|
1179
|
+
return Promise.reject(Error("bitsPerStatus must be present for a bitstring status list"));
|
|
1180
|
+
}
|
|
1181
|
+
const proofFormat = CredentialMapper3.detectDocumentType(statusListEntity.statusListCredential) === DocumentFormat3.JWT ? "vc+jwt" : "lds";
|
|
1182
|
+
const statuslistLength = BitstreamStatusList.getStatusListLength(extractedDetails.encodedList, bitstringEntity.bitsPerStatus);
|
|
1183
|
+
return {
|
|
1184
|
+
id: extractedDetails.id,
|
|
1185
|
+
encodedList: extractedDetails.encodedList,
|
|
1186
|
+
issuer: extractedDetails.issuer,
|
|
1187
|
+
type: StatusListType4.BitstringStatusList,
|
|
1188
|
+
proofFormat,
|
|
1189
|
+
length: statuslistLength,
|
|
1190
|
+
statusListCredential: statusListEntity.statusListCredential,
|
|
1191
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
1192
|
+
correlationId: statusListEntity.correlationId,
|
|
1193
|
+
driverType: statusListEntity.driverType,
|
|
1194
|
+
statusPurpose: bitstringEntity.statusPurpose,
|
|
1195
|
+
bitsPerStatus: bitstringEntity.bitsPerStatus,
|
|
1196
|
+
...bitstringEntity.validFrom && {
|
|
1197
|
+
validFrom: bitstringEntity.validFrom
|
|
1198
|
+
},
|
|
1199
|
+
...bitstringEntity.validUntil && {
|
|
1200
|
+
validUntil: bitstringEntity.validUntil
|
|
1201
|
+
},
|
|
1202
|
+
...bitstringEntity.ttl && {
|
|
1203
|
+
ttl: bitstringEntity.ttl
|
|
1204
|
+
},
|
|
1205
|
+
bitstringStatusList: {
|
|
1206
|
+
statusPurpose: bitstringEntity.statusPurpose,
|
|
1207
|
+
bitsPerStatus: bitstringEntity.bitsPerStatus,
|
|
1208
|
+
...bitstringEntity.validFrom && {
|
|
1209
|
+
validFrom: bitstringEntity.validFrom
|
|
1210
|
+
},
|
|
1211
|
+
...bitstringEntity.validUntil && {
|
|
1212
|
+
validUntil: bitstringEntity.validUntil
|
|
1213
|
+
},
|
|
1214
|
+
...bitstringEntity.ttl && {
|
|
1215
|
+
ttl: bitstringEntity.ttl
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Creates a credential status entry for a specific credential in a status list
|
|
1223
|
+
*
|
|
1224
|
+
* @param args - Parameters including the status list, entry details, and index
|
|
1225
|
+
* @returns Promise resolving to the credential status entry
|
|
1226
|
+
*/
|
|
1227
|
+
async createCredentialStatus(args) {
|
|
1228
|
+
const { statusList, statusListEntry, statusListIndex } = args;
|
|
1229
|
+
const bitstringStatusList = statusList;
|
|
1230
|
+
const bitstringStatusListEntry = statusListEntry;
|
|
1231
|
+
return {
|
|
1232
|
+
id: `${statusList.id}#${statusListIndex}`,
|
|
1233
|
+
type: "BitstringStatusListEntry",
|
|
1234
|
+
statusPurpose: bitstringStatusListEntry.statusPurpose,
|
|
1235
|
+
statusListIndex: "" + statusListIndex,
|
|
1236
|
+
statusListCredential: statusList.id,
|
|
1237
|
+
bitsPerStatus: bitstringStatusList.bitsPerStatus,
|
|
1238
|
+
statusMessage: bitstringStatusListEntry.statusMessage,
|
|
1239
|
+
statusReference: bitstringStatusListEntry.statusReference
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Creates a signed verifiable credential from an unsigned status list credential
|
|
1244
|
+
*
|
|
1245
|
+
* @param args - Parameters including the unsigned credential and signing details
|
|
1246
|
+
* @param context - Veramo agent context for credential operations
|
|
1247
|
+
* @returns Promise resolving to the signed credential
|
|
1248
|
+
*/
|
|
1249
|
+
async createVerifiableCredential(args, context) {
|
|
1250
|
+
const { unsignedCredential, issuer, proofFormat, keyRef } = args;
|
|
1251
|
+
const identifier = await context.agent.identifierManagedGet({
|
|
1252
|
+
identifier: typeof issuer === "string" ? issuer : issuer.id,
|
|
1253
|
+
vmRelationship: "assertionMethod",
|
|
1254
|
+
offlineWhenNoDIDRegistered: true
|
|
1255
|
+
});
|
|
1256
|
+
const verifiableCredential = await context.agent.createVerifiableCredential({
|
|
1257
|
+
credential: unsignedCredential,
|
|
1258
|
+
keyRef: keyRef ?? identifier.kmsKeyRef,
|
|
1259
|
+
proofFormat,
|
|
1260
|
+
fetchRemoteContexts: true
|
|
1261
|
+
});
|
|
1262
|
+
return CredentialMapper3.toWrappedVerifiableCredential(verifiableCredential).original;
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Builds the appropriate content type string for a given proof format
|
|
1266
|
+
*
|
|
1267
|
+
* @param proofFormat - The proof format to build content type for
|
|
1268
|
+
* @returns The corresponding content type string
|
|
1269
|
+
*/
|
|
1270
|
+
buildContentType(proofFormat) {
|
|
1271
|
+
switch (proofFormat) {
|
|
1272
|
+
case "jwt":
|
|
1273
|
+
return "application/statuslist+jwt";
|
|
1274
|
+
case "cbor":
|
|
1275
|
+
return "application/statuslist+cwt";
|
|
1276
|
+
case "vc+jwt":
|
|
1277
|
+
return "application/statuslist+vc+jwt";
|
|
1278
|
+
case "lds":
|
|
1279
|
+
return "application/statuslist+ld+json";
|
|
1280
|
+
default:
|
|
1281
|
+
throw Error(`Unsupported content type '${proofFormat}' for status lists`);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
|
|
1286
|
+
// src/impl/StatusListFactory.ts
|
|
713
1287
|
var StatusListFactory = class _StatusListFactory {
|
|
714
1288
|
static {
|
|
715
1289
|
__name(this, "StatusListFactory");
|
|
@@ -718,8 +1292,9 @@ var StatusListFactory = class _StatusListFactory {
|
|
|
718
1292
|
implementations;
|
|
719
1293
|
constructor() {
|
|
720
1294
|
this.implementations = /* @__PURE__ */ new Map();
|
|
721
|
-
this.implementations.set(
|
|
722
|
-
this.implementations.set(
|
|
1295
|
+
this.implementations.set(StatusListType5.StatusList2021, new StatusList2021Implementation());
|
|
1296
|
+
this.implementations.set(StatusListType5.OAuthStatusList, new OAuthStatusListImplementation());
|
|
1297
|
+
this.implementations.set(StatusListType5.BitstringStatusList, new BitstringStatusListImplementation());
|
|
723
1298
|
}
|
|
724
1299
|
static getInstance() {
|
|
725
1300
|
if (!_StatusListFactory.instance) {
|
|
@@ -792,7 +1367,7 @@ __name(vcLibCheckStatusFunction, "vcLibCheckStatusFunction");
|
|
|
792
1367
|
async function checkStatusForCredential(args) {
|
|
793
1368
|
const verifyStatusListCredential = args.verifyStatusListCredential ?? true;
|
|
794
1369
|
const verifyMatchingIssuers = args.verifyMatchingIssuers ?? true;
|
|
795
|
-
const uniform =
|
|
1370
|
+
const uniform = CredentialMapper4.toUniformCredential(args.credential);
|
|
796
1371
|
if (!("credentialStatus" in uniform) || !uniform.credentialStatus) {
|
|
797
1372
|
if (args.mandatoryCredentialStatus) {
|
|
798
1373
|
const error = "No credential status object found in the Verifiable Credential and it is mandatory";
|
|
@@ -807,7 +1382,7 @@ async function checkStatusForCredential(args) {
|
|
|
807
1382
|
};
|
|
808
1383
|
}
|
|
809
1384
|
if ("credentialStatus" in uniform && uniform.credentialStatus) {
|
|
810
|
-
if (uniform.credentialStatus.type === "StatusList2021Entry") {
|
|
1385
|
+
if (uniform.credentialStatus.type === "StatusList2021Entry" || uniform.credentialStatus.type === "BitstringStatusListEntry") {
|
|
811
1386
|
return checkStatus({
|
|
812
1387
|
...args,
|
|
813
1388
|
verifyStatusListCredential,
|
|
@@ -855,35 +1430,35 @@ async function updateStatusIndexFromStatusListCredential(args, context) {
|
|
|
855
1430
|
return implementation.updateStatusListIndex(args, context);
|
|
856
1431
|
}
|
|
857
1432
|
__name(updateStatusIndexFromStatusListCredential, "updateStatusIndexFromStatusListCredential");
|
|
858
|
-
async function
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
const type = uniform.type.find((t) => t.includes("StatusList2021") || t.includes("OAuth2StatusList"));
|
|
874
|
-
if (!type) {
|
|
875
|
-
throw new Error("Invalid status list credential type");
|
|
876
|
-
}
|
|
877
|
-
statusListType = type.replace("Credential", "");
|
|
1433
|
+
async function extractCredentialDetails(statusListCredential) {
|
|
1434
|
+
const statusListType = determineStatusListType(statusListCredential);
|
|
1435
|
+
const implementation = getStatusListImplementation(statusListType);
|
|
1436
|
+
return implementation.extractCredentialDetails(statusListCredential);
|
|
1437
|
+
}
|
|
1438
|
+
__name(extractCredentialDetails, "extractCredentialDetails");
|
|
1439
|
+
async function toStatusListDetails(args) {
|
|
1440
|
+
if ("statusListCredential" in args) {
|
|
1441
|
+
const statusListType = args.statusListType;
|
|
1442
|
+
const implementation = getStatusListImplementation(statusListType);
|
|
1443
|
+
return implementation.toStatusListDetails(args);
|
|
1444
|
+
} else {
|
|
1445
|
+
const statusListType = args.statusListEntity.type;
|
|
1446
|
+
const implementation = getStatusListImplementation(statusListType);
|
|
1447
|
+
return implementation.toStatusListDetails(args);
|
|
878
1448
|
}
|
|
1449
|
+
}
|
|
1450
|
+
__name(toStatusListDetails, "toStatusListDetails");
|
|
1451
|
+
async function createCredentialStatusFromStatusList(args) {
|
|
1452
|
+
const { statusList, statusListEntry, statusListIndex } = args;
|
|
1453
|
+
const statusListType = determineStatusListType(statusList.statusListCredential);
|
|
879
1454
|
const implementation = getStatusListImplementation(statusListType);
|
|
880
|
-
return
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1455
|
+
return implementation.createCredentialStatus({
|
|
1456
|
+
statusList,
|
|
1457
|
+
statusListEntry,
|
|
1458
|
+
statusListIndex
|
|
884
1459
|
});
|
|
885
1460
|
}
|
|
886
|
-
__name(
|
|
1461
|
+
__name(createCredentialStatusFromStatusList, "createCredentialStatusFromStatusList");
|
|
887
1462
|
async function updateStatusListIndexFromEncodedList(args, context) {
|
|
888
1463
|
const { type } = getAssertedValue("type", args);
|
|
889
1464
|
const implementation = getStatusListImplementation(type);
|
|
@@ -898,7 +1473,7 @@ async function statusList2021ToVerifiableCredential(args, context) {
|
|
|
898
1473
|
offlineWhenNoDIDRegistered: true
|
|
899
1474
|
});
|
|
900
1475
|
const proofFormat = args?.proofFormat ?? "lds";
|
|
901
|
-
assertValidProofType(
|
|
1476
|
+
assertValidProofType(StatusListType6.StatusList2021, proofFormat);
|
|
902
1477
|
const veramoProofFormat = proofFormat;
|
|
903
1478
|
const encodedList = getAssertedValue("encodedList", args.encodedList);
|
|
904
1479
|
const statusPurpose = getAssertedValue("statusPurpose", args.statusPurpose);
|
|
@@ -927,7 +1502,7 @@ async function statusList2021ToVerifiableCredential(args, context) {
|
|
|
927
1502
|
proofFormat: veramoProofFormat,
|
|
928
1503
|
fetchRemoteContexts: true
|
|
929
1504
|
});
|
|
930
|
-
return
|
|
1505
|
+
return CredentialMapper4.toWrappedVerifiableCredential(verifiableCredential).original;
|
|
931
1506
|
}
|
|
932
1507
|
__name(statusList2021ToVerifiableCredential, "statusList2021ToVerifiableCredential");
|
|
933
1508
|
export {
|
|
@@ -935,12 +1510,15 @@ export {
|
|
|
935
1510
|
StatusOAuth,
|
|
936
1511
|
checkStatusForCredential,
|
|
937
1512
|
checkStatusIndexFromStatusListCredential,
|
|
1513
|
+
createCredentialStatusFromStatusList,
|
|
938
1514
|
createNewStatusList,
|
|
1515
|
+
determineStatusListType,
|
|
1516
|
+
extractCredentialDetails,
|
|
939
1517
|
fetchStatusListCredential,
|
|
940
1518
|
simpleCheckStatusFromStatusListUrl,
|
|
941
1519
|
statusList2021ToVerifiableCredential,
|
|
942
|
-
statusListCredentialToDetails,
|
|
943
1520
|
statusPluginStatusFunction,
|
|
1521
|
+
toStatusListDetails,
|
|
944
1522
|
updateStatusIndexFromStatusListCredential,
|
|
945
1523
|
updateStatusListIndexFromEncodedList,
|
|
946
1524
|
vcLibCheckStatusFunction
|