@sphereon/ssi-sdk.vc-status-list 0.34.0 → 0.34.1-feature.SSISDK.17.bitstring.sl.11
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 +424 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +76 -26
- package/dist/index.d.ts +76 -26
- package/dist/index.js +425 -46
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/functions.ts +50 -14
- package/src/impl/BitstringStatusListImplementation.ts +347 -0
- package/src/impl/IStatusList.ts +66 -4
- package/src/impl/OAuthStatusList.ts +60 -18
- package/src/impl/StatusList2021.ts +47 -12
- package/src/impl/StatusListFactory.ts +2 -0
- package/src/types/BitstringStatusList.ts +4 -0
- package/src/types/index.ts +71 -22
- package/src/utils.ts +35 -2
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ var Status2021 = /* @__PURE__ */ function(Status20212) {
|
|
|
15
15
|
}({});
|
|
16
16
|
|
|
17
17
|
// src/functions.ts
|
|
18
|
-
import { CredentialMapper as
|
|
18
|
+
import { CredentialMapper as CredentialMapper4, DocumentFormat as DocumentFormat4, 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,12 @@ var ValidProofTypeMap = /* @__PURE__ */ new Map([
|
|
|
72
72
|
"jwt",
|
|
73
73
|
"cbor"
|
|
74
74
|
]
|
|
75
|
+
],
|
|
76
|
+
[
|
|
77
|
+
StatusListType.BitstringStatusList,
|
|
78
|
+
[
|
|
79
|
+
"lds"
|
|
80
|
+
]
|
|
75
81
|
]
|
|
76
82
|
]);
|
|
77
83
|
function assertValidProofType(type, proofFormat) {
|
|
@@ -122,6 +128,26 @@ function determineProofFormat(credential) {
|
|
|
122
128
|
}
|
|
123
129
|
}
|
|
124
130
|
__name(determineProofFormat, "determineProofFormat");
|
|
131
|
+
function ensureDate(value) {
|
|
132
|
+
if (value === void 0 || value === null) {
|
|
133
|
+
return void 0;
|
|
134
|
+
}
|
|
135
|
+
if (value instanceof Date) {
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
if (typeof value === "string") {
|
|
139
|
+
if (value.trim() === "") {
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
const date = new Date(value);
|
|
143
|
+
if (isNaN(date.getTime())) {
|
|
144
|
+
return void 0;
|
|
145
|
+
}
|
|
146
|
+
return date;
|
|
147
|
+
}
|
|
148
|
+
return void 0;
|
|
149
|
+
}
|
|
150
|
+
__name(ensureDate, "ensureDate");
|
|
125
151
|
|
|
126
152
|
// src/impl/StatusList2021.ts
|
|
127
153
|
import { CredentialMapper as CredentialMapper2, DocumentFormat as DocumentFormat2, StatusListType as StatusListType2 } from "@sphereon/ssi-types";
|
|
@@ -185,13 +211,14 @@ var StatusList2021Implementation = class {
|
|
|
185
211
|
encodedList,
|
|
186
212
|
proofFormat
|
|
187
213
|
}, context);
|
|
214
|
+
if (!("statusPurpose" in credentialSubject)) {
|
|
215
|
+
return Promise.reject(Error("statusPurpose is required in credentialSubject for StatusList2021"));
|
|
216
|
+
}
|
|
188
217
|
return {
|
|
189
218
|
statusListCredential: updatedCredential,
|
|
190
219
|
encodedList,
|
|
191
220
|
statusList2021: {
|
|
192
|
-
|
|
193
|
-
statusPurpose: credentialSubject.statusPurpose
|
|
194
|
-
} : {},
|
|
221
|
+
statusPurpose: credentialSubject.statusPurpose,
|
|
195
222
|
indexingDirection: "rightToLeft"
|
|
196
223
|
},
|
|
197
224
|
length: statusList.length - 1,
|
|
@@ -214,7 +241,7 @@ var StatusList2021Implementation = class {
|
|
|
214
241
|
encodedList: args.encodedList
|
|
215
242
|
});
|
|
216
243
|
const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
217
|
-
statusList.setStatus(index, args.value);
|
|
244
|
+
statusList.setStatus(index, args.value !== 0);
|
|
218
245
|
const newEncodedList = await statusList.encode();
|
|
219
246
|
const credential = await this.createVerifiableCredential({
|
|
220
247
|
id,
|
|
@@ -256,10 +283,12 @@ var StatusList2021Implementation = class {
|
|
|
256
283
|
const encodedList = getAssertedProperty("encodedList", credentialSubject);
|
|
257
284
|
const proofFormat = CredentialMapper2.detectDocumentType(statusListPayload) === DocumentFormat2.JWT ? "jwt" : "lds";
|
|
258
285
|
const statusPurpose = getAssertedProperty("statusPurpose", credentialSubject);
|
|
286
|
+
const indexingDirection = "rightToLeft";
|
|
259
287
|
const list = await StatusList.decode({
|
|
260
288
|
encodedList
|
|
261
289
|
});
|
|
262
290
|
return {
|
|
291
|
+
// Base implementation fields
|
|
263
292
|
id,
|
|
264
293
|
encodedList,
|
|
265
294
|
issuer,
|
|
@@ -268,18 +297,36 @@ var StatusList2021Implementation = class {
|
|
|
268
297
|
length: list.length,
|
|
269
298
|
statusListCredential: statusListPayload,
|
|
270
299
|
statuslistContentType: this.buildContentType(proofFormat),
|
|
300
|
+
correlationId: args.correlationId,
|
|
301
|
+
driverType: args.driverType,
|
|
302
|
+
// Flattened StatusList2021-specific fields
|
|
303
|
+
indexingDirection,
|
|
304
|
+
statusPurpose,
|
|
305
|
+
// Legacy nested structure for backward compatibility
|
|
271
306
|
statusList2021: {
|
|
272
|
-
indexingDirection
|
|
273
|
-
statusPurpose
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
307
|
+
indexingDirection,
|
|
308
|
+
statusPurpose,
|
|
309
|
+
// Optional fields from args
|
|
310
|
+
...args.correlationId && {
|
|
311
|
+
correlationId: args.correlationId
|
|
312
|
+
},
|
|
313
|
+
...args.driverType && {
|
|
314
|
+
driverType: args.driverType
|
|
315
|
+
}
|
|
280
316
|
}
|
|
281
317
|
};
|
|
282
318
|
}
|
|
319
|
+
async createCredentialStatus(args) {
|
|
320
|
+
const { statusList, statusListIndex } = args;
|
|
321
|
+
const statusList2021 = statusList;
|
|
322
|
+
return {
|
|
323
|
+
id: `${statusList.id}#${statusListIndex}`,
|
|
324
|
+
type: "StatusList2021Entry",
|
|
325
|
+
statusPurpose: statusList2021.statusPurpose ?? "revocation",
|
|
326
|
+
statusListIndex: "" + statusListIndex,
|
|
327
|
+
statusListCredential: statusList.id
|
|
328
|
+
};
|
|
329
|
+
}
|
|
283
330
|
async createVerifiableCredential(args, context) {
|
|
284
331
|
const identifier = await context.agent.identifierManagedGet({
|
|
285
332
|
identifier: typeof args.issuer === "string" ? args.issuer : args.issuer.id,
|
|
@@ -572,7 +619,8 @@ var OAuthStatusListImplementation = class {
|
|
|
572
619
|
}
|
|
573
620
|
const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT2;
|
|
574
621
|
const { issuer, id, oauthStatusList, keyRef } = args;
|
|
575
|
-
const { bitsPerStatus
|
|
622
|
+
const { bitsPerStatus } = oauthStatusList;
|
|
623
|
+
const expiresAt = ensureDate(oauthStatusList.expiresAt);
|
|
576
624
|
const length = args.length ?? DEFAULT_LIST_LENGTH2;
|
|
577
625
|
const issuerString = typeof issuer === "string" ? issuer : issuer.id;
|
|
578
626
|
const correlationId = getAssertedValue("correlationId", args.correlationId);
|
|
@@ -595,7 +643,8 @@ var OAuthStatusListImplementation = class {
|
|
|
595
643
|
};
|
|
596
644
|
}
|
|
597
645
|
async updateStatusListIndex(args, context) {
|
|
598
|
-
const { statusListCredential, value,
|
|
646
|
+
const { statusListCredential, value, keyRef } = args;
|
|
647
|
+
const expiresAt = ensureDate(args.expiresAt);
|
|
599
648
|
if (typeof statusListCredential !== "string") {
|
|
600
649
|
return Promise.reject("statusListCredential in neither JWT nor CWT");
|
|
601
650
|
}
|
|
@@ -606,6 +655,9 @@ var OAuthStatusListImplementation = class {
|
|
|
606
655
|
if (index < 0 || index >= statusList.statusList.length) {
|
|
607
656
|
throw new Error("Status list index out of bounds");
|
|
608
657
|
}
|
|
658
|
+
if (typeof value !== "number") {
|
|
659
|
+
throw new Error("Status list values should be of type number");
|
|
660
|
+
}
|
|
609
661
|
statusList.setStatus(index, value);
|
|
610
662
|
const { statusListCredential: signedCredential, encodedList } = await this.createSignedStatusList(proofFormat, context, statusList, issuer, id, expiresAt, keyRef);
|
|
611
663
|
return {
|
|
@@ -628,12 +680,13 @@ var OAuthStatusListImplementation = class {
|
|
|
628
680
|
throw new Error("OAuthStatusList options are required for type OAuthStatusList");
|
|
629
681
|
}
|
|
630
682
|
const { proofFormat, oauthStatusList, keyRef } = args;
|
|
631
|
-
const { bitsPerStatus
|
|
683
|
+
const { bitsPerStatus } = oauthStatusList;
|
|
684
|
+
const expiresAt = ensureDate(oauthStatusList.expiresAt);
|
|
632
685
|
const { issuer, id } = getAssertedValues(args);
|
|
633
686
|
const issuerString = typeof issuer === "string" ? issuer : issuer.id;
|
|
634
687
|
const listToUpdate = StatusList4.decompressStatusList(args.encodedList, bitsPerStatus ?? DEFAULT_BITS_PER_STATUS);
|
|
635
688
|
const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
636
|
-
listToUpdate.setStatus(index, args.value
|
|
689
|
+
listToUpdate.setStatus(index, args.value);
|
|
637
690
|
const { statusListCredential, encodedList } = await this.createSignedStatusList(proofFormat ?? DEFAULT_PROOF_FORMAT2, context, listToUpdate, issuerString, id, expiresAt, keyRef);
|
|
638
691
|
return {
|
|
639
692
|
encodedList,
|
|
@@ -650,9 +703,6 @@ var OAuthStatusListImplementation = class {
|
|
|
650
703
|
statuslistContentType: this.buildContentType(proofFormat)
|
|
651
704
|
};
|
|
652
705
|
}
|
|
653
|
-
buildContentType(proofFormat) {
|
|
654
|
-
return `application/statuslist+${proofFormat === "cbor" ? "cwt" : "jwt"}`;
|
|
655
|
-
}
|
|
656
706
|
async checkStatusIndex(args) {
|
|
657
707
|
const { statusListCredential, statusListIndex } = args;
|
|
658
708
|
if (typeof statusListCredential !== "string") {
|
|
@@ -662,7 +712,7 @@ var OAuthStatusListImplementation = class {
|
|
|
662
712
|
const { statusList } = proofFormat === "jwt" ? decodeStatusListJWT(statusListCredential) : decodeStatusListCWT(statusListCredential);
|
|
663
713
|
const index = typeof statusListIndex === "number" ? statusListIndex : parseInt(statusListIndex);
|
|
664
714
|
if (index < 0 || index >= statusList.statusList.length) {
|
|
665
|
-
throw new Error(
|
|
715
|
+
throw new Error(`Status list index out of bounds, has ${statusList.statusList.length} items, requested ${index}`);
|
|
666
716
|
}
|
|
667
717
|
return statusList.getStatus(index);
|
|
668
718
|
}
|
|
@@ -671,7 +721,10 @@ var OAuthStatusListImplementation = class {
|
|
|
671
721
|
const proofFormat = determineProofFormat(statusListPayload);
|
|
672
722
|
const decoded = proofFormat === "jwt" ? decodeStatusListJWT(statusListPayload) : decodeStatusListCWT(statusListPayload);
|
|
673
723
|
const { statusList, issuer, id, exp } = decoded;
|
|
724
|
+
const bitsPerStatus = statusList.getBitsPerStatus();
|
|
725
|
+
const expiresAt = exp ? new Date(exp * 1e3) : void 0;
|
|
674
726
|
return {
|
|
727
|
+
// Base implementation fields
|
|
675
728
|
id,
|
|
676
729
|
encodedList: statusList.compressStatusList(),
|
|
677
730
|
issuer,
|
|
@@ -680,12 +733,21 @@ var OAuthStatusListImplementation = class {
|
|
|
680
733
|
length: statusList.statusList.length,
|
|
681
734
|
statusListCredential: statusListPayload,
|
|
682
735
|
statuslistContentType: this.buildContentType(proofFormat),
|
|
736
|
+
correlationId: args.correlationId,
|
|
737
|
+
driverType: args.driverType,
|
|
738
|
+
// Flattened OAuth-specific fields
|
|
739
|
+
bitsPerStatus,
|
|
740
|
+
...expiresAt && {
|
|
741
|
+
expiresAt
|
|
742
|
+
},
|
|
743
|
+
// Legacy nested structure for backward compatibility
|
|
683
744
|
oauthStatusList: {
|
|
684
|
-
bitsPerStatus
|
|
685
|
-
...
|
|
686
|
-
expiresAt
|
|
745
|
+
bitsPerStatus,
|
|
746
|
+
...expiresAt && {
|
|
747
|
+
expiresAt
|
|
687
748
|
}
|
|
688
749
|
},
|
|
750
|
+
// Optional fields from args
|
|
689
751
|
...args.correlationId && {
|
|
690
752
|
correlationId: args.correlationId
|
|
691
753
|
},
|
|
@@ -694,6 +756,21 @@ var OAuthStatusListImplementation = class {
|
|
|
694
756
|
}
|
|
695
757
|
};
|
|
696
758
|
}
|
|
759
|
+
async createCredentialStatus(args) {
|
|
760
|
+
const { statusList, statusListIndex } = args;
|
|
761
|
+
const oauthStatusList = statusList;
|
|
762
|
+
return {
|
|
763
|
+
id: `${statusList.id}#${statusListIndex}`,
|
|
764
|
+
type: "OAuthStatusListEntry",
|
|
765
|
+
bitsPerStatus: oauthStatusList.bitsPerStatus,
|
|
766
|
+
statusListIndex: "" + statusListIndex,
|
|
767
|
+
statusListCredential: statusList.id,
|
|
768
|
+
expiresAt: oauthStatusList.expiresAt
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
buildContentType(proofFormat) {
|
|
772
|
+
return `application/statuslist+${proofFormat === "cbor" ? "cwt" : "jwt"}`;
|
|
773
|
+
}
|
|
697
774
|
async createSignedStatusList(proofFormat, context, statusList, issuerString, id, expiresAt, keyRef) {
|
|
698
775
|
switch (proofFormat) {
|
|
699
776
|
case "jwt": {
|
|
@@ -709,7 +786,294 @@ var OAuthStatusListImplementation = class {
|
|
|
709
786
|
};
|
|
710
787
|
|
|
711
788
|
// src/impl/StatusListFactory.ts
|
|
712
|
-
import { StatusListType as
|
|
789
|
+
import { StatusListType as StatusListType5 } from "@sphereon/ssi-types";
|
|
790
|
+
|
|
791
|
+
// src/impl/BitstringStatusListImplementation.ts
|
|
792
|
+
import { CredentialMapper as CredentialMapper3, DocumentFormat as DocumentFormat3, StatusListType as StatusListType4 } from "@sphereon/ssi-types";
|
|
793
|
+
import { BitstreamStatusList, createStatusListCredential } from "@4sure-tech/vc-bitstring-status-lists";
|
|
794
|
+
var DEFAULT_LIST_LENGTH3 = 131072;
|
|
795
|
+
var DEFAULT_PROOF_FORMAT3 = "lds";
|
|
796
|
+
var DEFAULT_STATUS_PURPOSE = "revocation";
|
|
797
|
+
var BitstringStatusListImplementation = class {
|
|
798
|
+
static {
|
|
799
|
+
__name(this, "BitstringStatusListImplementation");
|
|
800
|
+
}
|
|
801
|
+
async createNewStatusList(args, context) {
|
|
802
|
+
if (!args.bitstringStatusList) {
|
|
803
|
+
throw new Error("BitstringStatusList options are required for type BitstringStatusList");
|
|
804
|
+
}
|
|
805
|
+
const length = args?.length ?? DEFAULT_LIST_LENGTH3;
|
|
806
|
+
const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT3;
|
|
807
|
+
assertValidProofType(StatusListType4.BitstringStatusList, proofFormat);
|
|
808
|
+
const veramoProofFormat = proofFormat;
|
|
809
|
+
const { issuer, id } = args;
|
|
810
|
+
const correlationId = getAssertedValue("correlationId", args.correlationId);
|
|
811
|
+
const { statusPurpose, bitsPerStatus, validFrom, validUntil, ttl } = args.bitstringStatusList;
|
|
812
|
+
const statusListCredential = await this.createVerifiableCredential({
|
|
813
|
+
...args,
|
|
814
|
+
proofFormat: veramoProofFormat,
|
|
815
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
816
|
+
validFrom: ensureDate(validFrom),
|
|
817
|
+
validUntil: ensureDate(validUntil),
|
|
818
|
+
ttl
|
|
819
|
+
}, context);
|
|
820
|
+
return {
|
|
821
|
+
encodedList: statusListCredential.credentialSubject.encodedList,
|
|
822
|
+
statusListCredential,
|
|
823
|
+
bitstringStatusList: {
|
|
824
|
+
statusPurpose: statusPurpose ?? DEFAULT_STATUS_PURPOSE,
|
|
825
|
+
...statusListCredential.validFrom && {
|
|
826
|
+
validFrom: new Date(statusListCredential.validFrom)
|
|
827
|
+
},
|
|
828
|
+
...statusListCredential.validUntil && {
|
|
829
|
+
validUntil: new Date(statusListCredential.validUntil)
|
|
830
|
+
},
|
|
831
|
+
ttl,
|
|
832
|
+
bitsPerStatus
|
|
833
|
+
},
|
|
834
|
+
length,
|
|
835
|
+
type: StatusListType4.BitstringStatusList,
|
|
836
|
+
proofFormat,
|
|
837
|
+
id,
|
|
838
|
+
correlationId,
|
|
839
|
+
issuer,
|
|
840
|
+
statuslistContentType: this.buildContentType(proofFormat)
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
async updateStatusListIndex(args, context) {
|
|
844
|
+
if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
|
|
845
|
+
return Promise.reject("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListIndex)");
|
|
846
|
+
}
|
|
847
|
+
const credential = args.statusListCredential;
|
|
848
|
+
const uniform = CredentialMapper3.toUniformCredential(credential);
|
|
849
|
+
const { issuer, credentialSubject } = uniform;
|
|
850
|
+
const id = getAssertedValue("id", uniform.id);
|
|
851
|
+
const origEncodedList = getAssertedProperty("encodedList", credentialSubject);
|
|
852
|
+
const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
853
|
+
const statusList = await BitstreamStatusList.decode({
|
|
854
|
+
encodedList: origEncodedList,
|
|
855
|
+
statusSize: args.bitsPerStatus
|
|
856
|
+
});
|
|
857
|
+
statusList.setStatus(index, args.value);
|
|
858
|
+
const proofFormat = CredentialMapper3.detectDocumentType(credential) === DocumentFormat3.JWT ? "jwt" : "lds";
|
|
859
|
+
const credSubject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
|
|
860
|
+
const statusPurpose = getAssertedProperty("statusPurpose", credSubject);
|
|
861
|
+
const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : void 0;
|
|
862
|
+
const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : void 0;
|
|
863
|
+
const ttl = credSubject.ttl;
|
|
864
|
+
const updatedCredential = await this.createVerifiableCredential({
|
|
865
|
+
...args,
|
|
866
|
+
id,
|
|
867
|
+
issuer,
|
|
868
|
+
statusList,
|
|
869
|
+
proofFormat,
|
|
870
|
+
statusPurpose,
|
|
871
|
+
ttl,
|
|
872
|
+
validFrom,
|
|
873
|
+
validUntil
|
|
874
|
+
}, context);
|
|
875
|
+
return {
|
|
876
|
+
statusListCredential: updatedCredential,
|
|
877
|
+
encodedList: updatedCredential.credentialSubject.encodedList,
|
|
878
|
+
bitstringStatusList: {
|
|
879
|
+
statusPurpose,
|
|
880
|
+
...updatedCredential.validFrom && {
|
|
881
|
+
validFrom: new Date(updatedCredential.validFrom)
|
|
882
|
+
},
|
|
883
|
+
...updatedCredential.validUntil && {
|
|
884
|
+
validUntil: new Date(updatedCredential.validUntil)
|
|
885
|
+
},
|
|
886
|
+
bitsPerStatus: args.bitsPerStatus,
|
|
887
|
+
ttl
|
|
888
|
+
},
|
|
889
|
+
length: statusList.getLength(),
|
|
890
|
+
type: StatusListType4.BitstringStatusList,
|
|
891
|
+
proofFormat,
|
|
892
|
+
id,
|
|
893
|
+
issuer,
|
|
894
|
+
statuslistContentType: this.buildContentType(proofFormat)
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
async updateStatusListFromEncodedList(args, context) {
|
|
898
|
+
if (!args.bitstringStatusList) {
|
|
899
|
+
throw new Error("bitstringStatusList options required for type BitstringStatusList");
|
|
900
|
+
}
|
|
901
|
+
if (args.bitstringStatusList.bitsPerStatus < 1) {
|
|
902
|
+
return Promise.reject("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (updateStatusListFromEncodedList)");
|
|
903
|
+
}
|
|
904
|
+
const { statusPurpose, bitsPerStatus, ttl, validFrom, validUntil } = args.bitstringStatusList;
|
|
905
|
+
const proofFormat = args?.proofFormat ?? DEFAULT_PROOF_FORMAT3;
|
|
906
|
+
assertValidProofType(StatusListType4.BitstringStatusList, proofFormat);
|
|
907
|
+
const veramoProofFormat = proofFormat;
|
|
908
|
+
const { issuer, id } = getAssertedValues(args);
|
|
909
|
+
const statusList = await BitstreamStatusList.decode({
|
|
910
|
+
encodedList: args.encodedList,
|
|
911
|
+
statusSize: bitsPerStatus
|
|
912
|
+
});
|
|
913
|
+
const index = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
914
|
+
statusList.setStatus(index, args.value);
|
|
915
|
+
const credential = await this.createVerifiableCredential({
|
|
916
|
+
id,
|
|
917
|
+
issuer,
|
|
918
|
+
statusList,
|
|
919
|
+
proofFormat: veramoProofFormat,
|
|
920
|
+
keyRef: args.keyRef,
|
|
921
|
+
statusPurpose,
|
|
922
|
+
validFrom: ensureDate(validFrom),
|
|
923
|
+
validUntil: ensureDate(validUntil),
|
|
924
|
+
ttl
|
|
925
|
+
}, context);
|
|
926
|
+
return {
|
|
927
|
+
type: StatusListType4.BitstringStatusList,
|
|
928
|
+
statusListCredential: credential,
|
|
929
|
+
encodedList: credential.credentialSubject.encodedList,
|
|
930
|
+
bitstringStatusList: {
|
|
931
|
+
statusPurpose,
|
|
932
|
+
bitsPerStatus,
|
|
933
|
+
...credential.validFrom && {
|
|
934
|
+
validFrom: new Date(credential.validFrom)
|
|
935
|
+
},
|
|
936
|
+
...credential.validUntil && {
|
|
937
|
+
validUntil: new Date(credential.validUntil)
|
|
938
|
+
},
|
|
939
|
+
ttl
|
|
940
|
+
},
|
|
941
|
+
length: statusList.getLength(),
|
|
942
|
+
proofFormat: args.proofFormat ?? "lds",
|
|
943
|
+
id,
|
|
944
|
+
issuer,
|
|
945
|
+
statuslistContentType: this.buildContentType(proofFormat)
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
async checkStatusIndex(args) {
|
|
949
|
+
if (!args.bitsPerStatus || args.bitsPerStatus < 1) {
|
|
950
|
+
return Promise.reject("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (checkStatusIndex)");
|
|
951
|
+
}
|
|
952
|
+
const uniform = CredentialMapper3.toUniformCredential(args.statusListCredential);
|
|
953
|
+
const { credentialSubject } = uniform;
|
|
954
|
+
const encodedList = getAssertedProperty("encodedList", credentialSubject);
|
|
955
|
+
const statusSize = args.bitsPerStatus;
|
|
956
|
+
const statusList = await BitstreamStatusList.decode({
|
|
957
|
+
encodedList,
|
|
958
|
+
statusSize
|
|
959
|
+
});
|
|
960
|
+
const numIndex = typeof args.statusListIndex === "number" ? args.statusListIndex : parseInt(args.statusListIndex);
|
|
961
|
+
if (statusList.getLength() <= numIndex) {
|
|
962
|
+
throw new Error(`Status list index out of bounds, has ${statusList.getLength()} entries, requested ${numIndex}`);
|
|
963
|
+
}
|
|
964
|
+
return statusList.getStatus(numIndex);
|
|
965
|
+
}
|
|
966
|
+
async toStatusListDetails(args) {
|
|
967
|
+
const { statusListPayload, bitsPerStatus } = args;
|
|
968
|
+
if (!bitsPerStatus || bitsPerStatus < 1) {
|
|
969
|
+
return Promise.reject("bitsPerStatus must be set for bitstring status lists and must be 1 or higher. (toStatusListDetails)");
|
|
970
|
+
}
|
|
971
|
+
const uniform = CredentialMapper3.toUniformCredential(statusListPayload);
|
|
972
|
+
const { issuer, credentialSubject } = uniform;
|
|
973
|
+
const id = getAssertedValue("id", uniform.id);
|
|
974
|
+
const encodedList = getAssertedProperty("encodedList", credentialSubject);
|
|
975
|
+
const proofFormat = CredentialMapper3.detectDocumentType(statusListPayload) === DocumentFormat3.JWT ? "jwt" : "lds";
|
|
976
|
+
const credSubject = Array.isArray(credentialSubject) ? credentialSubject[0] : credentialSubject;
|
|
977
|
+
const statusPurpose = getAssertedProperty("statusPurpose", credSubject);
|
|
978
|
+
const validFrom = uniform.validFrom ? new Date(uniform.validFrom) : void 0;
|
|
979
|
+
const validUntil = uniform.validUntil ? new Date(uniform.validUntil) : void 0;
|
|
980
|
+
const ttl = credSubject.ttl;
|
|
981
|
+
const statuslistLength = BitstreamStatusList.getStatusListLength(encodedList, bitsPerStatus);
|
|
982
|
+
return {
|
|
983
|
+
// Base implementation fields
|
|
984
|
+
id,
|
|
985
|
+
encodedList,
|
|
986
|
+
issuer,
|
|
987
|
+
type: StatusListType4.BitstringStatusList,
|
|
988
|
+
proofFormat,
|
|
989
|
+
length: statuslistLength,
|
|
990
|
+
statusListCredential: statusListPayload,
|
|
991
|
+
statuslistContentType: this.buildContentType(proofFormat),
|
|
992
|
+
correlationId: args.correlationId,
|
|
993
|
+
driverType: args.driverType,
|
|
994
|
+
// Flattened Bitstring-specific fields
|
|
995
|
+
statusPurpose,
|
|
996
|
+
bitsPerStatus,
|
|
997
|
+
...validFrom && {
|
|
998
|
+
validFrom
|
|
999
|
+
},
|
|
1000
|
+
...validUntil && {
|
|
1001
|
+
validUntil
|
|
1002
|
+
},
|
|
1003
|
+
...ttl && {
|
|
1004
|
+
ttl
|
|
1005
|
+
},
|
|
1006
|
+
// Legacy nested structure for backward compatibility
|
|
1007
|
+
bitstringStatusList: {
|
|
1008
|
+
statusPurpose,
|
|
1009
|
+
bitsPerStatus,
|
|
1010
|
+
...validFrom && {
|
|
1011
|
+
validFrom
|
|
1012
|
+
},
|
|
1013
|
+
...validUntil && {
|
|
1014
|
+
validUntil
|
|
1015
|
+
},
|
|
1016
|
+
...ttl && {
|
|
1017
|
+
ttl
|
|
1018
|
+
}
|
|
1019
|
+
},
|
|
1020
|
+
// Optional fields from args
|
|
1021
|
+
...args.correlationId && {
|
|
1022
|
+
correlationId: args.correlationId
|
|
1023
|
+
},
|
|
1024
|
+
...args.driverType && {
|
|
1025
|
+
driverType: args.driverType
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
async createCredentialStatus(args) {
|
|
1030
|
+
const { statusList, statusListEntry, statusListIndex } = args;
|
|
1031
|
+
const isBitstringEntry = /* @__PURE__ */ __name((entry) => {
|
|
1032
|
+
return "statusPurpose" in entry;
|
|
1033
|
+
}, "isBitstringEntry");
|
|
1034
|
+
if (!isBitstringEntry(statusListEntry)) {
|
|
1035
|
+
throw new Error("Expected bitstring status list entry for bitstring status list");
|
|
1036
|
+
}
|
|
1037
|
+
const bitstringStatusList = statusList;
|
|
1038
|
+
return {
|
|
1039
|
+
id: `${statusList.id}#${statusListIndex}`,
|
|
1040
|
+
type: "BitstringStatusListEntry",
|
|
1041
|
+
statusPurpose: statusListEntry.statusPurpose,
|
|
1042
|
+
statusListIndex: "" + statusListIndex,
|
|
1043
|
+
statusListCredential: statusList.id,
|
|
1044
|
+
bitsPerStatus: bitstringStatusList.bitsPerStatus
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
async createVerifiableCredential(args, context) {
|
|
1048
|
+
const identifier = await context.agent.identifierManagedGet({
|
|
1049
|
+
identifier: typeof args.issuer === "string" ? args.issuer : args.issuer.id,
|
|
1050
|
+
vmRelationship: "assertionMethod",
|
|
1051
|
+
offlineWhenNoDIDRegistered: true
|
|
1052
|
+
});
|
|
1053
|
+
const unsignedCredential = await createStatusListCredential(args);
|
|
1054
|
+
const verifiableCredential = await context.agent.createVerifiableCredential({
|
|
1055
|
+
credential: unsignedCredential,
|
|
1056
|
+
keyRef: args.keyRef ?? identifier.kmsKeyRef,
|
|
1057
|
+
proofFormat: args.proofFormat,
|
|
1058
|
+
fetchRemoteContexts: true
|
|
1059
|
+
});
|
|
1060
|
+
return CredentialMapper3.toWrappedVerifiableCredential(verifiableCredential).original;
|
|
1061
|
+
}
|
|
1062
|
+
buildContentType(proofFormat) {
|
|
1063
|
+
switch (proofFormat) {
|
|
1064
|
+
case "jwt":
|
|
1065
|
+
return `application/statuslist+jwt`;
|
|
1066
|
+
case "cbor":
|
|
1067
|
+
return `application/statuslist+cwt`;
|
|
1068
|
+
case "lds":
|
|
1069
|
+
return "application/statuslist+ld+json";
|
|
1070
|
+
default:
|
|
1071
|
+
throw Error(`Unsupported content type '${proofFormat}' for status lists`);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
|
|
1076
|
+
// src/impl/StatusListFactory.ts
|
|
713
1077
|
var StatusListFactory = class _StatusListFactory {
|
|
714
1078
|
static {
|
|
715
1079
|
__name(this, "StatusListFactory");
|
|
@@ -718,8 +1082,9 @@ var StatusListFactory = class _StatusListFactory {
|
|
|
718
1082
|
implementations;
|
|
719
1083
|
constructor() {
|
|
720
1084
|
this.implementations = /* @__PURE__ */ new Map();
|
|
721
|
-
this.implementations.set(
|
|
722
|
-
this.implementations.set(
|
|
1085
|
+
this.implementations.set(StatusListType5.StatusList2021, new StatusList2021Implementation());
|
|
1086
|
+
this.implementations.set(StatusListType5.OAuthStatusList, new OAuthStatusListImplementation());
|
|
1087
|
+
this.implementations.set(StatusListType5.BitstringStatusList, new BitstringStatusListImplementation());
|
|
723
1088
|
}
|
|
724
1089
|
static getInstance() {
|
|
725
1090
|
if (!_StatusListFactory.instance) {
|
|
@@ -792,7 +1157,7 @@ __name(vcLibCheckStatusFunction, "vcLibCheckStatusFunction");
|
|
|
792
1157
|
async function checkStatusForCredential(args) {
|
|
793
1158
|
const verifyStatusListCredential = args.verifyStatusListCredential ?? true;
|
|
794
1159
|
const verifyMatchingIssuers = args.verifyMatchingIssuers ?? true;
|
|
795
|
-
const uniform =
|
|
1160
|
+
const uniform = CredentialMapper4.toUniformCredential(args.credential);
|
|
796
1161
|
if (!("credentialStatus" in uniform) || !uniform.credentialStatus) {
|
|
797
1162
|
if (args.mandatoryCredentialStatus) {
|
|
798
1163
|
const error = "No credential status object found in the Verifiable Credential and it is mandatory";
|
|
@@ -807,7 +1172,7 @@ async function checkStatusForCredential(args) {
|
|
|
807
1172
|
};
|
|
808
1173
|
}
|
|
809
1174
|
if ("credentialStatus" in uniform && uniform.credentialStatus) {
|
|
810
|
-
if (uniform.credentialStatus.type === "StatusList2021Entry") {
|
|
1175
|
+
if (uniform.credentialStatus.type === "StatusList2021Entry" || uniform.credentialStatus.type === "BitstringStatusListEntry") {
|
|
811
1176
|
return checkStatus({
|
|
812
1177
|
...args,
|
|
813
1178
|
verifyStatusListCredential,
|
|
@@ -855,35 +1220,48 @@ async function updateStatusIndexFromStatusListCredential(args, context) {
|
|
|
855
1220
|
return implementation.updateStatusListIndex(args, context);
|
|
856
1221
|
}
|
|
857
1222
|
__name(updateStatusIndexFromStatusListCredential, "updateStatusIndexFromStatusListCredential");
|
|
858
|
-
async function statusListCredentialToDetails(
|
|
859
|
-
const credential = getAssertedValue("statusListCredential",
|
|
1223
|
+
async function statusListCredentialToDetails({ correlationId, driverType, statusListCredential, bitsPerStatus }) {
|
|
1224
|
+
const credential = getAssertedValue("statusListCredential", statusListCredential);
|
|
860
1225
|
let statusListType;
|
|
861
|
-
const documentFormat =
|
|
862
|
-
if (documentFormat ===
|
|
1226
|
+
const documentFormat = CredentialMapper4.detectDocumentType(credential);
|
|
1227
|
+
if (documentFormat === DocumentFormat4.JWT) {
|
|
863
1228
|
const [header] = credential.split(".");
|
|
864
1229
|
const decodedHeader = JSON.parse(Buffer.from(header, "base64").toString());
|
|
865
1230
|
if (decodedHeader.typ === "statuslist+jwt") {
|
|
866
|
-
statusListType =
|
|
1231
|
+
statusListType = StatusListType6.OAuthStatusList;
|
|
867
1232
|
}
|
|
868
|
-
} else if (documentFormat ===
|
|
869
|
-
statusListType =
|
|
1233
|
+
} else if (documentFormat === DocumentFormat4.MSO_MDOC) {
|
|
1234
|
+
statusListType = StatusListType6.OAuthStatusList;
|
|
870
1235
|
}
|
|
871
1236
|
if (!statusListType) {
|
|
872
|
-
const uniform =
|
|
873
|
-
const type = uniform.type.find((t) => t.includes("StatusList2021") || t.includes("OAuth2StatusList"));
|
|
1237
|
+
const uniform = CredentialMapper4.toUniformCredential(credential);
|
|
1238
|
+
const type = uniform.type.find((t) => t.includes("StatusList2021") || t.includes("OAuth2StatusList") || t.includes("BitstringStatusList"));
|
|
874
1239
|
if (!type) {
|
|
875
1240
|
throw new Error("Invalid status list credential type");
|
|
876
1241
|
}
|
|
877
1242
|
statusListType = type.replace("Credential", "");
|
|
878
1243
|
}
|
|
879
1244
|
const implementation = getStatusListImplementation(statusListType);
|
|
880
|
-
|
|
1245
|
+
const result = await implementation.toStatusListDetails({
|
|
881
1246
|
statusListPayload: credential,
|
|
882
|
-
correlationId
|
|
883
|
-
driverType
|
|
1247
|
+
correlationId,
|
|
1248
|
+
driverType,
|
|
1249
|
+
bitsPerStatus
|
|
884
1250
|
});
|
|
1251
|
+
return result;
|
|
885
1252
|
}
|
|
886
1253
|
__name(statusListCredentialToDetails, "statusListCredentialToDetails");
|
|
1254
|
+
async function createCredentialStatusFromStatusList(args) {
|
|
1255
|
+
const { statusList, statusListEntry, statusListIndex } = args;
|
|
1256
|
+
const statusListType = determineStatusListType(statusList.statusListCredential);
|
|
1257
|
+
const implementation = getStatusListImplementation(statusListType);
|
|
1258
|
+
return implementation.createCredentialStatus({
|
|
1259
|
+
statusList,
|
|
1260
|
+
statusListEntry,
|
|
1261
|
+
statusListIndex
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
__name(createCredentialStatusFromStatusList, "createCredentialStatusFromStatusList");
|
|
887
1265
|
async function updateStatusListIndexFromEncodedList(args, context) {
|
|
888
1266
|
const { type } = getAssertedValue("type", args);
|
|
889
1267
|
const implementation = getStatusListImplementation(type);
|
|
@@ -898,7 +1276,7 @@ async function statusList2021ToVerifiableCredential(args, context) {
|
|
|
898
1276
|
offlineWhenNoDIDRegistered: true
|
|
899
1277
|
});
|
|
900
1278
|
const proofFormat = args?.proofFormat ?? "lds";
|
|
901
|
-
assertValidProofType(
|
|
1279
|
+
assertValidProofType(StatusListType6.StatusList2021, proofFormat);
|
|
902
1280
|
const veramoProofFormat = proofFormat;
|
|
903
1281
|
const encodedList = getAssertedValue("encodedList", args.encodedList);
|
|
904
1282
|
const statusPurpose = getAssertedValue("statusPurpose", args.statusPurpose);
|
|
@@ -927,7 +1305,7 @@ async function statusList2021ToVerifiableCredential(args, context) {
|
|
|
927
1305
|
proofFormat: veramoProofFormat,
|
|
928
1306
|
fetchRemoteContexts: true
|
|
929
1307
|
});
|
|
930
|
-
return
|
|
1308
|
+
return CredentialMapper4.toWrappedVerifiableCredential(verifiableCredential).original;
|
|
931
1309
|
}
|
|
932
1310
|
__name(statusList2021ToVerifiableCredential, "statusList2021ToVerifiableCredential");
|
|
933
1311
|
export {
|
|
@@ -935,6 +1313,7 @@ export {
|
|
|
935
1313
|
StatusOAuth,
|
|
936
1314
|
checkStatusForCredential,
|
|
937
1315
|
checkStatusIndexFromStatusListCredential,
|
|
1316
|
+
createCredentialStatusFromStatusList,
|
|
938
1317
|
createNewStatusList,
|
|
939
1318
|
fetchStatusListCredential,
|
|
940
1319
|
simpleCheckStatusFromStatusListUrl,
|