@cheqd/did-provider-cheqd 3.5.0 → 3.6.0-develop.1
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/build/cjs/agent/ICheqd.d.ts +98 -129
- package/build/cjs/agent/ICheqd.d.ts.map +1 -1
- package/build/cjs/agent/ICheqd.js +916 -246
- package/build/cjs/agent/ICheqd.js.map +1 -1
- package/build/cjs/did-manager/cheqd-did-provider.d.ts +14 -1
- package/build/cjs/did-manager/cheqd-did-provider.d.ts.map +1 -1
- package/build/cjs/did-manager/cheqd-did-provider.js +17 -4
- package/build/cjs/did-manager/cheqd-did-provider.js.map +1 -1
- package/build/cjs/dkg-threshold/lit-protocol.d.ts +4 -1
- package/build/cjs/dkg-threshold/lit-protocol.d.ts.map +1 -1
- package/build/cjs/dkg-threshold/lit-protocol.js +10 -0
- package/build/cjs/dkg-threshold/lit-protocol.js.map +1 -1
- package/build/esm/agent/ICheqd.d.ts +98 -129
- package/build/esm/agent/ICheqd.d.ts.map +1 -1
- package/build/esm/agent/ICheqd.js +918 -248
- package/build/esm/agent/ICheqd.js.map +1 -1
- package/build/esm/did-manager/cheqd-did-provider.d.ts +14 -1
- package/build/esm/did-manager/cheqd-did-provider.d.ts.map +1 -1
- package/build/esm/did-manager/cheqd-did-provider.js +16 -3
- package/build/esm/did-manager/cheqd-did-provider.js.map +1 -1
- package/build/esm/dkg-threshold/lit-protocol.d.ts +4 -1
- package/build/esm/dkg-threshold/lit-protocol.d.ts.map +1 -1
- package/build/esm/dkg-threshold/lit-protocol.js +10 -0
- package/build/esm/dkg-threshold/lit-protocol.js.map +1 -1
- package/build/tsconfig.cjs.tsbuildinfo +1 -1
- package/build/tsconfig.esm.tsbuildinfo +1 -1
- package/build/tsconfig.types.tsbuildinfo +1 -1
- package/build/types/agent/ICheqd.d.ts +98 -129
- package/build/types/agent/ICheqd.d.ts.map +1 -1
- package/build/types/did-manager/cheqd-did-provider.d.ts +14 -1
- package/build/types/did-manager/cheqd-did-provider.d.ts.map +1 -1
- package/build/types/dkg-threshold/lit-protocol.d.ts +4 -1
- package/build/types/dkg-threshold/lit-protocol.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/agent/ICheqd.ts +1101 -351
- package/src/did-manager/cheqd-did-provider.ts +32 -6
- package/src/dkg-threshold/lit-protocol.ts +15 -2
|
@@ -10,8 +10,8 @@ import { StatusList } from '@digitalbazaar/vc-status-list';
|
|
|
10
10
|
import { v4 } from 'uuid';
|
|
11
11
|
import fs from 'fs';
|
|
12
12
|
import Debug from 'debug';
|
|
13
|
-
import { LitCompatibleCosmosChains, LitProtocol } from '../dkg-threshold/lit-protocol.js';
|
|
14
|
-
import { blobToHexString, randomFromRange, toBlob,
|
|
13
|
+
import { LitCompatibleCosmosChains, LitProtocol, } from '../dkg-threshold/lit-protocol.js';
|
|
14
|
+
import { blobToHexString, randomFromRange, toBlob, } from '../utils/helpers.js';
|
|
15
15
|
import { resolverUrl } from '../did-manager/cheqd-did-resolver.js';
|
|
16
16
|
const debug = Debug('veramo:did-provider-cheqd');
|
|
17
17
|
export const AccessControlConditionTypes = { timelockPayment: 'timelockPayment', memoNonce: 'memoNonce', balance: 'balance' };
|
|
@@ -28,7 +28,6 @@ const GenerateDidDocWithLinkedResourceMethodName = 'cheqdGenerateDidDocWithLinke
|
|
|
28
28
|
const GenerateKeyPairMethodName = 'cheqdGenerateIdentityKeys';
|
|
29
29
|
const GenerateVersionIdMethodName = 'cheqdGenerateVersionId';
|
|
30
30
|
const GenerateStatusList2021MethodName = 'cheqdGenerateStatusList2021';
|
|
31
|
-
const GenerateEncryptedStatusList2021MethodName = 'cheqdGenerateEncryptedStatusList2021';
|
|
32
31
|
const IssueRevocableCredentialWithStatusList2021MethodName = 'cheqdIssueRevocableCredentialWithStatusList2021';
|
|
33
32
|
const IssueSuspendableCredentialWithStatusList2021MethodName = 'cheqdIssueSuspendableCredentialWithStatusList2021';
|
|
34
33
|
const VerifyCredentialMethodName = 'cheqdVerifyCredential';
|
|
@@ -40,8 +39,8 @@ const SuspendCredentialMethodName = 'cheqdSuspendCredential';
|
|
|
40
39
|
const SuspendCredentialsMethodName = 'cheqdSuspendCredentials';
|
|
41
40
|
const UnsuspendCredentialMethodName = 'cheqdUnsuspendCredential';
|
|
42
41
|
const UnsuspendCredentialsMethodName = 'cheqdUnsuspendCredentials';
|
|
43
|
-
const
|
|
44
|
-
const
|
|
42
|
+
const TransactSendTokensMethodName = 'cheqdTransactSendTokens';
|
|
43
|
+
const ObservePaymentConditionMethodName = 'cheqdObservePaymentCondition';
|
|
45
44
|
const DidPrefix = 'did';
|
|
46
45
|
const CheqdDidMethod = 'cheqd';
|
|
47
46
|
export class Cheqd {
|
|
@@ -239,24 +238,6 @@ export class Cheqd {
|
|
|
239
238
|
"type": "string"
|
|
240
239
|
}
|
|
241
240
|
},
|
|
242
|
-
"cheqdGenerateEncryptedStatusList2021": {
|
|
243
|
-
"description": "Generate a new encrypted Status List 2021",
|
|
244
|
-
"arguments": {
|
|
245
|
-
"type": "object",
|
|
246
|
-
"properties": {
|
|
247
|
-
"args": {
|
|
248
|
-
"type": "object",
|
|
249
|
-
"description": "A cheqdGenerateEncryptedStatusList2021Args object as any for extensibility"
|
|
250
|
-
}
|
|
251
|
-
},
|
|
252
|
-
"required": [
|
|
253
|
-
"args"
|
|
254
|
-
]
|
|
255
|
-
},
|
|
256
|
-
"returnType": {
|
|
257
|
-
"type": "string"
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
241
|
"cheqdIssueRevocableCredentialWithStatusList2021": {
|
|
261
242
|
"description": "Issue a revocable credential with a Status List 2021 as credential status registry",
|
|
262
243
|
"arguments": {
|
|
@@ -455,14 +436,14 @@ export class Cheqd {
|
|
|
455
436
|
"type": "array"
|
|
456
437
|
}
|
|
457
438
|
},
|
|
458
|
-
"
|
|
459
|
-
"description": "
|
|
439
|
+
"cheqdTransactSendTokens": {
|
|
440
|
+
"description": "Send tokens from one account to another",
|
|
460
441
|
"arguments": {
|
|
461
442
|
"type": "object",
|
|
462
443
|
"properties": {
|
|
463
444
|
"args": {
|
|
464
445
|
"type": "object",
|
|
465
|
-
"description": "A
|
|
446
|
+
"description": "A cheqdTransactSendTokensArgs object as any for extensibility"
|
|
466
447
|
}
|
|
467
448
|
},
|
|
468
449
|
"required": [
|
|
@@ -473,14 +454,14 @@ export class Cheqd {
|
|
|
473
454
|
"type": "object"
|
|
474
455
|
}
|
|
475
456
|
},
|
|
476
|
-
"
|
|
477
|
-
"description": "Observe
|
|
457
|
+
"cheqdObservePaymentCondition": {
|
|
458
|
+
"description": "Observe payment conditions for a given set of payment conditions",
|
|
478
459
|
"arguments": {
|
|
479
460
|
"type": "object",
|
|
480
461
|
"properties": {
|
|
481
462
|
"args": {
|
|
482
463
|
"type": "object",
|
|
483
|
-
"description": "
|
|
464
|
+
"description": "cheqdObservePaymentConditionArgs object as any for extensibility"
|
|
484
465
|
}
|
|
485
466
|
},
|
|
486
467
|
"required": [
|
|
@@ -519,7 +500,6 @@ export class Cheqd {
|
|
|
519
500
|
[GenerateKeyPairMethodName]: this.GenerateIdentityKeys.bind(this),
|
|
520
501
|
[GenerateVersionIdMethodName]: this.GenerateVersionId.bind(this),
|
|
521
502
|
[GenerateStatusList2021MethodName]: this.GenerateStatusList2021.bind(this),
|
|
522
|
-
[GenerateEncryptedStatusList2021MethodName]: this.GenerateEncryptedStatusList2021.bind(this),
|
|
523
503
|
[IssueRevocableCredentialWithStatusList2021MethodName]: this.IssueRevocableCredentialWithStatusList2021.bind(this),
|
|
524
504
|
[IssueSuspendableCredentialWithStatusList2021MethodName]: this.IssueSuspendableCredentialWithStatusList2021.bind(this),
|
|
525
505
|
[VerifyCredentialMethodName]: this.VerifyCredentialWithStatusList2021.bind(this),
|
|
@@ -531,8 +511,8 @@ export class Cheqd {
|
|
|
531
511
|
[SuspendCredentialsMethodName]: this.SuspendBulkCredentialsWithStatusList2021.bind(this),
|
|
532
512
|
[UnsuspendCredentialMethodName]: this.UnsuspendCredentialWithStatusList2021.bind(this),
|
|
533
513
|
[UnsuspendCredentialsMethodName]: this.UnsuspendBulkCredentialsWithStatusList2021.bind(this),
|
|
534
|
-
[
|
|
535
|
-
[
|
|
514
|
+
[TransactSendTokensMethodName]: this.TransactSendTokens.bind(this),
|
|
515
|
+
[ObservePaymentConditionMethodName]: this.ObservePaymentCondition.bind(this),
|
|
536
516
|
};
|
|
537
517
|
}
|
|
538
518
|
async CreateIdentifier(args, context) {
|
|
@@ -680,11 +660,11 @@ export class Cheqd {
|
|
|
680
660
|
if (!args?.paymentConditions || !args?.paymentConditions?.length || !Array.isArray(args?.paymentConditions) || args?.paymentConditions.length === 0) {
|
|
681
661
|
throw new Error('[did-provider-cheqd]: paymentConditions is required');
|
|
682
662
|
}
|
|
683
|
-
if (!args?.paymentConditions?.every((condition) => condition.feePaymentAddress && condition.feePaymentAmount)) {
|
|
684
|
-
throw new Error('[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount');
|
|
663
|
+
if (!args?.paymentConditions?.every((condition) => condition.feePaymentAddress && condition.feePaymentAmount && condition.intervalInSeconds)) {
|
|
664
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount and intervalInSeconds');
|
|
685
665
|
}
|
|
686
|
-
if (!args?.paymentConditions?.every((condition) => typeof condition.feePaymentAddress === 'string' && typeof condition.feePaymentAmount === 'string')) {
|
|
687
|
-
throw new Error('[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string');
|
|
666
|
+
if (!args?.paymentConditions?.every((condition) => typeof condition.feePaymentAddress === 'string' && typeof condition.feePaymentAmount === 'string' && typeof condition.intervalInSeconds === 'number')) {
|
|
667
|
+
throw new Error('[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string and intervalInSeconds must be number');
|
|
688
668
|
}
|
|
689
669
|
if (!args?.paymentConditions?.every((condition) => condition.type === AccessControlConditionTypes.timelockPayment)) {
|
|
690
670
|
throw new Error('[did-provider-cheqd]: paymentConditions must be of type timelockPayment');
|
|
@@ -694,42 +674,111 @@ export class Cheqd {
|
|
|
694
674
|
const network = args.issuerDid.split(':')[2];
|
|
695
675
|
// generate bitstring
|
|
696
676
|
const bitstring = await context.agent[GenerateStatusList2021MethodName]({ length: args?.statusListLength || Cheqd.defaultStatusList2021Length, bitstringEncoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url });
|
|
697
|
-
// construct data
|
|
677
|
+
// construct data and metadata tuple
|
|
698
678
|
const data = args.encrypted
|
|
699
|
-
? (await (async function () {
|
|
700
|
-
//
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
679
|
+
? (await (async function (that) {
|
|
680
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
681
|
+
const lit = await LitProtocol.create({
|
|
682
|
+
chain: args?.dkgOptions?.chain || that.didProvider.dkgOptions.chain,
|
|
683
|
+
litNetwork: args?.dkgOptions?.network || that.didProvider.dkgOptions.network,
|
|
684
|
+
});
|
|
685
|
+
// construct access control conditions
|
|
686
|
+
const unifiedAccessControlConditions = await Promise.all(args.paymentConditions.map(async (condition) => {
|
|
687
|
+
switch (condition.type) {
|
|
688
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
689
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
690
|
+
key: '$.tx_responses.*.timestamp',
|
|
691
|
+
comparator: '<=',
|
|
692
|
+
value: `${condition.intervalInSeconds}`,
|
|
693
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, args?.dkgOptions?.chain || that.didProvider.dkgOptions.chain);
|
|
694
|
+
default:
|
|
695
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
696
|
+
}
|
|
697
|
+
}));
|
|
698
|
+
// encrypt bitstring
|
|
699
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, unifiedAccessControlConditions, true);
|
|
700
|
+
// return result tuple
|
|
704
701
|
switch (args.statusPurpose) {
|
|
705
702
|
case DefaultStatusList2021StatusPurposeTypes.revocation:
|
|
706
|
-
return {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
703
|
+
return [{
|
|
704
|
+
StatusList2021: {
|
|
705
|
+
statusPurpose: args.statusPurpose,
|
|
706
|
+
encodedList: await blobToHexString(encryptedString),
|
|
707
|
+
validFrom: new Date().toISOString(),
|
|
708
|
+
validUntil: args?.validUntil
|
|
709
|
+
},
|
|
710
|
+
metadata: {
|
|
711
|
+
type: DefaultStatusList2021ResourceTypes.revocation,
|
|
712
|
+
encrypted: true,
|
|
713
|
+
encoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
|
|
714
|
+
encryptedSymmetricKey,
|
|
715
|
+
paymentConditions: args.paymentConditions
|
|
716
|
+
}
|
|
712
717
|
},
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
718
|
+
{
|
|
719
|
+
symmetricKey: toString(symmetricKey, 'hex'),
|
|
720
|
+
encryptedSymmetricKey,
|
|
721
|
+
encryptedString: await blobToHexString(encryptedString),
|
|
717
722
|
}
|
|
718
|
-
|
|
723
|
+
];
|
|
719
724
|
case DefaultStatusList2021StatusPurposeTypes.suspension:
|
|
720
|
-
return {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
725
|
+
return [{
|
|
726
|
+
StatusList2021: {
|
|
727
|
+
statusPurpose: args.statusPurpose,
|
|
728
|
+
encodedList: await blobToHexString(encryptedString),
|
|
729
|
+
validFrom: new Date().toISOString(),
|
|
730
|
+
validUntil: args?.validUntil
|
|
731
|
+
},
|
|
732
|
+
metadata: {
|
|
733
|
+
type: DefaultStatusList2021ResourceTypes.suspension,
|
|
734
|
+
encrypted: true,
|
|
735
|
+
encoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
|
|
736
|
+
encryptedSymmetricKey,
|
|
737
|
+
paymentConditions: args.paymentConditions
|
|
738
|
+
}
|
|
726
739
|
},
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
740
|
+
{
|
|
741
|
+
symmetricKey: toString(symmetricKey, 'hex'),
|
|
742
|
+
encryptedSymmetricKey,
|
|
743
|
+
encryptedString: await blobToHexString(encryptedString),
|
|
731
744
|
}
|
|
732
|
-
|
|
745
|
+
];
|
|
746
|
+
default:
|
|
747
|
+
throw new Error(`[did-provider-cheqd]: status purpose is not valid ${args.statusPurpose}`);
|
|
748
|
+
}
|
|
749
|
+
}(this)))
|
|
750
|
+
: (await (async function () {
|
|
751
|
+
switch (args.statusPurpose) {
|
|
752
|
+
case DefaultStatusList2021StatusPurposeTypes.revocation:
|
|
753
|
+
return [{
|
|
754
|
+
StatusList2021: {
|
|
755
|
+
statusPurpose: args.statusPurpose,
|
|
756
|
+
encodedList: bitstring,
|
|
757
|
+
validFrom: new Date().toISOString(),
|
|
758
|
+
validUntil: args?.validUntil
|
|
759
|
+
},
|
|
760
|
+
metadata: {
|
|
761
|
+
type: DefaultStatusList2021ResourceTypes.revocation,
|
|
762
|
+
encrypted: false,
|
|
763
|
+
encoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
undefined];
|
|
767
|
+
case DefaultStatusList2021StatusPurposeTypes.suspension:
|
|
768
|
+
return [{
|
|
769
|
+
StatusList2021: {
|
|
770
|
+
statusPurpose: args.statusPurpose,
|
|
771
|
+
encodedList: bitstring,
|
|
772
|
+
validFrom: new Date().toISOString(),
|
|
773
|
+
validUntil: args?.validUntil
|
|
774
|
+
},
|
|
775
|
+
metadata: {
|
|
776
|
+
type: DefaultStatusList2021ResourceTypes.suspension,
|
|
777
|
+
encrypted: false,
|
|
778
|
+
encoding: args?.statusListEncoding || DefaultStatusList2021Encodings.base64url,
|
|
779
|
+
}
|
|
780
|
+
},
|
|
781
|
+
undefined];
|
|
733
782
|
default:
|
|
734
783
|
throw new Error('[did-provider-cheqd]: statusPurpose is not valid');
|
|
735
784
|
}
|
|
@@ -742,13 +791,15 @@ export class Cheqd {
|
|
|
742
791
|
resourceType: DefaultStatusList2021ResourceTypes[args.statusPurpose],
|
|
743
792
|
version: args?.resourceVersion || new Date().toISOString(),
|
|
744
793
|
alsoKnownAs: args?.alsoKnownAs || [],
|
|
745
|
-
data: fromString(JSON.stringify(data), 'utf-8'),
|
|
794
|
+
data: fromString(JSON.stringify(data[0]), 'utf-8'),
|
|
746
795
|
};
|
|
747
796
|
// return result
|
|
748
797
|
return {
|
|
749
798
|
created: await context.agent[BroadcastStatusList2021MethodName]({ kms: args.kms, payload, network: network }),
|
|
750
|
-
|
|
751
|
-
resourceMetadata: await Cheqd.fetchStatusList2021Metadata({ credentialStatus: { id: `${resolverUrl}${args.issuerDid}?resourceName=${args.statusListName}&resourceType=${DefaultStatusList2021ResourceTypes[args.statusPurpose]}`, type: 'StatusList2021Entry' } })
|
|
799
|
+
resource: data[0],
|
|
800
|
+
resourceMetadata: await Cheqd.fetchStatusList2021Metadata({ credentialStatus: { id: `${resolverUrl}${args.issuerDid}?resourceName=${args.statusListName}&resourceType=${DefaultStatusList2021ResourceTypes[args.statusPurpose]}`, type: 'StatusList2021Entry' } }),
|
|
801
|
+
encrypted: args.encrypted,
|
|
802
|
+
symmetricKey: args?.returnSymmetricKey ? data[1]?.symmetricKey : undefined,
|
|
752
803
|
};
|
|
753
804
|
}
|
|
754
805
|
async BroadcastStatusList2021(args, context) {
|
|
@@ -875,54 +926,6 @@ export class Cheqd {
|
|
|
875
926
|
return encoded;
|
|
876
927
|
}
|
|
877
928
|
}
|
|
878
|
-
async GenerateEncryptedStatusList2021(args, context) {
|
|
879
|
-
// validate encryptionOptions
|
|
880
|
-
if (!args.encryptionOptions) {
|
|
881
|
-
throw new Error('[did-provider-cheqd]: encryptionOptions is required');
|
|
882
|
-
}
|
|
883
|
-
// validate encryptionOptions.accessControlConditions
|
|
884
|
-
if (!args.encryptionOptions.accessControlConditions) {
|
|
885
|
-
throw new Error('[did-provider-cheqd]: encryptionOptions.accessControlConditions is required');
|
|
886
|
-
}
|
|
887
|
-
// generate status list
|
|
888
|
-
const statusList = args?.buffer
|
|
889
|
-
? new StatusList({ buffer: args.buffer })
|
|
890
|
-
: new StatusList({ length: args?.length || Cheqd.defaultStatusList2021Length });
|
|
891
|
-
// encode status list
|
|
892
|
-
const encoded = await statusList.encode();
|
|
893
|
-
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
894
|
-
const lit = await LitProtocol.create({
|
|
895
|
-
chain: args.bootstrapOptions.chain,
|
|
896
|
-
litNetwork: args.bootstrapOptions.litNetwork,
|
|
897
|
-
});
|
|
898
|
-
// construct access control conditions
|
|
899
|
-
const unifiedAccessControlConditions = await Promise.all(args.encryptionOptions.accessControlConditions.map(async (condition) => {
|
|
900
|
-
switch (condition.type) {
|
|
901
|
-
case AccessControlConditionTypes.memoNonce:
|
|
902
|
-
return await LitProtocol.generateCosmosAccessControlConditionTransactionMemo({
|
|
903
|
-
key: '$.txs.*.body.memo',
|
|
904
|
-
comparator: 'contains',
|
|
905
|
-
value: condition?.specificNonce || await LitProtocol.generateTxNonce(condition?.nonceFormat)
|
|
906
|
-
}, condition.amountObserved, condition.senderAddressObserved, condition.recipientAddressObserved, args.bootstrapOptions.chain);
|
|
907
|
-
case AccessControlConditionTypes.balance:
|
|
908
|
-
return await LitProtocol.generateCosmosAccessControlConditionBalance({
|
|
909
|
-
key: '$.balances[0].amount',
|
|
910
|
-
comparator: condition.comparator,
|
|
911
|
-
value: condition.amountObserved
|
|
912
|
-
}, args.bootstrapOptions.chain, condition.addressObserved);
|
|
913
|
-
default:
|
|
914
|
-
throw new Error(`[did-provider-cheqd]: accessControlCondition type is not supported`);
|
|
915
|
-
}
|
|
916
|
-
}));
|
|
917
|
-
// encrypt data
|
|
918
|
-
const { encryptedString, encryptedSymmetricKey } = await lit.encrypt(encoded, unifiedAccessControlConditions);
|
|
919
|
-
// return result
|
|
920
|
-
return {
|
|
921
|
-
encryptedStatusList2021: await blobToHexString(encryptedString),
|
|
922
|
-
encryptedSymmetricKey,
|
|
923
|
-
unifiedAccessControlConditions
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
929
|
async IssueRevocableCredentialWithStatusList2021(args, context) {
|
|
927
930
|
// generate index
|
|
928
931
|
const statusListIndex = args.statusOptions.statusListIndex || await randomFromRange(args.statusOptions.statusListRangeStart || 0, (args.statusOptions.statusListRangeEnd || Cheqd.defaultStatusList2021Length) - 1, args.statusOptions.indexNotIn || []);
|
|
@@ -1021,6 +1024,8 @@ export class Cheqd {
|
|
|
1021
1024
|
}
|
|
1022
1025
|
// if jwt credential, decode it
|
|
1023
1026
|
const credential = typeof args.credential === 'string' ? await Cheqd.decodeCredentialJWT(args.credential) : args.credential;
|
|
1027
|
+
// define dkg options, if provided
|
|
1028
|
+
args.dkgOptions ||= this.didProvider.dkgOptions;
|
|
1024
1029
|
// verify credential status
|
|
1025
1030
|
switch (credential.credentialStatus?.statusPurpose) {
|
|
1026
1031
|
case 'revocation':
|
|
@@ -1049,8 +1054,11 @@ export class Cheqd {
|
|
|
1049
1054
|
if (!verificationResult.verified) {
|
|
1050
1055
|
return { verified: false, error: verificationResult.error };
|
|
1051
1056
|
}
|
|
1057
|
+
// early return if no verifiable credentials are provided
|
|
1052
1058
|
if (!args.presentation.verifiableCredential)
|
|
1053
1059
|
throw new Error('[did-provider-cheqd]: verify presentation: presentation.verifiableCredential is required');
|
|
1060
|
+
// define dkg options, if provided
|
|
1061
|
+
args.dkgOptions ||= this.didProvider.dkgOptions;
|
|
1054
1062
|
// verify credential(s) status(es)
|
|
1055
1063
|
for (let credential of args.presentation.verifiableCredential) {
|
|
1056
1064
|
// if jwt credential, decode it
|
|
@@ -1123,6 +1131,8 @@ export class Cheqd {
|
|
|
1123
1131
|
throw new Error('[did-provider-cheqd]: revocation: credential is required');
|
|
1124
1132
|
// if jwt credential, decode it
|
|
1125
1133
|
const credential = typeof args.credential === 'string' ? await Cheqd.decodeCredentialJWT(args.credential) : args.credential;
|
|
1134
|
+
// define dkg options, if provided
|
|
1135
|
+
args.dkgOptions ||= this.didProvider.dkgOptions;
|
|
1126
1136
|
switch (credential.credentialStatus?.statusPurpose) {
|
|
1127
1137
|
case 'revocation':
|
|
1128
1138
|
if (await Cheqd.checkRevoked(credential, { ...args.options, topArgs: args }))
|
|
@@ -1203,6 +1213,8 @@ export class Cheqd {
|
|
|
1203
1213
|
if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
|
|
1204
1214
|
throw new Error('[did-provider-cheqd]: revocation: publish requires statusListFile or statusList, if fetchList is disabled');
|
|
1205
1215
|
}
|
|
1216
|
+
// define dkg options, if provided
|
|
1217
|
+
args.dkgOptions ||= this.didProvider.dkgOptions;
|
|
1206
1218
|
// revoke credential
|
|
1207
1219
|
return await Cheqd.revokeCredential(credential, {
|
|
1208
1220
|
...args.options,
|
|
@@ -1285,6 +1297,8 @@ export class Cheqd {
|
|
|
1285
1297
|
if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
|
|
1286
1298
|
throw new Error('[did-provider-cheqd]: revocation: publish requires statusListFile or statusList, if fetchList is disabled');
|
|
1287
1299
|
}
|
|
1300
|
+
// define dkg options, if provided
|
|
1301
|
+
args.dkgOptions ||= this.didProvider.dkgOptions;
|
|
1288
1302
|
// revoke credentials
|
|
1289
1303
|
return await Cheqd.revokeCredentials(credentials, {
|
|
1290
1304
|
...args.options,
|
|
@@ -1625,13 +1639,13 @@ export class Cheqd {
|
|
|
1625
1639
|
}
|
|
1626
1640
|
});
|
|
1627
1641
|
}
|
|
1628
|
-
async
|
|
1642
|
+
async TransactSendTokens(args, context) {
|
|
1629
1643
|
try {
|
|
1630
1644
|
// delegate to provider
|
|
1631
1645
|
const transactionResult = await this.didProvider.transactSendTokens({
|
|
1632
1646
|
recipientAddress: args.recipientAddress,
|
|
1633
1647
|
amount: args.amount,
|
|
1634
|
-
|
|
1648
|
+
memo: args.memo,
|
|
1635
1649
|
txBytes: args.txBytes,
|
|
1636
1650
|
});
|
|
1637
1651
|
// return transaction result
|
|
@@ -1651,9 +1665,27 @@ export class Cheqd {
|
|
|
1651
1665
|
};
|
|
1652
1666
|
}
|
|
1653
1667
|
}
|
|
1654
|
-
async
|
|
1655
|
-
// verify with raw unified access control
|
|
1668
|
+
async ObservePaymentCondition(args, context) {
|
|
1669
|
+
// verify with raw unified access control condition, if any
|
|
1656
1670
|
if (args?.unifiedAccessControlCondition) {
|
|
1671
|
+
// validate args - case: unifiedAccessControlCondition.chain
|
|
1672
|
+
if (!args.unifiedAccessControlCondition.chain || !Object.values(LitCompatibleCosmosChains).includes(args.unifiedAccessControlCondition.chain))
|
|
1673
|
+
throw new Error('[did-provider-cheqd]: observe: unifiedAccessControlCondition.chain is required and must be a valid Lit-compatible chain');
|
|
1674
|
+
// validate args - case: unifiedAccessControlCondition.path
|
|
1675
|
+
if (!args.unifiedAccessControlCondition.path)
|
|
1676
|
+
throw new Error('[did-provider-cheqd]: observe: unifiedAccessControlCondition.path is required');
|
|
1677
|
+
// validate args - case: unifiedAccessControlCondition.conditionType
|
|
1678
|
+
if (args.unifiedAccessControlCondition.conditionType !== 'cosmos')
|
|
1679
|
+
throw new Error('[did-provider-cheqd]: observe: unifiedAccessControlCondition.conditionType must be cosmos');
|
|
1680
|
+
// validate args - case: unifiedAccessControlCondition.method
|
|
1681
|
+
if (args.unifiedAccessControlCondition.method !== 'timelock')
|
|
1682
|
+
throw new Error('[did-provider-cheqd]: observe: unifiedAccessControlCondition.method must be timelock');
|
|
1683
|
+
// validate args - case: unifiedAccessControlCondition.parameters
|
|
1684
|
+
if (!args.unifiedAccessControlCondition.parameters || !Array.isArray(args.unifiedAccessControlCondition.parameters) || args.unifiedAccessControlCondition.parameters.length === 0 || args.unifiedAccessControlCondition.parameters.length > 1)
|
|
1685
|
+
throw new Error('[did-provider-cheqd]: observe: unifiedAccessControlCondition.parameters is required and must be an array of length 1 of type string content');
|
|
1686
|
+
// validate args - case: unifiedAccessControlCondition.returnValueTest
|
|
1687
|
+
if (!args.unifiedAccessControlCondition.returnValueTest || !args.unifiedAccessControlCondition.returnValueTest.comparator || !args.unifiedAccessControlCondition.returnValueTest.key || !args.unifiedAccessControlCondition.returnValueTest.value)
|
|
1688
|
+
throw new Error('[did-provider-cheqd]: observe: unifiedAccessControlCondition.returnValueTest is required');
|
|
1657
1689
|
try {
|
|
1658
1690
|
// define network
|
|
1659
1691
|
const network = (function () {
|
|
@@ -1666,12 +1698,39 @@ export class Cheqd {
|
|
|
1666
1698
|
throw new Error(`[did-provider-cheqd]: observe: Unsupported chain: ${args.unifiedAccessControlCondition.chain}`);
|
|
1667
1699
|
}
|
|
1668
1700
|
}());
|
|
1701
|
+
// get block height url
|
|
1702
|
+
const blockHeightUrl = function () {
|
|
1703
|
+
switch (args.unifiedAccessControlCondition.parameters[0]) {
|
|
1704
|
+
case 'latest':
|
|
1705
|
+
return `${DefaultRESTUrls[network]}/cosmos/base/tendermint/v1beta1/blocks/latest`;
|
|
1706
|
+
default:
|
|
1707
|
+
return `${DefaultRESTUrls[network]}/cosmos/base/tendermint/v1beta1/blocks/${args.unifiedAccessControlCondition.parameters[0]}`;
|
|
1708
|
+
}
|
|
1709
|
+
}();
|
|
1710
|
+
// fetch block response
|
|
1711
|
+
const blockHeightResponse = await (await fetch(blockHeightUrl)).json();
|
|
1712
|
+
// get timestamp from block response
|
|
1713
|
+
const blockTimestamp = Date.parse(blockHeightResponse.block.header.time);
|
|
1669
1714
|
// construct url
|
|
1670
1715
|
const url = `${DefaultRESTUrls[network]}${args.unifiedAccessControlCondition.path}`;
|
|
1671
1716
|
// fetch relevant txs
|
|
1672
1717
|
const txs = await (await fetch(url)).json();
|
|
1673
|
-
// skim through txs for relevant events, in which case
|
|
1674
|
-
const meetsConditionTxIndex = txs?.
|
|
1718
|
+
// skim through txs for relevant events, in which case the transaction timestamp is within the defined interval in seconds, from the block timestamp
|
|
1719
|
+
const meetsConditionTxIndex = txs?.tx_responses?.findIndex((tx) => {
|
|
1720
|
+
// get tx timestamp
|
|
1721
|
+
const txTimestamp = Date.parse(tx.timestamp);
|
|
1722
|
+
// calculate diff in seconds
|
|
1723
|
+
const diffInSeconds = Math.floor((blockTimestamp - txTimestamp) / 1000);
|
|
1724
|
+
// return meets condition
|
|
1725
|
+
switch (args.unifiedAccessControlCondition.returnValueTest.comparator) {
|
|
1726
|
+
case '<':
|
|
1727
|
+
return diffInSeconds < parseInt(args.unifiedAccessControlCondition.returnValueTest.value);
|
|
1728
|
+
case '<=':
|
|
1729
|
+
return diffInSeconds <= parseInt(args.unifiedAccessControlCondition.returnValueTest.value);
|
|
1730
|
+
default:
|
|
1731
|
+
throw new Error(`[did-provider-cheqd]: observe: Unsupported comparator: ${args.unifiedAccessControlCondition.returnValueTest.comparator}`);
|
|
1732
|
+
}
|
|
1733
|
+
});
|
|
1675
1734
|
// define meetsCondition
|
|
1676
1735
|
const meetsCondition = (typeof meetsConditionTxIndex !== 'undefined' && meetsConditionTxIndex !== -1);
|
|
1677
1736
|
// return observation result
|
|
@@ -1693,10 +1752,6 @@ export class Cheqd {
|
|
|
1693
1752
|
};
|
|
1694
1753
|
}
|
|
1695
1754
|
}
|
|
1696
|
-
// validate access control conditions components - case: senderAddress
|
|
1697
|
-
if (!args.senderAddress) {
|
|
1698
|
-
throw new Error('[did-provider-cheqd]: observation: senderAddress is required');
|
|
1699
|
-
}
|
|
1700
1755
|
// validate access control conditions components - case: recipientAddress
|
|
1701
1756
|
if (!args.recipientAddress) {
|
|
1702
1757
|
throw new Error('[did-provider-cheqd]: observation: recipientAddress is required');
|
|
@@ -1705,21 +1760,54 @@ export class Cheqd {
|
|
|
1705
1760
|
if (!args.amount || !args.amount.amount || !args.amount.denom || args.amount.denom !== 'ncheq') {
|
|
1706
1761
|
throw new Error('[did-provider-cheqd]: observation: amount is required, and must be an object with amount and denom valid string properties, amongst which denom must be `ncheq`');
|
|
1707
1762
|
}
|
|
1708
|
-
// validate access control conditions components - case:
|
|
1709
|
-
if (!args.
|
|
1710
|
-
throw new Error('[did-provider-cheqd]: observation:
|
|
1763
|
+
// validate access control conditions components - case: intervalInSeconds
|
|
1764
|
+
if (!args.intervalInSeconds) {
|
|
1765
|
+
throw new Error('[did-provider-cheqd]: observation: intervalInSeconds is required');
|
|
1766
|
+
}
|
|
1767
|
+
// validate access control conditions components - case: comparator
|
|
1768
|
+
if (!args.comparator || (args.comparator !== '<' && args.comparator !== '<=')) {
|
|
1769
|
+
throw new Error('[did-provider-cheqd]: observation: comparator is required and must be either `<` or `<=`');
|
|
1711
1770
|
}
|
|
1712
1771
|
// validate access control conditions components - case: network
|
|
1713
1772
|
if (!args.network) {
|
|
1714
1773
|
throw new Error('[did-provider-cheqd]: observation: network is required');
|
|
1715
1774
|
}
|
|
1775
|
+
// define block height, if not provided
|
|
1776
|
+
args.blockHeight ||= 'latest';
|
|
1716
1777
|
try {
|
|
1778
|
+
// get block height url
|
|
1779
|
+
const blockHeightUrl = function () {
|
|
1780
|
+
switch (args.blockHeight) {
|
|
1781
|
+
case 'latest':
|
|
1782
|
+
return `${DefaultRESTUrls[args.network]}/cosmos/base/tendermint/v1beta1/blocks/latest`;
|
|
1783
|
+
default:
|
|
1784
|
+
return `${DefaultRESTUrls[args.network]}/cosmos/base/tendermint/v1beta1/blocks/${args.blockHeight}`;
|
|
1785
|
+
}
|
|
1786
|
+
}();
|
|
1787
|
+
// fetch block response
|
|
1788
|
+
const blockHeightResponse = await (await fetch(blockHeightUrl)).json();
|
|
1789
|
+
// get timestamp from block response
|
|
1790
|
+
const blockTimestamp = Date.parse(blockHeightResponse.block.header.time);
|
|
1717
1791
|
// otherwise, construct url, as per components
|
|
1718
|
-
const url = `${DefaultRESTUrls[args.network]}/cosmos/tx/v1beta1/txs?events=transfer.recipient='${args.recipientAddress}'&events=transfer.
|
|
1792
|
+
const url = `${DefaultRESTUrls[args.network]}/cosmos/tx/v1beta1/txs?events=transfer.recipient='${args.recipientAddress}'&events=transfer.amount='${args.amount.amount}${args.amount.denom}'&order_by=2&pagination.limit=1`;
|
|
1719
1793
|
// fetch relevant txs
|
|
1720
1794
|
const txs = await (await fetch(url)).json();
|
|
1721
|
-
// skim through txs for relevant events, in which case
|
|
1722
|
-
const meetsConditionTxIndex = txs?.
|
|
1795
|
+
// skim through txs for relevant events, in which case the transaction timestamp is within the defined interval in seconds, from the block timestamp
|
|
1796
|
+
const meetsConditionTxIndex = txs?.tx_responses?.findIndex((tx) => {
|
|
1797
|
+
// get tx timestamp
|
|
1798
|
+
const txTimestamp = Date.parse(tx.timestamp);
|
|
1799
|
+
// calculate diff in seconds
|
|
1800
|
+
const diffInSeconds = Math.floor((blockTimestamp - txTimestamp) / 1000);
|
|
1801
|
+
// return meets condition
|
|
1802
|
+
switch (args.comparator) {
|
|
1803
|
+
case '<':
|
|
1804
|
+
return diffInSeconds < args.intervalInSeconds;
|
|
1805
|
+
case '<=':
|
|
1806
|
+
return diffInSeconds <= args.intervalInSeconds;
|
|
1807
|
+
default:
|
|
1808
|
+
throw new Error(`[did-provider-cheqd]: observe: Unsupported comparator: ${args.unifiedAccessControlCondition.returnValueTest.comparator}`);
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
1723
1811
|
// define meetsCondition
|
|
1724
1812
|
const meetsCondition = (typeof meetsConditionTxIndex !== 'undefined' && meetsConditionTxIndex !== -1);
|
|
1725
1813
|
// return observation result
|
|
@@ -1759,8 +1847,8 @@ export class Cheqd {
|
|
|
1759
1847
|
return publishedList.metadata.encoding === 'base64url'
|
|
1760
1848
|
? publishedList.StatusList2021.encodedList
|
|
1761
1849
|
: toString(fromString(publishedList.StatusList2021.encodedList, publishedList.metadata.encoding), 'base64url');
|
|
1762
|
-
// otherwise, decrypt and return bitstring
|
|
1763
|
-
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList,
|
|
1850
|
+
// otherwise, decrypt and return raw bitstring
|
|
1851
|
+
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList, 'hex'));
|
|
1764
1852
|
// decrypt
|
|
1765
1853
|
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
1766
1854
|
}())
|
|
@@ -1822,16 +1910,111 @@ export class Cheqd {
|
|
|
1822
1910
|
// publish status list 2021 as new version
|
|
1823
1911
|
const scoped = topArgs.publishEncrypted
|
|
1824
1912
|
? (await async function () {
|
|
1913
|
+
// validate encoding, if provided
|
|
1914
|
+
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
1915
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list encoding');
|
|
1916
|
+
}
|
|
1917
|
+
// validate validUntil, if provided
|
|
1918
|
+
if (options?.publishOptions?.statusListValidUntil) {
|
|
1919
|
+
// validate validUntil as string
|
|
1920
|
+
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
1921
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list validUntil (must be string)');
|
|
1922
|
+
// validate validUntil as date
|
|
1923
|
+
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
1924
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list validUntil (must be date)');
|
|
1925
|
+
// validate validUntil as future date
|
|
1926
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
1927
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list validUntil (must be future date)');
|
|
1928
|
+
// validate validUntil towards validFrom
|
|
1929
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
1930
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list validUntil (must be after validFrom)');
|
|
1931
|
+
}
|
|
1932
|
+
// validate paymentConditions, if provided
|
|
1933
|
+
if (topArgs?.paymentConditions) {
|
|
1934
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.feePaymentAddress && condition.feePaymentAmount && condition.intervalInSeconds)) {
|
|
1935
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount and intervalInSeconds');
|
|
1936
|
+
}
|
|
1937
|
+
if (!topArgs?.paymentConditions?.every((condition) => typeof condition.feePaymentAddress === 'string' && typeof condition.feePaymentAmount === 'string' && typeof condition.intervalInSeconds === 'number')) {
|
|
1938
|
+
throw new Error('[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string and intervalInSeconds must be number');
|
|
1939
|
+
}
|
|
1940
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.type === AccessControlConditionTypes.timelockPayment)) {
|
|
1941
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must be of type timelockPayment');
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
// validate dkgOptions
|
|
1945
|
+
if (!topArgs?.dkgOptions || !topArgs?.dkgOptions?.chain || !topArgs?.dkgOptions?.network) {
|
|
1946
|
+
throw new Error('[did-provider-cheqd]: dkgOptions is required');
|
|
1947
|
+
}
|
|
1825
1948
|
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
1826
1949
|
const lit = await LitProtocol.create({
|
|
1827
|
-
chain:
|
|
1828
|
-
litNetwork:
|
|
1950
|
+
chain: topArgs?.dkgOptions?.chain,
|
|
1951
|
+
litNetwork: topArgs?.dkgOptions?.network
|
|
1829
1952
|
});
|
|
1830
|
-
//
|
|
1831
|
-
const
|
|
1953
|
+
// construct access control conditions and payment conditions tuple
|
|
1954
|
+
const unifiedAccessControlConditionsTuple = publishedList.metadata.encrypted
|
|
1955
|
+
? (await (async function () {
|
|
1956
|
+
// define payment conditions, give precedence to top-level args
|
|
1957
|
+
const paymentConditions = topArgs?.paymentConditions || publishedList.metadata.paymentConditions;
|
|
1958
|
+
// return access control conditions and payment conditions tuple
|
|
1959
|
+
return [
|
|
1960
|
+
await Promise.all(paymentConditions.map(async (condition) => {
|
|
1961
|
+
switch (condition.type) {
|
|
1962
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
1963
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
1964
|
+
key: '$.tx_responses.*.timestamp',
|
|
1965
|
+
comparator: '<=',
|
|
1966
|
+
value: `${condition.intervalInSeconds}`,
|
|
1967
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, topArgs?.dkgOptions?.chain);
|
|
1968
|
+
default:
|
|
1969
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
1970
|
+
}
|
|
1971
|
+
})),
|
|
1972
|
+
paymentConditions
|
|
1973
|
+
];
|
|
1974
|
+
}()))
|
|
1975
|
+
: (await (async function () {
|
|
1976
|
+
// validate paymentConditions
|
|
1977
|
+
if (!topArgs?.paymentConditions) {
|
|
1978
|
+
throw new Error('[did-provider-cheqd]: paymentConditions is required');
|
|
1979
|
+
}
|
|
1980
|
+
// return access control conditions and payment conditions tuple
|
|
1981
|
+
return [
|
|
1982
|
+
await Promise.all(topArgs.paymentConditions.map(async (condition) => {
|
|
1983
|
+
switch (condition.type) {
|
|
1984
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
1985
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
1986
|
+
key: '$.tx_responses.*.timestamp',
|
|
1987
|
+
comparator: '<=',
|
|
1988
|
+
value: `${condition.intervalInSeconds}`,
|
|
1989
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight);
|
|
1990
|
+
default:
|
|
1991
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
1992
|
+
}
|
|
1993
|
+
})),
|
|
1994
|
+
topArgs.paymentConditions
|
|
1995
|
+
];
|
|
1996
|
+
}()));
|
|
1997
|
+
// encrypt bitstring
|
|
1998
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, unifiedAccessControlConditionsTuple[0], true);
|
|
1999
|
+
// define status list content
|
|
2000
|
+
const content = {
|
|
2001
|
+
StatusList2021: {
|
|
2002
|
+
statusPurpose: publishedList.StatusList2021.statusPurpose,
|
|
2003
|
+
encodedList: await blobToHexString(encryptedString),
|
|
2004
|
+
validFrom: publishedList.StatusList2021.validFrom,
|
|
2005
|
+
validUntil: options?.publishOptions?.statusListValidUntil || publishedList.StatusList2021.validUntil
|
|
2006
|
+
},
|
|
2007
|
+
metadata: {
|
|
2008
|
+
type: publishedList.metadata.type,
|
|
2009
|
+
encrypted: true,
|
|
2010
|
+
encoding: options?.publishOptions?.statusListEncoding || publishedList.metadata.encoding,
|
|
2011
|
+
encryptedSymmetricKey,
|
|
2012
|
+
paymentConditions: unifiedAccessControlConditionsTuple[1]
|
|
2013
|
+
}
|
|
2014
|
+
};
|
|
1832
2015
|
// return tuple of publish result and encryption relevant metadata
|
|
1833
2016
|
return [
|
|
1834
|
-
await Cheqd.publishStatusList2021(
|
|
2017
|
+
await Cheqd.publishStatusList2021(fromString(JSON.stringify(content), 'utf-8'), statusListMetadata, options?.publishOptions),
|
|
1835
2018
|
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
1836
2019
|
];
|
|
1837
2020
|
}())
|
|
@@ -1886,8 +2069,6 @@ export class Cheqd {
|
|
|
1886
2069
|
revoked: true,
|
|
1887
2070
|
published: topArgs?.publish ? true : undefined,
|
|
1888
2071
|
statusList: topArgs?.returnUpdatedStatusList ? await Cheqd.fetchStatusList2021(credential) : undefined,
|
|
1889
|
-
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
1890
|
-
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
1891
2072
|
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
1892
2073
|
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
|
|
1893
2074
|
};
|
|
@@ -1945,8 +2126,8 @@ export class Cheqd {
|
|
|
1945
2126
|
return publishedList.metadata.encoding === 'base64url'
|
|
1946
2127
|
? publishedList.StatusList2021.encodedList
|
|
1947
2128
|
: toString(fromString(publishedList.StatusList2021.encodedList, publishedList.metadata.encoding), 'base64url');
|
|
1948
|
-
// otherwise, decrypt and return bitstring
|
|
1949
|
-
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList,
|
|
2129
|
+
// otherwise, decrypt and return raw bitstring
|
|
2130
|
+
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList, 'hex'));
|
|
1950
2131
|
// decrypt
|
|
1951
2132
|
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
1952
2133
|
}())
|
|
@@ -2021,16 +2202,111 @@ export class Cheqd {
|
|
|
2021
2202
|
// publish status list 2021 as new version
|
|
2022
2203
|
const scoped = topArgs.publishEncrypted
|
|
2023
2204
|
? (await async function () {
|
|
2205
|
+
// validate encoding, if provided
|
|
2206
|
+
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
2207
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list encoding');
|
|
2208
|
+
}
|
|
2209
|
+
// validate validUntil, if provided
|
|
2210
|
+
if (options?.publishOptions?.statusListValidUntil) {
|
|
2211
|
+
// validate validUntil as string
|
|
2212
|
+
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
2213
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list validUntil (must be string)');
|
|
2214
|
+
// validate validUntil as date
|
|
2215
|
+
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
2216
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list validUntil (must be date)');
|
|
2217
|
+
// validate validUntil as future date
|
|
2218
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
2219
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list validUntil (must be future date)');
|
|
2220
|
+
// validate validUntil towards validFrom
|
|
2221
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
2222
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status list validUntil (must be after validFrom)');
|
|
2223
|
+
}
|
|
2224
|
+
// validate paymentConditions, if provided
|
|
2225
|
+
if (topArgs?.paymentConditions) {
|
|
2226
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.feePaymentAddress && condition.feePaymentAmount && condition.intervalInSeconds)) {
|
|
2227
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount and intervalInSeconds');
|
|
2228
|
+
}
|
|
2229
|
+
if (!topArgs?.paymentConditions?.every((condition) => typeof condition.feePaymentAddress === 'string' && typeof condition.feePaymentAmount === 'string' && typeof condition.intervalInSeconds === 'number')) {
|
|
2230
|
+
throw new Error('[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string and intervalInSeconds must be number');
|
|
2231
|
+
}
|
|
2232
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.type === AccessControlConditionTypes.timelockPayment)) {
|
|
2233
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must be of type timelockPayment');
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
// validate dkgOptions
|
|
2237
|
+
if (!topArgs?.dkgOptions || !topArgs?.dkgOptions?.chain || !topArgs?.dkgOptions?.network) {
|
|
2238
|
+
throw new Error('[did-provider-cheqd]: dkgOptions is required');
|
|
2239
|
+
}
|
|
2024
2240
|
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
2025
2241
|
const lit = await LitProtocol.create({
|
|
2026
|
-
chain:
|
|
2027
|
-
litNetwork:
|
|
2242
|
+
chain: topArgs?.dkgOptions?.chain,
|
|
2243
|
+
litNetwork: topArgs?.dkgOptions?.network
|
|
2028
2244
|
});
|
|
2029
|
-
//
|
|
2030
|
-
const
|
|
2245
|
+
// construct access control conditions and payment conditions tuple
|
|
2246
|
+
const unifiedAccessControlConditionsTuple = publishedList.metadata.encrypted
|
|
2247
|
+
? (await (async function () {
|
|
2248
|
+
// define payment conditions, give precedence to top-level args
|
|
2249
|
+
const paymentConditions = topArgs?.paymentConditions || publishedList.metadata.paymentConditions;
|
|
2250
|
+
// return access control conditions and payment conditions tuple
|
|
2251
|
+
return [
|
|
2252
|
+
await Promise.all(paymentConditions.map(async (condition) => {
|
|
2253
|
+
switch (condition.type) {
|
|
2254
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
2255
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
2256
|
+
key: '$.tx_responses.*.timestamp',
|
|
2257
|
+
comparator: '<=',
|
|
2258
|
+
value: `${condition.intervalInSeconds}`,
|
|
2259
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, topArgs?.dkgOptions?.chain);
|
|
2260
|
+
default:
|
|
2261
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
2262
|
+
}
|
|
2263
|
+
})),
|
|
2264
|
+
paymentConditions
|
|
2265
|
+
];
|
|
2266
|
+
}()))
|
|
2267
|
+
: (await (async function () {
|
|
2268
|
+
// validate paymentConditions
|
|
2269
|
+
if (!topArgs?.paymentConditions) {
|
|
2270
|
+
throw new Error('[did-provider-cheqd]: paymentConditions is required');
|
|
2271
|
+
}
|
|
2272
|
+
// return access control conditions and payment conditions tuple
|
|
2273
|
+
return [
|
|
2274
|
+
await Promise.all(topArgs.paymentConditions.map(async (condition) => {
|
|
2275
|
+
switch (condition.type) {
|
|
2276
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
2277
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
2278
|
+
key: '$.tx_responses.*.timestamp',
|
|
2279
|
+
comparator: '<=',
|
|
2280
|
+
value: `${condition.intervalInSeconds}`,
|
|
2281
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight);
|
|
2282
|
+
default:
|
|
2283
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
2284
|
+
}
|
|
2285
|
+
})),
|
|
2286
|
+
topArgs.paymentConditions
|
|
2287
|
+
];
|
|
2288
|
+
}()));
|
|
2289
|
+
// encrypt bitstring
|
|
2290
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, unifiedAccessControlConditionsTuple[0], true);
|
|
2291
|
+
// define status list content
|
|
2292
|
+
const content = {
|
|
2293
|
+
StatusList2021: {
|
|
2294
|
+
statusPurpose: publishedList.StatusList2021.statusPurpose,
|
|
2295
|
+
encodedList: await blobToHexString(encryptedString),
|
|
2296
|
+
validFrom: publishedList.StatusList2021.validFrom,
|
|
2297
|
+
validUntil: options?.publishOptions?.statusListValidUntil || publishedList.StatusList2021.validUntil
|
|
2298
|
+
},
|
|
2299
|
+
metadata: {
|
|
2300
|
+
type: publishedList.metadata.type,
|
|
2301
|
+
encrypted: true,
|
|
2302
|
+
encoding: options?.publishOptions?.statusListEncoding || publishedList.metadata.encoding,
|
|
2303
|
+
encryptedSymmetricKey,
|
|
2304
|
+
paymentConditions: unifiedAccessControlConditionsTuple[1]
|
|
2305
|
+
}
|
|
2306
|
+
};
|
|
2031
2307
|
// return tuple of publish result and encryption relevant metadata
|
|
2032
2308
|
return [
|
|
2033
|
-
await Cheqd.publishStatusList2021(
|
|
2309
|
+
await Cheqd.publishStatusList2021(fromString(JSON.stringify(content), 'utf-8'), statusListMetadata, options?.publishOptions),
|
|
2034
2310
|
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
2035
2311
|
];
|
|
2036
2312
|
}())
|
|
@@ -2085,8 +2361,6 @@ export class Cheqd {
|
|
|
2085
2361
|
revoked: revoked.map((result) => result.status === 'fulfilled' ? result.value.revoked : false),
|
|
2086
2362
|
published: topArgs?.publish ? true : undefined,
|
|
2087
2363
|
statusList: topArgs?.returnUpdatedStatusList ? await Cheqd.fetchStatusList2021(credentials[0]) : undefined,
|
|
2088
|
-
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
2089
|
-
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
2090
2364
|
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
2091
2365
|
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credentials[0]) : undefined
|
|
2092
2366
|
};
|
|
@@ -2115,8 +2389,8 @@ export class Cheqd {
|
|
|
2115
2389
|
return publishedList.metadata.encoding === 'base64url'
|
|
2116
2390
|
? publishedList.StatusList2021.encodedList
|
|
2117
2391
|
: toString(fromString(publishedList.StatusList2021.encodedList, publishedList.metadata.encoding), 'base64url');
|
|
2118
|
-
// otherwise, decrypt and return bitstring
|
|
2119
|
-
const scopedRawBlob = await toBlob(
|
|
2392
|
+
// otherwise, decrypt and return raw bitstring
|
|
2393
|
+
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList, 'hex'));
|
|
2120
2394
|
// decrypt
|
|
2121
2395
|
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2122
2396
|
}())
|
|
@@ -2133,7 +2407,7 @@ export class Cheqd {
|
|
|
2133
2407
|
const encoded = new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
2134
2408
|
// validate against published list
|
|
2135
2409
|
if (encoded !== publishedListTranscoded)
|
|
2136
|
-
throw new Error('[did-provider-cheqd]:
|
|
2410
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListFile does not match published status list 2021');
|
|
2137
2411
|
// return encoded
|
|
2138
2412
|
return encoded;
|
|
2139
2413
|
}
|
|
@@ -2143,15 +2417,15 @@ export class Cheqd {
|
|
|
2143
2417
|
const decrypted = await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2144
2418
|
// validate against published list
|
|
2145
2419
|
if (decrypted !== publishedListTranscoded)
|
|
2146
|
-
throw new Error('[did-provider-cheqd]:
|
|
2420
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListFile does not match published status list 2021');
|
|
2147
2421
|
// return decrypted
|
|
2148
2422
|
return decrypted;
|
|
2149
2423
|
}
|
|
2150
2424
|
if (!options?.statusListInlineBitstring)
|
|
2151
|
-
throw new Error('[did-provider-cheqd]:
|
|
2425
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
2152
2426
|
// validate against published list
|
|
2153
2427
|
if (options?.statusListInlineBitstring !== publishedListTranscoded)
|
|
2154
|
-
throw new Error('[did-provider-cheqd]:
|
|
2428
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListInlineBitstring does not match published status list 2021');
|
|
2155
2429
|
// otherwise, read from inline bitstring
|
|
2156
2430
|
return options?.statusListInlineBitstring;
|
|
2157
2431
|
}());
|
|
@@ -2178,38 +2452,133 @@ export class Cheqd {
|
|
|
2178
2452
|
// publish status list 2021 as new version
|
|
2179
2453
|
const scoped = topArgs.publishEncrypted
|
|
2180
2454
|
? (await async function () {
|
|
2455
|
+
// validate encoding, if provided
|
|
2456
|
+
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
2457
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list encoding');
|
|
2458
|
+
}
|
|
2459
|
+
// validate validUntil, if provided
|
|
2460
|
+
if (options?.publishOptions?.statusListValidUntil) {
|
|
2461
|
+
// validate validUntil as string
|
|
2462
|
+
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
2463
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be string)');
|
|
2464
|
+
// validate validUntil as date
|
|
2465
|
+
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
2466
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be date)');
|
|
2467
|
+
// validate validUntil as future date
|
|
2468
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
2469
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be future date)');
|
|
2470
|
+
// validate validUntil towards validFrom
|
|
2471
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
2472
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be after validFrom)');
|
|
2473
|
+
}
|
|
2474
|
+
// validate paymentConditions, if provided
|
|
2475
|
+
if (topArgs?.paymentConditions) {
|
|
2476
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.feePaymentAddress && condition.feePaymentAmount && condition.intervalInSeconds)) {
|
|
2477
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount and intervalInSeconds');
|
|
2478
|
+
}
|
|
2479
|
+
if (!topArgs?.paymentConditions?.every((condition) => typeof condition.feePaymentAddress === 'string' && typeof condition.feePaymentAmount === 'string' && typeof condition.intervalInSeconds === 'number')) {
|
|
2480
|
+
throw new Error('[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string and intervalInSeconds must be number');
|
|
2481
|
+
}
|
|
2482
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.type === AccessControlConditionTypes.timelockPayment)) {
|
|
2483
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must be of type timelockPayment');
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
// validate dkgOptions
|
|
2487
|
+
if (!topArgs?.dkgOptions || !topArgs?.dkgOptions?.chain || !topArgs?.dkgOptions?.network) {
|
|
2488
|
+
throw new Error('[did-provider-cheqd]: dkgOptions is required');
|
|
2489
|
+
}
|
|
2181
2490
|
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
2182
2491
|
const lit = await LitProtocol.create({
|
|
2183
|
-
chain:
|
|
2184
|
-
litNetwork:
|
|
2492
|
+
chain: topArgs?.dkgOptions?.chain,
|
|
2493
|
+
litNetwork: topArgs?.dkgOptions?.network
|
|
2185
2494
|
});
|
|
2186
|
-
//
|
|
2187
|
-
const
|
|
2495
|
+
// construct access control conditions and payment conditions tuple
|
|
2496
|
+
const unifiedAccessControlConditionsTuple = publishedList.metadata.encrypted
|
|
2497
|
+
? (await (async function () {
|
|
2498
|
+
// define payment conditions, give precedence to top-level args
|
|
2499
|
+
const paymentConditions = topArgs?.paymentConditions || publishedList.metadata.paymentConditions;
|
|
2500
|
+
// return access control conditions and payment conditions tuple
|
|
2501
|
+
return [
|
|
2502
|
+
await Promise.all(paymentConditions.map(async (condition) => {
|
|
2503
|
+
switch (condition.type) {
|
|
2504
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
2505
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
2506
|
+
key: '$.tx_responses.*.timestamp',
|
|
2507
|
+
comparator: '<=',
|
|
2508
|
+
value: `${condition.intervalInSeconds}`,
|
|
2509
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, topArgs?.dkgOptions?.chain);
|
|
2510
|
+
default:
|
|
2511
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
2512
|
+
}
|
|
2513
|
+
})),
|
|
2514
|
+
paymentConditions
|
|
2515
|
+
];
|
|
2516
|
+
}()))
|
|
2517
|
+
: (await (async function () {
|
|
2518
|
+
// validate paymentConditions
|
|
2519
|
+
if (!topArgs?.paymentConditions) {
|
|
2520
|
+
throw new Error('[did-provider-cheqd]: paymentConditions is required');
|
|
2521
|
+
}
|
|
2522
|
+
// return access control conditions and payment conditions tuple
|
|
2523
|
+
return [
|
|
2524
|
+
await Promise.all(topArgs.paymentConditions.map(async (condition) => {
|
|
2525
|
+
switch (condition.type) {
|
|
2526
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
2527
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
2528
|
+
key: '$.tx_responses.*.timestamp',
|
|
2529
|
+
comparator: '<=',
|
|
2530
|
+
value: `${condition.intervalInSeconds}`,
|
|
2531
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight);
|
|
2532
|
+
default:
|
|
2533
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
2534
|
+
}
|
|
2535
|
+
})),
|
|
2536
|
+
topArgs.paymentConditions
|
|
2537
|
+
];
|
|
2538
|
+
}()));
|
|
2539
|
+
// encrypt bitstring
|
|
2540
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, unifiedAccessControlConditionsTuple[0], true);
|
|
2541
|
+
// define status list content
|
|
2542
|
+
const content = {
|
|
2543
|
+
StatusList2021: {
|
|
2544
|
+
statusPurpose: publishedList.StatusList2021.statusPurpose,
|
|
2545
|
+
encodedList: await blobToHexString(encryptedString),
|
|
2546
|
+
validFrom: publishedList.StatusList2021.validFrom,
|
|
2547
|
+
validUntil: options?.publishOptions?.statusListValidUntil || publishedList.StatusList2021.validUntil
|
|
2548
|
+
},
|
|
2549
|
+
metadata: {
|
|
2550
|
+
type: publishedList.metadata.type,
|
|
2551
|
+
encrypted: true,
|
|
2552
|
+
encoding: options?.publishOptions?.statusListEncoding || publishedList.metadata.encoding,
|
|
2553
|
+
encryptedSymmetricKey,
|
|
2554
|
+
paymentConditions: unifiedAccessControlConditionsTuple[1]
|
|
2555
|
+
}
|
|
2556
|
+
};
|
|
2188
2557
|
// return tuple of publish result and encryption relevant metadata
|
|
2189
2558
|
return [
|
|
2190
|
-
await Cheqd.publishStatusList2021(
|
|
2559
|
+
await Cheqd.publishStatusList2021(fromString(JSON.stringify(content), 'utf-8'), statusListMetadata, options?.publishOptions),
|
|
2191
2560
|
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
2192
2561
|
];
|
|
2193
2562
|
}())
|
|
2194
2563
|
: (await async function () {
|
|
2195
2564
|
// validate encoding, if provided
|
|
2196
2565
|
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
2197
|
-
throw new Error('[did-provider-cheqd]:
|
|
2566
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list encoding');
|
|
2198
2567
|
}
|
|
2199
2568
|
// validate validUntil, if provided
|
|
2200
2569
|
if (options?.publishOptions?.statusListValidUntil) {
|
|
2201
2570
|
// validate validUntil as string
|
|
2202
2571
|
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
2203
|
-
throw new Error('[did-provider-cheqd]:
|
|
2572
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be string)');
|
|
2204
2573
|
// validate validUntil as date
|
|
2205
2574
|
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
2206
|
-
throw new Error('[did-provider-cheqd]:
|
|
2575
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be date)');
|
|
2207
2576
|
// validate validUntil as future date
|
|
2208
2577
|
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
2209
|
-
throw new Error('[did-provider-cheqd]:
|
|
2578
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be future date)');
|
|
2210
2579
|
// validate validUntil towards validFrom
|
|
2211
2580
|
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
2212
|
-
throw new Error('[did-provider-cheqd]:
|
|
2581
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be after validFrom)');
|
|
2213
2582
|
}
|
|
2214
2583
|
// define status list content
|
|
2215
2584
|
const content = {
|
|
@@ -2242,8 +2611,6 @@ export class Cheqd {
|
|
|
2242
2611
|
suspended: true,
|
|
2243
2612
|
published: topArgs?.publish ? true : undefined,
|
|
2244
2613
|
statusList: topArgs?.returnUpdatedStatusList ? await Cheqd.fetchStatusList2021(credential) : undefined,
|
|
2245
|
-
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
2246
|
-
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
2247
2614
|
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
2248
2615
|
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
|
|
2249
2616
|
};
|
|
@@ -2301,8 +2668,8 @@ export class Cheqd {
|
|
|
2301
2668
|
return publishedList.metadata.encoding === 'base64url'
|
|
2302
2669
|
? publishedList.StatusList2021.encodedList
|
|
2303
2670
|
: toString(fromString(publishedList.StatusList2021.encodedList, publishedList.metadata.encoding), 'base64url');
|
|
2304
|
-
// otherwise, decrypt and return bitstring
|
|
2305
|
-
const scopedRawBlob = await toBlob(
|
|
2671
|
+
// otherwise, decrypt and return raw bitstring
|
|
2672
|
+
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList, 'hex'));
|
|
2306
2673
|
// decrypt
|
|
2307
2674
|
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2308
2675
|
}())
|
|
@@ -2319,7 +2686,7 @@ export class Cheqd {
|
|
|
2319
2686
|
const encoded = new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
2320
2687
|
// validate against published list
|
|
2321
2688
|
if (encoded !== publishedListTranscoded)
|
|
2322
|
-
throw new Error('[did-provider-cheqd]:
|
|
2689
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListFile does not match published status list 2021');
|
|
2323
2690
|
// return encoded
|
|
2324
2691
|
return encoded;
|
|
2325
2692
|
}
|
|
@@ -2329,15 +2696,15 @@ export class Cheqd {
|
|
|
2329
2696
|
const decrypted = await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2330
2697
|
// validate against published list
|
|
2331
2698
|
if (decrypted !== publishedListTranscoded)
|
|
2332
|
-
throw new Error('[did-provider-cheqd]:
|
|
2699
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListFile does not match published status list 2021');
|
|
2333
2700
|
// return decrypted
|
|
2334
2701
|
return decrypted;
|
|
2335
2702
|
}
|
|
2336
2703
|
if (!options?.statusListInlineBitstring)
|
|
2337
|
-
throw new Error('[did-provider-cheqd]:
|
|
2704
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
2338
2705
|
// validate against published list
|
|
2339
2706
|
if (options?.statusListInlineBitstring !== publishedListTranscoded)
|
|
2340
|
-
throw new Error('[did-provider-cheqd]:
|
|
2707
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListInlineBitstring does not match published status list 2021');
|
|
2341
2708
|
// otherwise, read from inline bitstring
|
|
2342
2709
|
return options?.statusListInlineBitstring;
|
|
2343
2710
|
}());
|
|
@@ -2377,38 +2744,133 @@ export class Cheqd {
|
|
|
2377
2744
|
// publish status list 2021 as new version
|
|
2378
2745
|
const scoped = topArgs.publishEncrypted
|
|
2379
2746
|
? (await async function () {
|
|
2747
|
+
// validate encoding, if provided
|
|
2748
|
+
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
2749
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list encoding');
|
|
2750
|
+
}
|
|
2751
|
+
// validate validUntil, if provided
|
|
2752
|
+
if (options?.publishOptions?.statusListValidUntil) {
|
|
2753
|
+
// validate validUntil as string
|
|
2754
|
+
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
2755
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be string)');
|
|
2756
|
+
// validate validUntil as date
|
|
2757
|
+
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
2758
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be date)');
|
|
2759
|
+
// validate validUntil as future date
|
|
2760
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
2761
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be future date)');
|
|
2762
|
+
// validate validUntil towards validFrom
|
|
2763
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
2764
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be after validFrom)');
|
|
2765
|
+
}
|
|
2766
|
+
// validate paymentConditions, if provided
|
|
2767
|
+
if (topArgs?.paymentConditions) {
|
|
2768
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.feePaymentAddress && condition.feePaymentAmount && condition.intervalInSeconds)) {
|
|
2769
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount and intervalInSeconds');
|
|
2770
|
+
}
|
|
2771
|
+
if (!topArgs?.paymentConditions?.every((condition) => typeof condition.feePaymentAddress === 'string' && typeof condition.feePaymentAmount === 'string' && typeof condition.intervalInSeconds === 'number')) {
|
|
2772
|
+
throw new Error('[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string and intervalInSeconds must be number');
|
|
2773
|
+
}
|
|
2774
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.type === AccessControlConditionTypes.timelockPayment)) {
|
|
2775
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must be of type timelockPayment');
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
// validate dkgOptions
|
|
2779
|
+
if (!topArgs?.dkgOptions || !topArgs?.dkgOptions?.chain || !topArgs?.dkgOptions?.network) {
|
|
2780
|
+
throw new Error('[did-provider-cheqd]: dkgOptions is required');
|
|
2781
|
+
}
|
|
2380
2782
|
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
2381
2783
|
const lit = await LitProtocol.create({
|
|
2382
|
-
chain:
|
|
2383
|
-
litNetwork:
|
|
2784
|
+
chain: topArgs?.dkgOptions?.chain,
|
|
2785
|
+
litNetwork: topArgs?.dkgOptions?.network
|
|
2384
2786
|
});
|
|
2385
|
-
//
|
|
2386
|
-
const
|
|
2787
|
+
// construct access control conditions and payment conditions tuple
|
|
2788
|
+
const unifiedAccessControlConditionsTuple = publishedList.metadata.encrypted
|
|
2789
|
+
? (await (async function () {
|
|
2790
|
+
// define payment conditions, give precedence to top-level args
|
|
2791
|
+
const paymentConditions = topArgs?.paymentConditions || publishedList.metadata.paymentConditions;
|
|
2792
|
+
// return access control conditions and payment conditions tuple
|
|
2793
|
+
return [
|
|
2794
|
+
await Promise.all(paymentConditions.map(async (condition) => {
|
|
2795
|
+
switch (condition.type) {
|
|
2796
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
2797
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
2798
|
+
key: '$.tx_responses.*.timestamp',
|
|
2799
|
+
comparator: '<=',
|
|
2800
|
+
value: `${condition.intervalInSeconds}`,
|
|
2801
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, topArgs?.dkgOptions?.chain);
|
|
2802
|
+
default:
|
|
2803
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
2804
|
+
}
|
|
2805
|
+
})),
|
|
2806
|
+
paymentConditions
|
|
2807
|
+
];
|
|
2808
|
+
}()))
|
|
2809
|
+
: (await (async function () {
|
|
2810
|
+
// validate paymentConditions
|
|
2811
|
+
if (!topArgs?.paymentConditions) {
|
|
2812
|
+
throw new Error('[did-provider-cheqd]: paymentConditions is required');
|
|
2813
|
+
}
|
|
2814
|
+
// return access control conditions and payment conditions tuple
|
|
2815
|
+
return [
|
|
2816
|
+
await Promise.all(topArgs.paymentConditions.map(async (condition) => {
|
|
2817
|
+
switch (condition.type) {
|
|
2818
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
2819
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
2820
|
+
key: '$.tx_responses.*.timestamp',
|
|
2821
|
+
comparator: '<=',
|
|
2822
|
+
value: `${condition.intervalInSeconds}`,
|
|
2823
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight);
|
|
2824
|
+
default:
|
|
2825
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
2826
|
+
}
|
|
2827
|
+
})),
|
|
2828
|
+
topArgs.paymentConditions
|
|
2829
|
+
];
|
|
2830
|
+
}()));
|
|
2831
|
+
// encrypt bitstring
|
|
2832
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, unifiedAccessControlConditionsTuple[0], true);
|
|
2833
|
+
// define status list content
|
|
2834
|
+
const content = {
|
|
2835
|
+
StatusList2021: {
|
|
2836
|
+
statusPurpose: publishedList.StatusList2021.statusPurpose,
|
|
2837
|
+
encodedList: await blobToHexString(encryptedString),
|
|
2838
|
+
validFrom: publishedList.StatusList2021.validFrom,
|
|
2839
|
+
validUntil: options?.publishOptions?.statusListValidUntil || publishedList.StatusList2021.validUntil
|
|
2840
|
+
},
|
|
2841
|
+
metadata: {
|
|
2842
|
+
type: publishedList.metadata.type,
|
|
2843
|
+
encrypted: true,
|
|
2844
|
+
encoding: options?.publishOptions?.statusListEncoding || publishedList.metadata.encoding,
|
|
2845
|
+
encryptedSymmetricKey,
|
|
2846
|
+
paymentConditions: unifiedAccessControlConditionsTuple[1]
|
|
2847
|
+
}
|
|
2848
|
+
};
|
|
2387
2849
|
// return tuple of publish result and encryption relevant metadata
|
|
2388
2850
|
return [
|
|
2389
|
-
await Cheqd.publishStatusList2021(
|
|
2851
|
+
await Cheqd.publishStatusList2021(fromString(JSON.stringify(content), 'utf-8'), statusListMetadata, options?.publishOptions),
|
|
2390
2852
|
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
2391
2853
|
];
|
|
2392
2854
|
}())
|
|
2393
2855
|
: (await async function () {
|
|
2394
2856
|
// validate encoding, if provided
|
|
2395
2857
|
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
2396
|
-
throw new Error('[did-provider-cheqd]:
|
|
2858
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list encoding');
|
|
2397
2859
|
}
|
|
2398
2860
|
// validate validUntil, if provided
|
|
2399
2861
|
if (options?.publishOptions?.statusListValidUntil) {
|
|
2400
2862
|
// validate validUntil as string
|
|
2401
2863
|
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
2402
|
-
throw new Error('[did-provider-cheqd]:
|
|
2864
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be string)');
|
|
2403
2865
|
// validate validUntil as date
|
|
2404
2866
|
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
2405
|
-
throw new Error('[did-provider-cheqd]:
|
|
2867
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be date)');
|
|
2406
2868
|
// validate validUntil as future date
|
|
2407
2869
|
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
2408
|
-
throw new Error('[did-provider-cheqd]:
|
|
2870
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be future date)');
|
|
2409
2871
|
// validate validUntil towards validFrom
|
|
2410
2872
|
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
2411
|
-
throw new Error('[did-provider-cheqd]:
|
|
2873
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status list validUntil (must be after validFrom)');
|
|
2412
2874
|
}
|
|
2413
2875
|
// define status list content
|
|
2414
2876
|
const content = {
|
|
@@ -2441,8 +2903,6 @@ export class Cheqd {
|
|
|
2441
2903
|
suspended: suspended.map((result) => result.status === 'fulfilled' ? result.value.suspended : false),
|
|
2442
2904
|
published: topArgs?.publish ? true : undefined,
|
|
2443
2905
|
statusList: topArgs?.returnUpdatedStatusList ? await Cheqd.fetchStatusList2021(credentials[0]) : undefined,
|
|
2444
|
-
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
2445
|
-
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
2446
2906
|
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
2447
2907
|
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credentials[0]) : undefined
|
|
2448
2908
|
};
|
|
@@ -2462,7 +2922,7 @@ export class Cheqd {
|
|
|
2462
2922
|
const publishedList = (await Cheqd.fetchStatusList2021(credential));
|
|
2463
2923
|
// early return, if encrypted and no decryption key provided
|
|
2464
2924
|
if (publishedList.metadata.encrypted && !options?.topArgs?.symmetricKey)
|
|
2465
|
-
throw new Error('[did-provider-cheqd]:
|
|
2925
|
+
throw new Error('[did-provider-cheqd]: unsuspension: symmetricKey is required, if status list 2021 is encrypted');
|
|
2466
2926
|
// fetch status list 2021 inscribed in credential
|
|
2467
2927
|
const statusList2021 = options?.topArgs?.fetchList
|
|
2468
2928
|
? (await async function () {
|
|
@@ -2471,8 +2931,8 @@ export class Cheqd {
|
|
|
2471
2931
|
return publishedList.metadata.encoding === 'base64url'
|
|
2472
2932
|
? publishedList.StatusList2021.encodedList
|
|
2473
2933
|
: toString(fromString(publishedList.StatusList2021.encodedList, publishedList.metadata.encoding), 'base64url');
|
|
2474
|
-
// otherwise, decrypt and return bitstring
|
|
2475
|
-
const scopedRawBlob = await toBlob(
|
|
2934
|
+
// otherwise, decrypt and return raw bitstring
|
|
2935
|
+
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList, 'hex'));
|
|
2476
2936
|
// decrypt
|
|
2477
2937
|
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2478
2938
|
}())
|
|
@@ -2489,7 +2949,7 @@ export class Cheqd {
|
|
|
2489
2949
|
const encoded = new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
2490
2950
|
// validate against published list
|
|
2491
2951
|
if (encoded !== publishedListTranscoded)
|
|
2492
|
-
throw new Error('[did-provider-cheqd]:
|
|
2952
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListFile does not match published status list 2021');
|
|
2493
2953
|
// return encoded
|
|
2494
2954
|
return encoded;
|
|
2495
2955
|
}
|
|
@@ -2499,15 +2959,15 @@ export class Cheqd {
|
|
|
2499
2959
|
const decrypted = await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2500
2960
|
// validate against published list
|
|
2501
2961
|
if (decrypted !== publishedListTranscoded)
|
|
2502
|
-
throw new Error('[did-provider-cheqd]:
|
|
2962
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListFile does not match published status list 2021');
|
|
2503
2963
|
// return decrypted
|
|
2504
2964
|
return decrypted;
|
|
2505
2965
|
}
|
|
2506
2966
|
if (!options?.statusListInlineBitstring)
|
|
2507
|
-
throw new Error('[did-provider-cheqd]:
|
|
2967
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
2508
2968
|
// validate against published list
|
|
2509
2969
|
if (options?.statusListInlineBitstring !== publishedListTranscoded)
|
|
2510
|
-
throw new Error('[did-provider-cheqd]:
|
|
2970
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListInlineBitstring does not match published status list 2021');
|
|
2511
2971
|
// otherwise, read from inline bitstring
|
|
2512
2972
|
return options?.statusListInlineBitstring;
|
|
2513
2973
|
}());
|
|
@@ -2534,38 +2994,133 @@ export class Cheqd {
|
|
|
2534
2994
|
// publish status list 2021 as new version
|
|
2535
2995
|
const scoped = topArgs.publishEncrypted
|
|
2536
2996
|
? (await async function () {
|
|
2997
|
+
// validate encoding, if provided
|
|
2998
|
+
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
2999
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list encoding');
|
|
3000
|
+
}
|
|
3001
|
+
// validate validUntil, if provided
|
|
3002
|
+
if (options?.publishOptions?.statusListValidUntil) {
|
|
3003
|
+
// validate validUntil as string
|
|
3004
|
+
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
3005
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be string)');
|
|
3006
|
+
// validate validUntil as date
|
|
3007
|
+
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
3008
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be date)');
|
|
3009
|
+
// validate validUntil as future date
|
|
3010
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
3011
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be future date)');
|
|
3012
|
+
// validate validUntil towards validFrom
|
|
3013
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
3014
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be after validFrom)');
|
|
3015
|
+
}
|
|
3016
|
+
// validate paymentConditions, if provided
|
|
3017
|
+
if (topArgs?.paymentConditions) {
|
|
3018
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.feePaymentAddress && condition.feePaymentAmount && condition.intervalInSeconds)) {
|
|
3019
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount and intervalInSeconds');
|
|
3020
|
+
}
|
|
3021
|
+
if (!topArgs?.paymentConditions?.every((condition) => typeof condition.feePaymentAddress === 'string' && typeof condition.feePaymentAmount === 'string' && typeof condition.intervalInSeconds === 'number')) {
|
|
3022
|
+
throw new Error('[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string and intervalInSeconds must be number');
|
|
3023
|
+
}
|
|
3024
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.type === AccessControlConditionTypes.timelockPayment)) {
|
|
3025
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must be of type timelockPayment');
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
3028
|
+
// validate dkgOptions
|
|
3029
|
+
if (!topArgs?.dkgOptions || !topArgs?.dkgOptions?.chain || !topArgs?.dkgOptions?.network) {
|
|
3030
|
+
throw new Error('[did-provider-cheqd]: dkgOptions is required');
|
|
3031
|
+
}
|
|
2537
3032
|
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
2538
3033
|
const lit = await LitProtocol.create({
|
|
2539
|
-
chain:
|
|
2540
|
-
litNetwork:
|
|
3034
|
+
chain: topArgs?.dkgOptions?.chain,
|
|
3035
|
+
litNetwork: topArgs?.dkgOptions?.network
|
|
2541
3036
|
});
|
|
2542
|
-
//
|
|
2543
|
-
const
|
|
3037
|
+
// construct access control conditions and payment conditions tuple
|
|
3038
|
+
const unifiedAccessControlConditionsTuple = publishedList.metadata.encrypted
|
|
3039
|
+
? (await (async function () {
|
|
3040
|
+
// define payment conditions, give precedence to top-level args
|
|
3041
|
+
const paymentConditions = topArgs?.paymentConditions || publishedList.metadata.paymentConditions;
|
|
3042
|
+
// return access control conditions and payment conditions tuple
|
|
3043
|
+
return [
|
|
3044
|
+
await Promise.all(paymentConditions.map(async (condition) => {
|
|
3045
|
+
switch (condition.type) {
|
|
3046
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
3047
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
3048
|
+
key: '$.tx_responses.*.timestamp',
|
|
3049
|
+
comparator: '<=',
|
|
3050
|
+
value: `${condition.intervalInSeconds}`,
|
|
3051
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, topArgs?.dkgOptions?.chain);
|
|
3052
|
+
default:
|
|
3053
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
3054
|
+
}
|
|
3055
|
+
})),
|
|
3056
|
+
paymentConditions
|
|
3057
|
+
];
|
|
3058
|
+
}()))
|
|
3059
|
+
: (await (async function () {
|
|
3060
|
+
// validate paymentConditions
|
|
3061
|
+
if (!topArgs?.paymentConditions) {
|
|
3062
|
+
throw new Error('[did-provider-cheqd]: paymentConditions is required');
|
|
3063
|
+
}
|
|
3064
|
+
// return access control conditions and payment conditions tuple
|
|
3065
|
+
return [
|
|
3066
|
+
await Promise.all(topArgs.paymentConditions.map(async (condition) => {
|
|
3067
|
+
switch (condition.type) {
|
|
3068
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
3069
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
3070
|
+
key: '$.tx_responses.*.timestamp',
|
|
3071
|
+
comparator: '<=',
|
|
3072
|
+
value: `${condition.intervalInSeconds}`,
|
|
3073
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight);
|
|
3074
|
+
default:
|
|
3075
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
3076
|
+
}
|
|
3077
|
+
})),
|
|
3078
|
+
topArgs.paymentConditions
|
|
3079
|
+
];
|
|
3080
|
+
}()));
|
|
3081
|
+
// encrypt bitstring
|
|
3082
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, unifiedAccessControlConditionsTuple[0], true);
|
|
3083
|
+
// define status list content
|
|
3084
|
+
const content = {
|
|
3085
|
+
StatusList2021: {
|
|
3086
|
+
statusPurpose: publishedList.StatusList2021.statusPurpose,
|
|
3087
|
+
encodedList: await blobToHexString(encryptedString),
|
|
3088
|
+
validFrom: publishedList.StatusList2021.validFrom,
|
|
3089
|
+
validUntil: options?.publishOptions?.statusListValidUntil || publishedList.StatusList2021.validUntil
|
|
3090
|
+
},
|
|
3091
|
+
metadata: {
|
|
3092
|
+
type: publishedList.metadata.type,
|
|
3093
|
+
encrypted: true,
|
|
3094
|
+
encoding: options?.publishOptions?.statusListEncoding || publishedList.metadata.encoding,
|
|
3095
|
+
encryptedSymmetricKey,
|
|
3096
|
+
paymentConditions: unifiedAccessControlConditionsTuple[1]
|
|
3097
|
+
}
|
|
3098
|
+
};
|
|
2544
3099
|
// return tuple of publish result and encryption relevant metadata
|
|
2545
3100
|
return [
|
|
2546
|
-
await Cheqd.publishStatusList2021(
|
|
3101
|
+
await Cheqd.publishStatusList2021(fromString(JSON.stringify(content), 'utf-8'), statusListMetadata, options?.publishOptions),
|
|
2547
3102
|
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
2548
3103
|
];
|
|
2549
3104
|
}())
|
|
2550
3105
|
: (await async function () {
|
|
2551
3106
|
// validate encoding, if provided
|
|
2552
3107
|
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
2553
|
-
throw new Error('[did-provider-cheqd]:
|
|
3108
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list encoding');
|
|
2554
3109
|
}
|
|
2555
3110
|
// validate validUntil, if provided
|
|
2556
3111
|
if (options?.publishOptions?.statusListValidUntil) {
|
|
2557
3112
|
// validate validUntil as string
|
|
2558
3113
|
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
2559
|
-
throw new Error('[did-provider-cheqd]:
|
|
3114
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be string)');
|
|
2560
3115
|
// validate validUntil as date
|
|
2561
3116
|
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
2562
|
-
throw new Error('[did-provider-cheqd]:
|
|
3117
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be date)');
|
|
2563
3118
|
// validate validUntil as future date
|
|
2564
3119
|
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
2565
|
-
throw new Error('[did-provider-cheqd]:
|
|
3120
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be future date)');
|
|
2566
3121
|
// validate validUntil towards validFrom
|
|
2567
3122
|
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
2568
|
-
throw new Error('[did-provider-cheqd]:
|
|
3123
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be after validFrom)');
|
|
2569
3124
|
}
|
|
2570
3125
|
// define status list content
|
|
2571
3126
|
const content = {
|
|
@@ -2598,8 +3153,6 @@ export class Cheqd {
|
|
|
2598
3153
|
unsuspended: true,
|
|
2599
3154
|
published: topArgs?.publish ? true : undefined,
|
|
2600
3155
|
statusList: topArgs?.returnUpdatedStatusList ? await Cheqd.fetchStatusList2021(credential) : undefined,
|
|
2601
|
-
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
2602
|
-
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
2603
3156
|
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
2604
3157
|
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
|
|
2605
3158
|
};
|
|
@@ -2657,8 +3210,8 @@ export class Cheqd {
|
|
|
2657
3210
|
return publishedList.metadata.encoding === 'base64url'
|
|
2658
3211
|
? publishedList.StatusList2021.encodedList
|
|
2659
3212
|
: toString(fromString(publishedList.StatusList2021.encodedList, publishedList.metadata.encoding), 'base64url');
|
|
2660
|
-
// otherwise, decrypt and return bitstring
|
|
2661
|
-
const scopedRawBlob = await toBlob(
|
|
3213
|
+
// otherwise, decrypt and return raw bitstring
|
|
3214
|
+
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList, 'hex'));
|
|
2662
3215
|
// decrypt
|
|
2663
3216
|
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2664
3217
|
}())
|
|
@@ -2675,7 +3228,7 @@ export class Cheqd {
|
|
|
2675
3228
|
const encoded = new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
2676
3229
|
// validate against published list
|
|
2677
3230
|
if (encoded !== publishedListTranscoded)
|
|
2678
|
-
throw new Error('[did-provider-cheqd]:
|
|
3231
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListFile does not match published status list 2021');
|
|
2679
3232
|
// return encoded
|
|
2680
3233
|
return encoded;
|
|
2681
3234
|
}
|
|
@@ -2685,15 +3238,15 @@ export class Cheqd {
|
|
|
2685
3238
|
const decrypted = await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2686
3239
|
// validate against published list
|
|
2687
3240
|
if (decrypted !== publishedListTranscoded)
|
|
2688
|
-
throw new Error('[did-provider-cheqd]:
|
|
3241
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListFile does not match published status list 2021');
|
|
2689
3242
|
// return decrypted
|
|
2690
3243
|
return decrypted;
|
|
2691
3244
|
}
|
|
2692
3245
|
if (!options?.statusListInlineBitstring)
|
|
2693
|
-
throw new Error('[did-provider-cheqd]:
|
|
3246
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
2694
3247
|
// validate against published list
|
|
2695
3248
|
if (options?.statusListInlineBitstring !== publishedListTranscoded)
|
|
2696
|
-
throw new Error('[did-provider-cheqd]:
|
|
3249
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListInlineBitstring does not match published status list 2021');
|
|
2697
3250
|
// otherwise, read from inline bitstring
|
|
2698
3251
|
return options?.statusListInlineBitstring;
|
|
2699
3252
|
}());
|
|
@@ -2733,38 +3286,133 @@ export class Cheqd {
|
|
|
2733
3286
|
// publish status list 2021 as new version
|
|
2734
3287
|
const scoped = topArgs.publishEncrypted
|
|
2735
3288
|
? (await async function () {
|
|
3289
|
+
// validate encoding, if provided
|
|
3290
|
+
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
3291
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list encoding');
|
|
3292
|
+
}
|
|
3293
|
+
// validate validUntil, if provided
|
|
3294
|
+
if (options?.publishOptions?.statusListValidUntil) {
|
|
3295
|
+
// validate validUntil as string
|
|
3296
|
+
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
3297
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be string)');
|
|
3298
|
+
// validate validUntil as date
|
|
3299
|
+
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
3300
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be date)');
|
|
3301
|
+
// validate validUntil as future date
|
|
3302
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
3303
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be future date)');
|
|
3304
|
+
// validate validUntil towards validFrom
|
|
3305
|
+
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
3306
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be after validFrom)');
|
|
3307
|
+
}
|
|
3308
|
+
// validate paymentConditions, if provided
|
|
3309
|
+
if (topArgs?.paymentConditions) {
|
|
3310
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.feePaymentAddress && condition.feePaymentAmount && condition.intervalInSeconds)) {
|
|
3311
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must contain feePaymentAddress and feeAmount and intervalInSeconds');
|
|
3312
|
+
}
|
|
3313
|
+
if (!topArgs?.paymentConditions?.every((condition) => typeof condition.feePaymentAddress === 'string' && typeof condition.feePaymentAmount === 'string' && typeof condition.intervalInSeconds === 'number')) {
|
|
3314
|
+
throw new Error('[did-provider-cheqd]: feePaymentAddress and feePaymentAmount must be string and intervalInSeconds must be number');
|
|
3315
|
+
}
|
|
3316
|
+
if (!topArgs?.paymentConditions?.every((condition) => condition.type === AccessControlConditionTypes.timelockPayment)) {
|
|
3317
|
+
throw new Error('[did-provider-cheqd]: paymentConditions must be of type timelockPayment');
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
// validate dkgOptions
|
|
3321
|
+
if (!topArgs?.dkgOptions || !topArgs?.dkgOptions?.chain || !topArgs?.dkgOptions?.network) {
|
|
3322
|
+
throw new Error('[did-provider-cheqd]: dkgOptions is required');
|
|
3323
|
+
}
|
|
2736
3324
|
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
2737
3325
|
const lit = await LitProtocol.create({
|
|
2738
|
-
chain:
|
|
2739
|
-
litNetwork:
|
|
3326
|
+
chain: topArgs?.dkgOptions?.chain,
|
|
3327
|
+
litNetwork: topArgs?.dkgOptions?.network
|
|
2740
3328
|
});
|
|
2741
|
-
//
|
|
2742
|
-
const
|
|
3329
|
+
// construct access control conditions and payment conditions tuple
|
|
3330
|
+
const unifiedAccessControlConditionsTuple = publishedList.metadata.encrypted
|
|
3331
|
+
? (await (async function () {
|
|
3332
|
+
// define payment conditions, give precedence to top-level args
|
|
3333
|
+
const paymentConditions = topArgs?.paymentConditions || publishedList.metadata.paymentConditions;
|
|
3334
|
+
// return access control conditions and payment conditions tuple
|
|
3335
|
+
return [
|
|
3336
|
+
await Promise.all(paymentConditions.map(async (condition) => {
|
|
3337
|
+
switch (condition.type) {
|
|
3338
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
3339
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
3340
|
+
key: '$.tx_responses.*.timestamp',
|
|
3341
|
+
comparator: '<=',
|
|
3342
|
+
value: `${condition.intervalInSeconds}`,
|
|
3343
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, topArgs?.dkgOptions?.chain);
|
|
3344
|
+
default:
|
|
3345
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
3346
|
+
}
|
|
3347
|
+
})),
|
|
3348
|
+
paymentConditions
|
|
3349
|
+
];
|
|
3350
|
+
}()))
|
|
3351
|
+
: (await (async function () {
|
|
3352
|
+
// validate paymentConditions
|
|
3353
|
+
if (!topArgs?.paymentConditions) {
|
|
3354
|
+
throw new Error('[did-provider-cheqd]: paymentConditions is required');
|
|
3355
|
+
}
|
|
3356
|
+
// return access control conditions and payment conditions tuple
|
|
3357
|
+
return [
|
|
3358
|
+
await Promise.all(topArgs.paymentConditions.map(async (condition) => {
|
|
3359
|
+
switch (condition.type) {
|
|
3360
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
3361
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
3362
|
+
key: '$.tx_responses.*.timestamp',
|
|
3363
|
+
comparator: '<=',
|
|
3364
|
+
value: `${condition.intervalInSeconds}`,
|
|
3365
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight);
|
|
3366
|
+
default:
|
|
3367
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
3368
|
+
}
|
|
3369
|
+
})),
|
|
3370
|
+
topArgs.paymentConditions
|
|
3371
|
+
];
|
|
3372
|
+
}()));
|
|
3373
|
+
// encrypt bitstring
|
|
3374
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, unifiedAccessControlConditionsTuple[0], true);
|
|
3375
|
+
// define status list content
|
|
3376
|
+
const content = {
|
|
3377
|
+
StatusList2021: {
|
|
3378
|
+
statusPurpose: publishedList.StatusList2021.statusPurpose,
|
|
3379
|
+
encodedList: await blobToHexString(encryptedString),
|
|
3380
|
+
validFrom: publishedList.StatusList2021.validFrom,
|
|
3381
|
+
validUntil: options?.publishOptions?.statusListValidUntil || publishedList.StatusList2021.validUntil
|
|
3382
|
+
},
|
|
3383
|
+
metadata: {
|
|
3384
|
+
type: publishedList.metadata.type,
|
|
3385
|
+
encrypted: true,
|
|
3386
|
+
encoding: options?.publishOptions?.statusListEncoding || publishedList.metadata.encoding,
|
|
3387
|
+
encryptedSymmetricKey,
|
|
3388
|
+
paymentConditions: unifiedAccessControlConditionsTuple[1]
|
|
3389
|
+
}
|
|
3390
|
+
};
|
|
2743
3391
|
// return tuple of publish result and encryption relevant metadata
|
|
2744
3392
|
return [
|
|
2745
|
-
await Cheqd.publishStatusList2021(
|
|
3393
|
+
await Cheqd.publishStatusList2021(fromString(JSON.stringify(content), 'utf-8'), statusListMetadata, options?.publishOptions),
|
|
2746
3394
|
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
2747
3395
|
];
|
|
2748
3396
|
}())
|
|
2749
3397
|
: (await async function () {
|
|
2750
3398
|
// validate encoding, if provided
|
|
2751
3399
|
if (options?.publishOptions?.statusListEncoding && !Object.values(DefaultStatusList2021Encodings).includes(options?.publishOptions?.statusListEncoding)) {
|
|
2752
|
-
throw new Error('[did-provider-cheqd]:
|
|
3400
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list encoding');
|
|
2753
3401
|
}
|
|
2754
3402
|
// validate validUntil, if provided
|
|
2755
3403
|
if (options?.publishOptions?.statusListValidUntil) {
|
|
2756
3404
|
// validate validUntil as string
|
|
2757
3405
|
if (typeof options?.publishOptions?.statusListValidUntil !== 'string')
|
|
2758
|
-
throw new Error('[did-provider-cheqd]:
|
|
3406
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be string)');
|
|
2759
3407
|
// validate validUntil as date
|
|
2760
3408
|
if (isNaN(Date.parse(options?.publishOptions?.statusListValidUntil)))
|
|
2761
|
-
throw new Error('[did-provider-cheqd]:
|
|
3409
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be date)');
|
|
2762
3410
|
// validate validUntil as future date
|
|
2763
3411
|
if (new Date(options?.publishOptions?.statusListValidUntil) < new Date())
|
|
2764
|
-
throw new Error('[did-provider-cheqd]:
|
|
3412
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be future date)');
|
|
2765
3413
|
// validate validUntil towards validFrom
|
|
2766
3414
|
if (new Date(options?.publishOptions?.statusListValidUntil) <= new Date(publishedList.StatusList2021.validFrom))
|
|
2767
|
-
throw new Error('[did-provider-cheqd]:
|
|
3415
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status list validUntil (must be after validFrom)');
|
|
2768
3416
|
}
|
|
2769
3417
|
// define status list content
|
|
2770
3418
|
const content = {
|
|
@@ -2797,8 +3445,6 @@ export class Cheqd {
|
|
|
2797
3445
|
unsuspended: unsuspended.map((result) => result.status === 'fulfilled' ? result.value.unsuspended : false),
|
|
2798
3446
|
published: topArgs?.publish ? true : undefined,
|
|
2799
3447
|
statusList: topArgs?.returnUpdatedStatusList ? await Cheqd.fetchStatusList2021(credentials[0]) : undefined,
|
|
2800
|
-
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
2801
|
-
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
2802
3448
|
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
2803
3449
|
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credentials[0]) : undefined
|
|
2804
3450
|
};
|
|
@@ -2812,13 +3458,10 @@ export class Cheqd {
|
|
|
2812
3458
|
static async checkRevoked(credential, options = { fetchList: true }) {
|
|
2813
3459
|
// validate status purpose
|
|
2814
3460
|
if (credential.credentialStatus?.statusPurpose !== 'revocation') {
|
|
2815
|
-
throw new Error(`[did-provider-cheqd]: revocation: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
|
|
3461
|
+
throw new Error(`[did-provider-cheqd]: check: revocation: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
|
|
2816
3462
|
}
|
|
2817
3463
|
// fetch status list 2021
|
|
2818
3464
|
const publishedList = (await Cheqd.fetchStatusList2021(credential));
|
|
2819
|
-
// early return, if encrypted and decryption key is not provided
|
|
2820
|
-
if (publishedList.metadata.encrypted && !options?.topArgs?.encryptedSymmetricKey)
|
|
2821
|
-
throw new Error('[did-provider-cheqd]: revocation: encryptedSymmetricKey is required, if status list 2021 is encrypted');
|
|
2822
3465
|
// fetch status list 2021 inscribed in credential
|
|
2823
3466
|
const statusList2021 = options?.topArgs?.fetchList
|
|
2824
3467
|
? (await async function () {
|
|
@@ -2827,15 +3470,28 @@ export class Cheqd {
|
|
|
2827
3470
|
return publishedList.metadata.encoding === 'base64url'
|
|
2828
3471
|
? publishedList.StatusList2021.encodedList
|
|
2829
3472
|
: toString(fromString(publishedList.StatusList2021.encodedList, publishedList.metadata.encoding), 'base64url');
|
|
2830
|
-
// otherwise, decrypt and return bitstring
|
|
2831
|
-
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList,
|
|
3473
|
+
// otherwise, decrypt and return raw bitstring
|
|
3474
|
+
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList, 'hex'));
|
|
2832
3475
|
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
2833
3476
|
const lit = await LitProtocol.create({
|
|
2834
|
-
chain: options?.topArgs?.
|
|
2835
|
-
litNetwork: options?.topArgs?.
|
|
3477
|
+
chain: options?.topArgs?.dkgOptions?.chain,
|
|
3478
|
+
litNetwork: options?.topArgs?.dkgOptions?.network
|
|
2836
3479
|
});
|
|
3480
|
+
// construct access control conditions
|
|
3481
|
+
const unifiedAccessControlConditions = await Promise.all(publishedList.metadata.paymentConditions.map(async (condition) => {
|
|
3482
|
+
switch (condition.type) {
|
|
3483
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
3484
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
3485
|
+
key: '$.tx_responses.*.timestamp',
|
|
3486
|
+
comparator: '<=',
|
|
3487
|
+
value: `${condition.intervalInSeconds}`,
|
|
3488
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, options?.topArgs?.dkgOptions?.chain);
|
|
3489
|
+
default:
|
|
3490
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
3491
|
+
}
|
|
3492
|
+
}));
|
|
2837
3493
|
// decrypt
|
|
2838
|
-
return await lit.decrypt(scopedRawBlob,
|
|
3494
|
+
return await lit.decrypt(scopedRawBlob, publishedList.metadata.encryptedSymmetricKey, unifiedAccessControlConditions);
|
|
2839
3495
|
}())
|
|
2840
3496
|
: (await async function () {
|
|
2841
3497
|
// transcode to base64url, if needed
|
|
@@ -2850,7 +3506,7 @@ export class Cheqd {
|
|
|
2850
3506
|
const encoded = new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
2851
3507
|
// validate against published list
|
|
2852
3508
|
if (encoded !== publishedListTranscoded)
|
|
2853
|
-
throw new Error('[did-provider-cheqd]: revocation: statusListFile does not match published status list 2021');
|
|
3509
|
+
throw new Error('[did-provider-cheqd]: check: revocation: statusListFile does not match published status list 2021');
|
|
2854
3510
|
// return encoded
|
|
2855
3511
|
return encoded;
|
|
2856
3512
|
}
|
|
@@ -2860,33 +3516,34 @@ export class Cheqd {
|
|
|
2860
3516
|
const decrypted = await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2861
3517
|
// validate against published list
|
|
2862
3518
|
if (decrypted !== publishedListTranscoded)
|
|
2863
|
-
throw new Error('[did-provider-cheqd]: revocation: statusListFile does not match published status list 2021');
|
|
3519
|
+
throw new Error('[did-provider-cheqd]: check: revocation: statusListFile does not match published status list 2021');
|
|
2864
3520
|
// return decrypted
|
|
2865
3521
|
return decrypted;
|
|
2866
3522
|
}
|
|
2867
3523
|
if (!options?.statusListInlineBitstring)
|
|
2868
|
-
throw new Error('[did-provider-cheqd]: revocation: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
3524
|
+
throw new Error('[did-provider-cheqd]: check: revocation: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
2869
3525
|
// validate against published list
|
|
2870
3526
|
if (options?.statusListInlineBitstring !== publishedListTranscoded)
|
|
2871
|
-
throw new Error('[did-provider-cheqd]: revocation: statusListInlineBitstring does not match published status list 2021');
|
|
3527
|
+
throw new Error('[did-provider-cheqd]: check: revocation: statusListInlineBitstring does not match published status list 2021');
|
|
2872
3528
|
// otherwise, read from inline bitstring
|
|
2873
3529
|
return options?.statusListInlineBitstring;
|
|
2874
3530
|
}());
|
|
3531
|
+
// transcode, if needed
|
|
3532
|
+
const transcodedStatusList2021 = publishedList.metadata.encoding === 'base64url'
|
|
3533
|
+
? statusList2021
|
|
3534
|
+
: toString(fromString(statusList2021, publishedList.metadata.encoding), 'base64url');
|
|
2875
3535
|
// parse status list 2021
|
|
2876
|
-
const statusList = await StatusList.decode({ encodedList:
|
|
3536
|
+
const statusList = await StatusList.decode({ encodedList: transcodedStatusList2021 });
|
|
2877
3537
|
// get status by index
|
|
2878
3538
|
return !!statusList.getStatus(Number(credential.credentialStatus.statusListIndex));
|
|
2879
3539
|
}
|
|
2880
3540
|
static async checkSuspended(credential, options = { fetchList: true }) {
|
|
2881
3541
|
// validate status purpose
|
|
2882
3542
|
if (credential.credentialStatus?.statusPurpose !== 'suspension') {
|
|
2883
|
-
throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
|
|
3543
|
+
throw new Error(`[did-provider-cheqd]: check: suspension: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
|
|
2884
3544
|
}
|
|
2885
3545
|
// fetch status list 2021
|
|
2886
3546
|
const publishedList = (await Cheqd.fetchStatusList2021(credential));
|
|
2887
|
-
// early return, if encrypted and decryption key is not provided
|
|
2888
|
-
if (publishedList.metadata.encrypted && !options?.topArgs?.encryptedSymmetricKey)
|
|
2889
|
-
throw new Error('[did-provider-cheqd]: revocation: encryptedSymmetricKey is required, if status list 2021 is encrypted');
|
|
2890
3547
|
// fetch status list 2021 inscribed in credential
|
|
2891
3548
|
const statusList2021 = options?.topArgs?.fetchList
|
|
2892
3549
|
? (await async function () {
|
|
@@ -2896,14 +3553,27 @@ export class Cheqd {
|
|
|
2896
3553
|
? publishedList.StatusList2021.encodedList
|
|
2897
3554
|
: toString(fromString(publishedList.StatusList2021.encodedList, publishedList.metadata.encoding), 'base64url');
|
|
2898
3555
|
// otherwise, decrypt and return bitstring
|
|
2899
|
-
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList,
|
|
3556
|
+
const scopedRawBlob = await toBlob(fromString(publishedList.StatusList2021.encodedList, 'hex'));
|
|
2900
3557
|
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
2901
3558
|
const lit = await LitProtocol.create({
|
|
2902
|
-
chain: options?.topArgs?.
|
|
2903
|
-
litNetwork: options?.topArgs?.
|
|
3559
|
+
chain: options?.topArgs?.dkgOptions?.chain,
|
|
3560
|
+
litNetwork: options?.topArgs?.dkgOptions?.network
|
|
2904
3561
|
});
|
|
3562
|
+
// construct access control conditions
|
|
3563
|
+
const unifiedAccessControlConditions = await Promise.all(publishedList.metadata.paymentConditions.map(async (condition) => {
|
|
3564
|
+
switch (condition.type) {
|
|
3565
|
+
case AccessControlConditionTypes.timelockPayment:
|
|
3566
|
+
return await LitProtocol.generateCosmosAccessControlConditionInverseTimelock({
|
|
3567
|
+
key: '$.tx_responses.*.timestamp',
|
|
3568
|
+
comparator: '<=',
|
|
3569
|
+
value: `${condition.intervalInSeconds}`,
|
|
3570
|
+
}, condition.feePaymentAmount, condition.feePaymentAddress, condition?.blockHeight, options?.topArgs?.dkgOptions?.chain);
|
|
3571
|
+
default:
|
|
3572
|
+
throw new Error(`[did-provider-cheqd]: unsupported access control condition type ${condition.type}`);
|
|
3573
|
+
}
|
|
3574
|
+
}));
|
|
2905
3575
|
// decrypt
|
|
2906
|
-
return await lit.decrypt(scopedRawBlob,
|
|
3576
|
+
return await lit.decrypt(scopedRawBlob, publishedList.metadata.encryptedSymmetricKey, unifiedAccessControlConditions);
|
|
2907
3577
|
}())
|
|
2908
3578
|
: (await async function () {
|
|
2909
3579
|
// transcode to base64url, if needed
|
|
@@ -2918,7 +3588,7 @@ export class Cheqd {
|
|
|
2918
3588
|
const encoded = new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
2919
3589
|
// validate against published list
|
|
2920
3590
|
if (encoded !== publishedListTranscoded)
|
|
2921
|
-
throw new Error('[did-provider-cheqd]:
|
|
3591
|
+
throw new Error('[did-provider-cheqd]: check: suspension: statusListFile does not match published status list 2021');
|
|
2922
3592
|
// return encoded
|
|
2923
3593
|
return encoded;
|
|
2924
3594
|
}
|
|
@@ -2928,15 +3598,15 @@ export class Cheqd {
|
|
|
2928
3598
|
const decrypted = await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
2929
3599
|
// validate against published list
|
|
2930
3600
|
if (decrypted !== publishedListTranscoded)
|
|
2931
|
-
throw new Error('[did-provider-cheqd]:
|
|
3601
|
+
throw new Error('[did-provider-cheqd]: check: suspension: statusListFile does not match published status list 2021');
|
|
2932
3602
|
// return decrypted
|
|
2933
3603
|
return decrypted;
|
|
2934
3604
|
}
|
|
2935
3605
|
if (!options?.statusListInlineBitstring)
|
|
2936
|
-
throw new Error('[did-provider-cheqd]:
|
|
3606
|
+
throw new Error('[did-provider-cheqd]: check: suspension: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
2937
3607
|
// validate against published list
|
|
2938
3608
|
if (options?.statusListInlineBitstring !== publishedListTranscoded)
|
|
2939
|
-
throw new Error('[did-provider-cheqd]:
|
|
3609
|
+
throw new Error('[did-provider-cheqd]: check: suspension: statusListInlineBitstring does not match published status list 2021');
|
|
2940
3610
|
// otherwise, read from inline bitstring
|
|
2941
3611
|
return options?.statusListInlineBitstring;
|
|
2942
3612
|
}());
|