@cheqd/did-provider-cheqd 3.2.1 → 3.3.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 +513 -14
- package/build/cjs/agent/ICheqd.d.ts.map +1 -1
- package/build/cjs/agent/ICheqd.js +1446 -5
- package/build/cjs/agent/ICheqd.js.map +1 -1
- package/build/cjs/did-manager/cheqd-did-provider.d.ts +26 -7
- package/build/cjs/did-manager/cheqd-did-provider.d.ts.map +1 -1
- package/build/cjs/did-manager/cheqd-did-provider.js +30 -8
- package/build/cjs/did-manager/cheqd-did-provider.js.map +1 -1
- package/build/cjs/did-manager/cheqd-did-resolver.d.ts +5 -0
- package/build/cjs/did-manager/cheqd-did-resolver.d.ts.map +1 -1
- package/build/cjs/did-manager/cheqd-did-resolver.js +7 -2
- package/build/cjs/did-manager/cheqd-did-resolver.js.map +1 -1
- package/build/cjs/dkg-threshold/lit-protocol.d.ts +92 -0
- package/build/cjs/dkg-threshold/lit-protocol.d.ts.map +1 -0
- package/build/cjs/dkg-threshold/lit-protocol.js +170 -0
- package/build/cjs/dkg-threshold/lit-protocol.js.map +1 -0
- package/build/cjs/global.d..d.ts +2 -0
- package/build/cjs/global.d..d.ts.map +1 -0
- package/build/cjs/global.d..js +2 -0
- package/build/cjs/global.d..js.map +1 -0
- package/build/cjs/index.js +1 -2
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/utils/env.d.ts +7 -0
- package/build/cjs/utils/env.d.ts.map +1 -0
- package/build/cjs/utils/env.js +10 -0
- package/build/cjs/utils/env.js.map +1 -0
- package/build/cjs/utils/helpers.d.ts +12 -0
- package/build/cjs/utils/helpers.d.ts.map +1 -0
- package/build/cjs/utils/helpers.js +63 -0
- package/build/cjs/utils/helpers.js.map +1 -0
- package/build/esm/agent/ICheqd.d.ts +513 -14
- package/build/esm/agent/ICheqd.d.ts.map +1 -1
- package/build/esm/agent/ICheqd.js +1446 -5
- package/build/esm/agent/ICheqd.js.map +1 -1
- package/build/esm/did-manager/cheqd-did-provider.d.ts +26 -7
- package/build/esm/did-manager/cheqd-did-provider.d.ts.map +1 -1
- package/build/esm/did-manager/cheqd-did-provider.js +29 -7
- package/build/esm/did-manager/cheqd-did-provider.js.map +1 -1
- package/build/esm/did-manager/cheqd-did-resolver.d.ts +5 -0
- package/build/esm/did-manager/cheqd-did-resolver.d.ts.map +1 -1
- package/build/esm/did-manager/cheqd-did-resolver.js +6 -1
- package/build/esm/did-manager/cheqd-did-resolver.js.map +1 -1
- package/build/esm/dkg-threshold/lit-protocol.d.ts +92 -0
- package/build/esm/dkg-threshold/lit-protocol.d.ts.map +1 -0
- package/build/esm/dkg-threshold/lit-protocol.js +166 -0
- package/build/esm/dkg-threshold/lit-protocol.js.map +1 -0
- package/build/esm/global.d..d.ts +2 -0
- package/build/esm/global.d..d.ts.map +1 -0
- package/build/esm/global.d..js +2 -0
- package/build/esm/global.d..js.map +1 -0
- package/build/esm/index.js +1 -1
- package/build/esm/index.js.map +1 -1
- package/build/esm/utils/env.d.ts +7 -0
- package/build/esm/utils/env.d.ts.map +1 -0
- package/build/esm/utils/env.js +7 -0
- package/build/esm/utils/env.js.map +1 -0
- package/build/esm/utils/helpers.d.ts +12 -0
- package/build/esm/utils/helpers.d.ts.map +1 -0
- package/build/esm/utils/helpers.js +51 -0
- package/build/esm/utils/helpers.js.map +1 -0
- 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 +513 -14
- package/build/types/agent/ICheqd.d.ts.map +1 -1
- package/build/types/did-manager/cheqd-did-provider.d.ts +26 -7
- package/build/types/did-manager/cheqd-did-provider.d.ts.map +1 -1
- package/build/types/did-manager/cheqd-did-resolver.d.ts +5 -0
- package/build/types/did-manager/cheqd-did-resolver.d.ts.map +1 -1
- package/build/types/dkg-threshold/lit-protocol.d.ts +92 -0
- package/build/types/dkg-threshold/lit-protocol.d.ts.map +1 -0
- package/build/types/global.d..d.ts +2 -0
- package/build/types/global.d..d.ts.map +1 -0
- package/build/types/utils/env.d.ts +7 -0
- package/build/types/utils/env.d.ts.map +1 -0
- package/build/types/utils/helpers.d.ts +12 -0
- package/build/types/utils/helpers.d.ts.map +1 -0
- package/package.json +7 -1
- package/src/agent/ICheqd.ts +2209 -232
- package/src/did-manager/cheqd-did-provider.ts +55 -8
- package/src/did-manager/cheqd-did-resolver.ts +7 -1
- package/src/dkg-threshold/lit-protocol.ts +238 -0
- package/src/global.d..ts +1 -0
- package/src/utils/env.ts +6 -0
- package/src/utils/helpers.ts +66 -0
- package/tsconfig.json +1 -0
|
@@ -2,20 +2,45 @@
|
|
|
2
2
|
// any is used for extensibility
|
|
3
3
|
// unused vars are kept by convention
|
|
4
4
|
// non-null assertion is used when we know better than the compiler that the value is not null or undefined
|
|
5
|
-
import { createDidPayload, createDidVerificationMethod, createKeyPairBase64, createKeyPairHex, createVerificationKeys } from '@cheqd/sdk';
|
|
5
|
+
import { CheqdNetwork, createDidPayload, createDidVerificationMethod, createKeyPairBase64, createKeyPairHex, createVerificationKeys } from '@cheqd/sdk';
|
|
6
|
+
import { DefaultRESTUrls } from '../did-manager/cheqd-did-provider.js';
|
|
6
7
|
import { fromString, toString } from 'uint8arrays';
|
|
8
|
+
import { decodeJWT } from 'did-jwt';
|
|
9
|
+
import { StatusList } from '@digitalbazaar/vc-status-list';
|
|
7
10
|
import { v4 } from 'uuid';
|
|
8
11
|
import fs from 'fs';
|
|
9
12
|
import Debug from 'debug';
|
|
13
|
+
import { LitCompatibleCosmosChains, LitProtocol } from '../dkg-threshold/lit-protocol.js';
|
|
14
|
+
import { blobToHexString, randomFromRange, toBlob, unescapeUnicode } from '../utils/helpers.js';
|
|
15
|
+
import { resolverUrl } from '../did-manager/cheqd-did-resolver.js';
|
|
10
16
|
const debug = Debug('veramo:did-provider-cheqd');
|
|
17
|
+
export const AccessControlConditionTypes = { memoNonce: 'memoNonce', balance: 'balance' };
|
|
18
|
+
export const AccessControlConditionReturnValueComparators = { lessThan: '<', greaterThan: '>', equalTo: '=', lessThanOrEqualTo: '<=', greaterThanOrEqualTo: '>=' };
|
|
11
19
|
const CreateIdentifierMethodName = 'cheqdCreateIdentifier';
|
|
12
20
|
const UpdateIdentifierMethodName = 'cheqdUpdateIdentifier';
|
|
13
21
|
const DeactivateIdentifierMethodName = 'cheqdDeactivateIdentifier';
|
|
14
22
|
const CreateResourceMethodName = 'cheqdCreateLinkedResource';
|
|
23
|
+
const CreateStatusList2021MethodName = 'cheqdCreateStatusList2021';
|
|
24
|
+
const CreateEncryptedStatusList2021MethodName = 'cheqdCreateEncryptedStatusList2021';
|
|
15
25
|
const GenerateDidDocMethodName = 'cheqdGenerateDidDoc';
|
|
16
26
|
const GenerateDidDocWithLinkedResourceMethodName = 'cheqdGenerateDidDocWithLinkedResource';
|
|
17
27
|
const GenerateKeyPairMethodName = 'cheqdGenerateIdentityKeys';
|
|
18
28
|
const GenerateVersionIdMethodName = 'cheqdGenerateVersionId';
|
|
29
|
+
const GenerateStatusList2021MethodName = 'cheqdGenerateStatusList2021';
|
|
30
|
+
const GenerateEncryptedStatusList2021MethodName = 'cheqdGenerateEncryptedStatusList2021';
|
|
31
|
+
const IssueRevocableCredentialWithStatusList2021MethodName = 'cheqdIssueRevocableCredentialWithStatusList2021';
|
|
32
|
+
const IssueSuspendableCredentialWithStatusList2021MethodName = 'cheqdIssueSuspendableCredentialWithStatusList2021';
|
|
33
|
+
const VerifyCredentialMethodName = 'cheqdVerifyCredential';
|
|
34
|
+
const VerifyPresentationMethodName = 'cheqdVerifyPresentation';
|
|
35
|
+
const CheckCredentialStatusMethodName = 'cheqdCheckCredentialStatus';
|
|
36
|
+
const RevokeCredentialMethodName = 'cheqdRevokeCredential';
|
|
37
|
+
const RevokeCredentialsMethodName = 'cheqdRevokeCredentials';
|
|
38
|
+
const SuspendCredentialMethodName = 'cheqdSuspendCredential';
|
|
39
|
+
const SuspendCredentialsMethodName = 'cheqdSuspendCredentials';
|
|
40
|
+
const UnsuspendCredentialMethodName = 'cheqdUnsuspendCredential';
|
|
41
|
+
const UnsuspendCredentialsMethodName = 'cheqdUnsuspendCredentials';
|
|
42
|
+
const TransactVerifierPaysIssuerMethodName = 'cheqdTransactVerifierPaysIssuer';
|
|
43
|
+
const ObserveVerifierPaysIssuerMethodName = 'cheqdObserveVerifierPaysIssuer';
|
|
19
44
|
const DidPrefix = 'did';
|
|
20
45
|
const CheqdDidMethod = 'cheqd';
|
|
21
46
|
export class Cheqd {
|
|
@@ -92,6 +117,42 @@ export class Cheqd {
|
|
|
92
117
|
"args"
|
|
93
118
|
]
|
|
94
119
|
},
|
|
120
|
+
"returnType": {
|
|
121
|
+
"type": "boolean"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"cheqdCreateStatusList2021": {
|
|
125
|
+
"description": "Create a new Status List 2021",
|
|
126
|
+
"arguments": {
|
|
127
|
+
"type": "object",
|
|
128
|
+
"properties": {
|
|
129
|
+
"args": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"description": "A cheqdCreateStatusList2021Args object as any for extensibility"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"required": [
|
|
135
|
+
"args"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
"returnType": {
|
|
139
|
+
"type": "boolean"
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"cheqdCreateEncryptedStatusList2021": {
|
|
143
|
+
"description": "Create a new Encrypted Status List 2021",
|
|
144
|
+
"arguments": {
|
|
145
|
+
"type": "object",
|
|
146
|
+
"properties": {
|
|
147
|
+
"args": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"description": "A cheqdCreateEncryptedStatusList2021Args object as any for extensibility"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"required": [
|
|
153
|
+
"args"
|
|
154
|
+
]
|
|
155
|
+
},
|
|
95
156
|
"returnType": {
|
|
96
157
|
"type": "object"
|
|
97
158
|
}
|
|
@@ -156,7 +217,274 @@ export class Cheqd {
|
|
|
156
217
|
"type": "object",
|
|
157
218
|
"description": "A cheqdGenerateVersionIdArgs object as any for extensibility"
|
|
158
219
|
}
|
|
159
|
-
}
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
"returnType": {
|
|
223
|
+
"type": "object"
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
"cheqdGenerateStatusList2021": {
|
|
227
|
+
"description": "Generate a new Status List 2021",
|
|
228
|
+
"arguments": {
|
|
229
|
+
"type": "object",
|
|
230
|
+
"properties": {
|
|
231
|
+
"args": {
|
|
232
|
+
"type": "object",
|
|
233
|
+
"description": "A cheqdGenerateStatusList2021Args object as any for extensibility"
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
"returnType": {
|
|
238
|
+
"type": "string"
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
"cheqdGenerateEncryptedStatusList2021": {
|
|
242
|
+
"description": "Generate a new encrypted Status List 2021",
|
|
243
|
+
"arguments": {
|
|
244
|
+
"type": "object",
|
|
245
|
+
"properties": {
|
|
246
|
+
"args": {
|
|
247
|
+
"type": "object",
|
|
248
|
+
"description": "A cheqdGenerateEncryptedStatusList2021Args object as any for extensibility"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"required": [
|
|
252
|
+
"args"
|
|
253
|
+
]
|
|
254
|
+
},
|
|
255
|
+
"returnType": {
|
|
256
|
+
"type": "string"
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
"cheqdIssueRevocableCredentialWithStatusList2021": {
|
|
260
|
+
"description": "Issue a revocable credential with a Status List 2021 as credential status registry",
|
|
261
|
+
"arguments": {
|
|
262
|
+
"type": "object",
|
|
263
|
+
"properties": {
|
|
264
|
+
"args": {
|
|
265
|
+
"type": "object",
|
|
266
|
+
"description": "A cheqdIssueCredentialWithStatusList2021Args object as any for extensibility"
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"required": [
|
|
270
|
+
"args"
|
|
271
|
+
]
|
|
272
|
+
},
|
|
273
|
+
"returnType": {
|
|
274
|
+
"type": "object"
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
"cheqdIssueSuspendableCredentialWithStatusList2021": {
|
|
278
|
+
"description": "Issue a suspendable credential with a Status List 2021 as credential status registry",
|
|
279
|
+
"arguments": {
|
|
280
|
+
"type": "object",
|
|
281
|
+
"properties": {
|
|
282
|
+
"args": {
|
|
283
|
+
"type": "object",
|
|
284
|
+
"description": "A cheqdIssueCredentialWithStatusList2021Args object as any for extensibility"
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
"required": [
|
|
288
|
+
"args"
|
|
289
|
+
]
|
|
290
|
+
},
|
|
291
|
+
"returnType": {
|
|
292
|
+
"type": "object"
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
"cheqdVerifyCredential": {
|
|
296
|
+
"description": "Verify a credential, enhanced by revocation / suspension check with a Status List 2021 as credential status registry",
|
|
297
|
+
"arguments": {
|
|
298
|
+
"type": "object",
|
|
299
|
+
"properties": {
|
|
300
|
+
"args": {
|
|
301
|
+
"type": "object",
|
|
302
|
+
"description": "A cheqdVerifyCredentialWithStatusList2021Args object as any for extensibility"
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
"required": [
|
|
306
|
+
"args"
|
|
307
|
+
]
|
|
308
|
+
},
|
|
309
|
+
"returnType": {
|
|
310
|
+
"type": "object"
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
"cheqdVerifyPresentation": {
|
|
314
|
+
"description": "Verify a presentation, enhanced by revocation / suspension check with a Status List 2021 as credential status registry",
|
|
315
|
+
"arguments": {
|
|
316
|
+
"type": "object",
|
|
317
|
+
"properties": {
|
|
318
|
+
"args": {
|
|
319
|
+
"type": "object",
|
|
320
|
+
"description": "A cheqdVerifyPresentationWithStatusList2021Args object as any for extensibility"
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
"required": [
|
|
324
|
+
"args"
|
|
325
|
+
]
|
|
326
|
+
},
|
|
327
|
+
"returnType": {
|
|
328
|
+
"type": "object"
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
"cheqdCheckCredentialStatus": {
|
|
332
|
+
"description": "Check the revocation / suspension status of a credential with a Status List 2021 as credential status registry",
|
|
333
|
+
"arguments": {
|
|
334
|
+
"type": "object",
|
|
335
|
+
"properties": {
|
|
336
|
+
"args": {
|
|
337
|
+
"type": "object",
|
|
338
|
+
"description": "A cheqdCheckCredentialStatusWithStatusList2021Args object as any for extensibility"
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
"required": [
|
|
342
|
+
"args"
|
|
343
|
+
]
|
|
344
|
+
},
|
|
345
|
+
"returnType": {
|
|
346
|
+
"type": "object"
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
"cheqdRevokeCredential": {
|
|
350
|
+
"description": "Revoke a credential against a Status List 2021 as credential status registry",
|
|
351
|
+
"arguments": {
|
|
352
|
+
"type": "object",
|
|
353
|
+
"properties": {
|
|
354
|
+
"args": {
|
|
355
|
+
"type": "object",
|
|
356
|
+
"description": "A cheqdRevokeCredentialWithStatusList2021Args object as any for extensibility"
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"required": [
|
|
360
|
+
"args"
|
|
361
|
+
]
|
|
362
|
+
},
|
|
363
|
+
"returnType": {
|
|
364
|
+
"type": "object"
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
"cheqdRevokeCredentials": {
|
|
368
|
+
"description": "Revoke multiple credentials against a Status List 2021 as credential status registry",
|
|
369
|
+
"arguments": {
|
|
370
|
+
"type": "object",
|
|
371
|
+
"properties": {
|
|
372
|
+
"args": {
|
|
373
|
+
"type": "object",
|
|
374
|
+
"description": "A cheqdRevokeBulkCredentialsWithStatusList2021Args object as any for extensibility"
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
"required": [
|
|
378
|
+
"args"
|
|
379
|
+
]
|
|
380
|
+
},
|
|
381
|
+
"returnType": {
|
|
382
|
+
"type": "array"
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
"cheqdSuspendCredential": {
|
|
386
|
+
"description": "Suspend a credential against a Status List 2021 as credential status registry",
|
|
387
|
+
"arguments": {
|
|
388
|
+
"type": "object",
|
|
389
|
+
"properties": {
|
|
390
|
+
"args": {
|
|
391
|
+
"type": "object",
|
|
392
|
+
"description": "A cheqdSuspendCredentialWithStatusList2021Args object as any for extensibility"
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
"required": [
|
|
396
|
+
"args"
|
|
397
|
+
]
|
|
398
|
+
},
|
|
399
|
+
"returnType": {
|
|
400
|
+
"type": "object"
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
"cheqdSuspendCredentials": {
|
|
404
|
+
"description": "Suspend multiple credentials against a Status List 2021 as credential status registry",
|
|
405
|
+
"arguments": {
|
|
406
|
+
"type": "object",
|
|
407
|
+
"properties": {
|
|
408
|
+
"args": {
|
|
409
|
+
"type": "object",
|
|
410
|
+
"description": "A cheqdSuspendBulkCredentialsWithStatusList2021Args object as any for extensibility"
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
"required": [
|
|
414
|
+
"args"
|
|
415
|
+
]
|
|
416
|
+
},
|
|
417
|
+
"returnType": {
|
|
418
|
+
"type": "array"
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
"cheqdUnsuspendCredential": {
|
|
422
|
+
"description": "Unsuspend a credential against a Status List 2021 as credential status registry",
|
|
423
|
+
"arguments": {
|
|
424
|
+
"type": "object",
|
|
425
|
+
"properties": {
|
|
426
|
+
"args": {
|
|
427
|
+
"type": "object",
|
|
428
|
+
"description": "cheqdUnsuspendCredentialWithStatusList2021Args object as any for extensibility"
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
"required": [
|
|
432
|
+
"args"
|
|
433
|
+
]
|
|
434
|
+
},
|
|
435
|
+
"returnType": {
|
|
436
|
+
"type": "object"
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
"cheqdUnsuspendCredentials": {
|
|
440
|
+
"description": "Unsuspend multiple credentials against a Status List 2021 as credential status registry",
|
|
441
|
+
"arguments": {
|
|
442
|
+
"type": "object",
|
|
443
|
+
"properties": {
|
|
444
|
+
"args": {
|
|
445
|
+
"type": "object",
|
|
446
|
+
"description": "A cheqdUnsuspendBulkCredentialsWithStatusList2021Args object as any for extensibility"
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
"required": [
|
|
450
|
+
"args"
|
|
451
|
+
]
|
|
452
|
+
},
|
|
453
|
+
"returnType": {
|
|
454
|
+
"type": "array"
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
"cheqdTransactVerifierPaysIssuer": {
|
|
458
|
+
"description": "Initiate a transaction where the verifier pays the issuer for a credential status check",
|
|
459
|
+
"arguments": {
|
|
460
|
+
"type": "object",
|
|
461
|
+
"properties": {
|
|
462
|
+
"args": {
|
|
463
|
+
"type": "object",
|
|
464
|
+
"description": "A cheqdTransactVerifierPaysIssuerArgs object as any for extensibility"
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
"required": [
|
|
468
|
+
"args"
|
|
469
|
+
]
|
|
470
|
+
},
|
|
471
|
+
"returnType": {
|
|
472
|
+
"type": "object"
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
"cheqdObserveVerifierPaysIssuer": {
|
|
476
|
+
"description": "Observe a transaction where the verifier pays the issuer for a credential status check",
|
|
477
|
+
"arguments": {
|
|
478
|
+
"type": "object",
|
|
479
|
+
"properties": {
|
|
480
|
+
"args": {
|
|
481
|
+
"type": "object",
|
|
482
|
+
"description": "cheqdObserveVerifierPaysIssuerArgs object as any for extensibility"
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
"required": [
|
|
486
|
+
"args"
|
|
487
|
+
]
|
|
160
488
|
},
|
|
161
489
|
"returnType": {
|
|
162
490
|
"type": "object"
|
|
@@ -168,6 +496,9 @@ export class Cheqd {
|
|
|
168
496
|
supportedDidProviders;
|
|
169
497
|
didProvider;
|
|
170
498
|
providerId;
|
|
499
|
+
static defaultStatusList2021Length = 16 * 1024 * 8; // 16KB in bits or 131072 bits / entries
|
|
500
|
+
static defaultContextV1 = 'https://www.w3.org/2018/credentials/v1';
|
|
501
|
+
static statusList2021Context = 'https://w3id.org/vc-status-list-2021/v1';
|
|
171
502
|
constructor(args) {
|
|
172
503
|
if (typeof args.providers !== 'object') {
|
|
173
504
|
throw new Error('[did-provider-cheqd]: at least one did provider is required');
|
|
@@ -180,10 +511,27 @@ export class Cheqd {
|
|
|
180
511
|
[UpdateIdentifierMethodName]: this.UpdateIdentifier.bind(this),
|
|
181
512
|
[DeactivateIdentifierMethodName]: this.DeactivateIdentifier.bind(this),
|
|
182
513
|
[CreateResourceMethodName]: this.CreateResource.bind(this),
|
|
514
|
+
[CreateStatusList2021MethodName]: this.CreateStatusList2021.bind(this),
|
|
515
|
+
[CreateEncryptedStatusList2021MethodName]: this.CreateEncryptedStatusList2021.bind(this),
|
|
183
516
|
[GenerateDidDocMethodName]: this.GenerateDidDoc.bind(this),
|
|
184
517
|
[GenerateDidDocWithLinkedResourceMethodName]: this.GenerateDidDocWithLinkedResource.bind(this),
|
|
185
518
|
[GenerateKeyPairMethodName]: this.GenerateIdentityKeys.bind(this),
|
|
186
|
-
[GenerateVersionIdMethodName]: this.GenerateVersionId.bind(this)
|
|
519
|
+
[GenerateVersionIdMethodName]: this.GenerateVersionId.bind(this),
|
|
520
|
+
[GenerateStatusList2021MethodName]: this.GenerateStatusList2021.bind(this),
|
|
521
|
+
[GenerateEncryptedStatusList2021MethodName]: this.GenerateEncryptedStatusList2021.bind(this),
|
|
522
|
+
[IssueRevocableCredentialWithStatusList2021MethodName]: this.IssueRevocableCredentialWithStatusList2021.bind(this),
|
|
523
|
+
[IssueSuspendableCredentialWithStatusList2021MethodName]: this.IssueSuspendableCredentialWithStatusList2021.bind(this),
|
|
524
|
+
[VerifyCredentialMethodName]: this.VerifyCredentialWithStatusList2021.bind(this),
|
|
525
|
+
[VerifyPresentationMethodName]: this.VerifyPresentationWithStatusList2021.bind(this),
|
|
526
|
+
[CheckCredentialStatusMethodName]: this.CheckCredentialStatusWithStatusList2021.bind(this),
|
|
527
|
+
[RevokeCredentialMethodName]: this.RevokeCredentialWithStatusList2021.bind(this),
|
|
528
|
+
[RevokeCredentialsMethodName]: this.RevokeBulkCredentialsWithStatusList2021.bind(this),
|
|
529
|
+
[SuspendCredentialMethodName]: this.SuspendCredentialWithStatusList2021.bind(this),
|
|
530
|
+
[SuspendCredentialsMethodName]: this.SuspendBulkCredentialsWithStatusList2021.bind(this),
|
|
531
|
+
[UnsuspendCredentialMethodName]: this.UnsuspendCredentialWithStatusList2021.bind(this),
|
|
532
|
+
[UnsuspendCredentialsMethodName]: this.UnsuspendBulkCredentialsWithStatusList2021.bind(this),
|
|
533
|
+
[TransactVerifierPaysIssuerMethodName]: this.TransactVerifierPaysIssuer.bind(this),
|
|
534
|
+
[ObserveVerifierPaysIssuerMethodName]: this.ObserveVerifierPaysIssuer.bind(this),
|
|
187
535
|
};
|
|
188
536
|
}
|
|
189
537
|
async CreateIdentifier(args, context) {
|
|
@@ -224,7 +572,6 @@ export class Cheqd {
|
|
|
224
572
|
return await context.agent.didManagerUpdate({
|
|
225
573
|
did: args.document.id,
|
|
226
574
|
document: args.document,
|
|
227
|
-
provider: this.providerId,
|
|
228
575
|
options: {
|
|
229
576
|
kms: args.kms,
|
|
230
577
|
keys: args.keys,
|
|
@@ -263,7 +610,7 @@ export class Cheqd {
|
|
|
263
610
|
throw new Error('[did-provider-cheqd]: network is required');
|
|
264
611
|
}
|
|
265
612
|
if (args?.file) {
|
|
266
|
-
args.payload.data =
|
|
613
|
+
args.payload.data = await Cheqd.getFile(args.file);
|
|
267
614
|
}
|
|
268
615
|
if (typeof args?.payload?.data === 'string') {
|
|
269
616
|
args.payload.data = fromString(args.payload.data, 'base64');
|
|
@@ -279,6 +626,110 @@ export class Cheqd {
|
|
|
279
626
|
}
|
|
280
627
|
}, context);
|
|
281
628
|
}
|
|
629
|
+
async CreateStatusList2021(args, context) {
|
|
630
|
+
if (typeof args.kms !== 'string') {
|
|
631
|
+
throw new Error('[did-provider-cheqd]: kms is required');
|
|
632
|
+
}
|
|
633
|
+
if (typeof args.payload !== 'object') {
|
|
634
|
+
throw new Error('[did-provider-cheqd]: payload object is required');
|
|
635
|
+
}
|
|
636
|
+
if (typeof args.network !== 'string') {
|
|
637
|
+
throw new Error('[did-provider-cheqd]: network is required');
|
|
638
|
+
}
|
|
639
|
+
if (args?.file) {
|
|
640
|
+
args.payload.data = await Cheqd.getFile(args.file);
|
|
641
|
+
}
|
|
642
|
+
if (typeof args?.payload?.data === 'string') {
|
|
643
|
+
args.payload.data = fromString(args.payload.data, 'base64');
|
|
644
|
+
}
|
|
645
|
+
// TODO: validate data as per bitstring
|
|
646
|
+
// set default resource type in runtime
|
|
647
|
+
args.payload.resourceType = 'StatusList2021';
|
|
648
|
+
this.providerId = Cheqd.generateProviderId(args.network);
|
|
649
|
+
this.didProvider = await Cheqd.loadProvider({ id: this.providerId }, this.supportedDidProviders);
|
|
650
|
+
return await this.didProvider.createResource({
|
|
651
|
+
options: {
|
|
652
|
+
kms: args.kms,
|
|
653
|
+
payload: args.payload,
|
|
654
|
+
signInputs: args.signInputs,
|
|
655
|
+
fee: args?.fee
|
|
656
|
+
}
|
|
657
|
+
}, context);
|
|
658
|
+
}
|
|
659
|
+
async CreateEncryptedStatusList2021(args, context) {
|
|
660
|
+
if (typeof args.kms !== 'string') {
|
|
661
|
+
throw new Error('[did-provider-cheqd]: kms is required');
|
|
662
|
+
}
|
|
663
|
+
if (typeof args.payload !== 'object') {
|
|
664
|
+
throw new Error('[did-provider-cheqd]: payload object is required');
|
|
665
|
+
}
|
|
666
|
+
if (typeof args.network !== 'string') {
|
|
667
|
+
throw new Error('[did-provider-cheqd]: network is required');
|
|
668
|
+
}
|
|
669
|
+
if (args?.file) {
|
|
670
|
+
args.payload.data = await Cheqd.getFile(args.file);
|
|
671
|
+
}
|
|
672
|
+
if (typeof args?.payload?.data === 'string') {
|
|
673
|
+
args.payload.data = fromString(args.payload.data, 'base64');
|
|
674
|
+
}
|
|
675
|
+
// TODO: validate data as per bitstring
|
|
676
|
+
if (!args?.encryptionOptions) {
|
|
677
|
+
throw new Error('[did-provider-cheqd]: encryptionOptions is required');
|
|
678
|
+
}
|
|
679
|
+
if (!args?.bootstrapOptions) {
|
|
680
|
+
throw new Error('[did-provider-cheqd]: bootstrapOptions is required');
|
|
681
|
+
}
|
|
682
|
+
if (!args?.encryptionOptions?.accessControlConditions) {
|
|
683
|
+
throw new Error('[did-provider-cheqd]: accessControlConditions is required');
|
|
684
|
+
}
|
|
685
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
686
|
+
const lit = await LitProtocol.create({
|
|
687
|
+
chain: args.bootstrapOptions?.chain,
|
|
688
|
+
litNetwork: args.bootstrapOptions?.litNetwork
|
|
689
|
+
});
|
|
690
|
+
// construct access control conditions
|
|
691
|
+
const unifiedAccessControlConditions = await Promise.all(args.encryptionOptions.accessControlConditions.map(async (condition) => {
|
|
692
|
+
switch (condition.type) {
|
|
693
|
+
case AccessControlConditionTypes.memoNonce:
|
|
694
|
+
return await LitProtocol.generateCosmosAccessControlConditionTransactionMemo({
|
|
695
|
+
key: '$.txs.*.body.memo',
|
|
696
|
+
comparator: 'contains',
|
|
697
|
+
value: condition?.specificNonce || await LitProtocol.generateTxNonce(condition?.nonceFormat)
|
|
698
|
+
}, condition.amountObserved, condition.senderAddressObserved, condition.recipientAddressObserved, args.bootstrapOptions.chain);
|
|
699
|
+
case AccessControlConditionTypes.balance:
|
|
700
|
+
return await LitProtocol.generateCosmosAccessControlConditionBalance({
|
|
701
|
+
key: '$.balances[0].amount',
|
|
702
|
+
comparator: condition.comparator,
|
|
703
|
+
value: condition.amountObserved
|
|
704
|
+
}, args.bootstrapOptions.chain, condition.addressObserved);
|
|
705
|
+
default:
|
|
706
|
+
throw new Error(`[did-provider-cheqd]: accessControlCondition type is not supported`);
|
|
707
|
+
}
|
|
708
|
+
}));
|
|
709
|
+
// encrypt data
|
|
710
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(toString(args.payload.data, 'base64url'), unifiedAccessControlConditions, true);
|
|
711
|
+
// set encrypted data
|
|
712
|
+
args.payload.data = new Uint8Array(await encryptedString.arrayBuffer());
|
|
713
|
+
// set default resource type in runtime
|
|
714
|
+
args.payload.resourceType = 'StatusList2021';
|
|
715
|
+
this.providerId = Cheqd.generateProviderId(args.network);
|
|
716
|
+
this.didProvider = await Cheqd.loadProvider({ id: this.providerId }, this.supportedDidProviders);
|
|
717
|
+
const created = await this.didProvider.createResource({
|
|
718
|
+
options: {
|
|
719
|
+
kms: args.kms,
|
|
720
|
+
payload: args.payload,
|
|
721
|
+
signInputs: args.signInputs,
|
|
722
|
+
fee: args?.fee
|
|
723
|
+
}
|
|
724
|
+
}, context);
|
|
725
|
+
return {
|
|
726
|
+
created,
|
|
727
|
+
encryptedSymmetricKey,
|
|
728
|
+
encryptedStatusList2021: await blobToHexString(encryptedString),
|
|
729
|
+
symmetricKey: args?.encryptionOptions?.returnSymmetricKey ? toString(symmetricKey, 'hex') : undefined,
|
|
730
|
+
unifiedAccessControlConditions
|
|
731
|
+
};
|
|
732
|
+
}
|
|
282
733
|
async GenerateDidDoc(args, context) {
|
|
283
734
|
if (typeof args.verificationMethod !== 'string') {
|
|
284
735
|
throw new Error('[did-provider-cheqd]: verificationMethod is required');
|
|
@@ -355,6 +806,978 @@ export class Cheqd {
|
|
|
355
806
|
async GenerateVersionId(args, context) {
|
|
356
807
|
return v4();
|
|
357
808
|
}
|
|
809
|
+
async GenerateStatusList2021(args, context) {
|
|
810
|
+
const statusList = args?.buffer
|
|
811
|
+
? new StatusList({ buffer: args.buffer })
|
|
812
|
+
: new StatusList({ length: args?.length || Cheqd.defaultStatusList2021Length });
|
|
813
|
+
const encoded = await statusList.encode();
|
|
814
|
+
switch (args?.bitstringEncoding) {
|
|
815
|
+
case 'base64url':
|
|
816
|
+
return encoded;
|
|
817
|
+
case 'base64':
|
|
818
|
+
return toString(fromString(encoded, 'base64url'), 'base64');
|
|
819
|
+
case 'hex':
|
|
820
|
+
return toString(fromString(encoded, 'base64url'), 'hex');
|
|
821
|
+
default:
|
|
822
|
+
return encoded;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
async GenerateEncryptedStatusList2021(args, context) {
|
|
826
|
+
// validate encryptionOptions
|
|
827
|
+
if (!args.encryptionOptions) {
|
|
828
|
+
throw new Error('[did-provider-cheqd]: encryptionOptions is required');
|
|
829
|
+
}
|
|
830
|
+
// validate encryptionOptions.accessControlConditions
|
|
831
|
+
if (!args.encryptionOptions.accessControlConditions) {
|
|
832
|
+
throw new Error('[did-provider-cheqd]: encryptionOptions.accessControlConditions is required');
|
|
833
|
+
}
|
|
834
|
+
// generate status list
|
|
835
|
+
const statusList = args?.buffer
|
|
836
|
+
? new StatusList({ buffer: args.buffer })
|
|
837
|
+
: new StatusList({ length: args?.length || Cheqd.defaultStatusList2021Length });
|
|
838
|
+
// encode status list
|
|
839
|
+
const encoded = await statusList.encode();
|
|
840
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
841
|
+
const lit = await LitProtocol.create({
|
|
842
|
+
chain: args.bootstrapOptions.chain,
|
|
843
|
+
litNetwork: args.bootstrapOptions.litNetwork,
|
|
844
|
+
});
|
|
845
|
+
// construct access control conditions
|
|
846
|
+
const unifiedAccessControlConditions = await Promise.all(args.encryptionOptions.accessControlConditions.map(async (condition) => {
|
|
847
|
+
switch (condition.type) {
|
|
848
|
+
case AccessControlConditionTypes.memoNonce:
|
|
849
|
+
return await LitProtocol.generateCosmosAccessControlConditionTransactionMemo({
|
|
850
|
+
key: '$.txs.*.body.memo',
|
|
851
|
+
comparator: 'contains',
|
|
852
|
+
value: condition?.specificNonce || await LitProtocol.generateTxNonce(condition?.nonceFormat)
|
|
853
|
+
}, condition.amountObserved, condition.senderAddressObserved, condition.recipientAddressObserved, args.bootstrapOptions.chain);
|
|
854
|
+
case AccessControlConditionTypes.balance:
|
|
855
|
+
return await LitProtocol.generateCosmosAccessControlConditionBalance({
|
|
856
|
+
key: '$.balances[0].amount',
|
|
857
|
+
comparator: condition.comparator,
|
|
858
|
+
value: condition.amountObserved
|
|
859
|
+
}, args.bootstrapOptions.chain, condition.addressObserved);
|
|
860
|
+
default:
|
|
861
|
+
throw new Error(`[did-provider-cheqd]: accessControlCondition type is not supported`);
|
|
862
|
+
}
|
|
863
|
+
}));
|
|
864
|
+
// encrypt data
|
|
865
|
+
const { encryptedString, encryptedSymmetricKey } = await lit.encrypt(encoded, unifiedAccessControlConditions);
|
|
866
|
+
// return result
|
|
867
|
+
return {
|
|
868
|
+
encryptedStatusList2021: await blobToHexString(encryptedString),
|
|
869
|
+
encryptedSymmetricKey,
|
|
870
|
+
unifiedAccessControlConditions
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
async IssueRevocableCredentialWithStatusList2021(args, context) {
|
|
874
|
+
// generate index
|
|
875
|
+
const statusListIndex = args.statusOptions.statusListIndex || await randomFromRange(args.statusOptions.statusListRangeStart || 0, (args.statusOptions.statusListRangeEnd || Cheqd.defaultStatusList2021Length) - 1, args.statusOptions.indexNotIn || []);
|
|
876
|
+
// construct issuer
|
|
877
|
+
const issuer = (args.issuanceOptions.credential.issuer.id)
|
|
878
|
+
? args.issuanceOptions.credential.issuer.id
|
|
879
|
+
: args.issuanceOptions.credential.issuer;
|
|
880
|
+
// generate status list credential
|
|
881
|
+
const statusListCredential = `${resolverUrl}${issuer}?resourceName=${args.statusOptions.statusListName}`;
|
|
882
|
+
// construct credential status
|
|
883
|
+
const credentialStatus = {
|
|
884
|
+
id: `${statusListCredential}#${statusListIndex}`,
|
|
885
|
+
type: 'StatusList2021Entry',
|
|
886
|
+
statusPurpose: 'revocation',
|
|
887
|
+
statusListIndex: `${statusListIndex}`,
|
|
888
|
+
statusListCredential,
|
|
889
|
+
};
|
|
890
|
+
// add credential status to credential
|
|
891
|
+
args.issuanceOptions.credential.credentialStatus = credentialStatus;
|
|
892
|
+
// add relevant context
|
|
893
|
+
args.issuanceOptions.credential['@context'] = function () {
|
|
894
|
+
// if no context is provided, add default context
|
|
895
|
+
if (!args.issuanceOptions.credential['@context']) {
|
|
896
|
+
return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
|
|
897
|
+
}
|
|
898
|
+
// if context is provided as an array, add default context if it is not already present
|
|
899
|
+
if (Array.isArray(args.issuanceOptions.credential['@context'])) {
|
|
900
|
+
if (args.issuanceOptions.credential['@context'].length === 0) {
|
|
901
|
+
return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
|
|
902
|
+
}
|
|
903
|
+
if (!args.issuanceOptions.credential['@context'].includes(Cheqd.statusList2021Context)) {
|
|
904
|
+
return [...args.issuanceOptions.credential['@context'], Cheqd.statusList2021Context];
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
// if context is provided as a string, add default context if it is not already present
|
|
908
|
+
if (typeof args.issuanceOptions.credential['@context'] === 'string')
|
|
909
|
+
return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
|
|
910
|
+
}();
|
|
911
|
+
// create a credential
|
|
912
|
+
const credential = await context.agent.createVerifiableCredential(args.issuanceOptions);
|
|
913
|
+
return credential;
|
|
914
|
+
}
|
|
915
|
+
async IssueSuspendableCredentialWithStatusList2021(args, context) {
|
|
916
|
+
// generate index
|
|
917
|
+
const statusListIndex = args.statusOptions.statusListIndex || await randomFromRange(args.statusOptions.statusListRangeStart || 0, (args.statusOptions.statusListRangeEnd || Cheqd.defaultStatusList2021Length) - 1, args.statusOptions.indexNotIn || []);
|
|
918
|
+
// construct issuer
|
|
919
|
+
const issuer = (args.issuanceOptions.credential.issuer.id)
|
|
920
|
+
? args.issuanceOptions.credential.issuer.id
|
|
921
|
+
: args.issuanceOptions.credential.issuer;
|
|
922
|
+
// generate status list credential
|
|
923
|
+
const statusListCredential = `${resolverUrl}${issuer}?resourceName=${args.statusOptions.statusListName}`;
|
|
924
|
+
// construct credential status
|
|
925
|
+
const credentialStatus = {
|
|
926
|
+
id: `${statusListCredential}#${statusListIndex}`,
|
|
927
|
+
type: 'StatusList2021Entry',
|
|
928
|
+
statusPurpose: 'suspension',
|
|
929
|
+
statusListIndex: `${statusListIndex}`,
|
|
930
|
+
statusListCredential,
|
|
931
|
+
};
|
|
932
|
+
// add credential status to credential
|
|
933
|
+
args.issuanceOptions.credential.credentialStatus = credentialStatus;
|
|
934
|
+
// add relevant context
|
|
935
|
+
args.issuanceOptions.credential['@context'] = function () {
|
|
936
|
+
// if no context is provided, add default context
|
|
937
|
+
if (!args.issuanceOptions.credential['@context']) {
|
|
938
|
+
return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
|
|
939
|
+
}
|
|
940
|
+
// if context is provided as an array, add default context if it is not already present
|
|
941
|
+
if (Array.isArray(args.issuanceOptions.credential['@context'])) {
|
|
942
|
+
if (args.issuanceOptions.credential['@context'].length === 0) {
|
|
943
|
+
return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
|
|
944
|
+
}
|
|
945
|
+
if (!args.issuanceOptions.credential['@context'].includes(Cheqd.statusList2021Context)) {
|
|
946
|
+
return [...args.issuanceOptions.credential['@context'], Cheqd.statusList2021Context];
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
// if context is provided as a string, add default context if it is not already present
|
|
950
|
+
if (typeof args.issuanceOptions.credential['@context'] === 'string')
|
|
951
|
+
return [Cheqd.defaultContextV1, Cheqd.statusList2021Context];
|
|
952
|
+
}();
|
|
953
|
+
// create a credential
|
|
954
|
+
const credential = await context.agent.createVerifiableCredential(args.issuanceOptions);
|
|
955
|
+
return credential;
|
|
956
|
+
}
|
|
957
|
+
async VerifyCredentialWithStatusList2021(args, context) {
|
|
958
|
+
// verify default policies
|
|
959
|
+
const verificationResult = await context.agent.verifyCredential({
|
|
960
|
+
credential: args.credential,
|
|
961
|
+
policies: {
|
|
962
|
+
credentialStatus: false
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
// early return if verification failed
|
|
966
|
+
if (!verificationResult.verified) {
|
|
967
|
+
return { verified: false, error: verificationResult.error };
|
|
968
|
+
}
|
|
969
|
+
// verify credential status
|
|
970
|
+
switch (args.credential.credentialStatus?.statusPurpose) {
|
|
971
|
+
case 'revocation':
|
|
972
|
+
if (await Cheqd.checkRevoked(args.credential, { ...args.options, topArgs: args }))
|
|
973
|
+
return { verified: false, revoked: true };
|
|
974
|
+
return { verified: true, revoked: false };
|
|
975
|
+
case 'suspension':
|
|
976
|
+
if (await Cheqd.checkSuspended(args.credential, { ...args.options, topArgs: args }))
|
|
977
|
+
return { verified: false, suspended: true };
|
|
978
|
+
return { verified: true, suspended: false };
|
|
979
|
+
default:
|
|
980
|
+
throw new Error(`[did-provider-cheqd]: verify credential: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
async VerifyPresentationWithStatusList2021(args, context) {
|
|
984
|
+
// verify default policies
|
|
985
|
+
const verificationResult = await context.agent.verifyPresentation({
|
|
986
|
+
presentation: args.presentation,
|
|
987
|
+
policies: {
|
|
988
|
+
credentialStatus: false
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
// early return if verification failed
|
|
992
|
+
if (!verificationResult.verified) {
|
|
993
|
+
return { verified: false, error: verificationResult.error };
|
|
994
|
+
}
|
|
995
|
+
if (!args.presentation.verifiableCredential)
|
|
996
|
+
throw new Error('[did-provider-cheqd]: verify presentation: presentation.verifiableCredential is required');
|
|
997
|
+
// verify credential(s) status(es)
|
|
998
|
+
for (let credential of args.presentation.verifiableCredential) {
|
|
999
|
+
// if jwt credential, decode it
|
|
1000
|
+
if (typeof credential === 'string') {
|
|
1001
|
+
const decodedCredential = decodeJWT(credential);
|
|
1002
|
+
// validate credential payload
|
|
1003
|
+
if (!decodedCredential.payload)
|
|
1004
|
+
throw new Error('[did-provider-cheqd]: verify presentation: decodedCredential.payload is required');
|
|
1005
|
+
// validate credential payload ref as VerifiableCredential
|
|
1006
|
+
if (!decodedCredential.payload.vc)
|
|
1007
|
+
throw new Error('[did-provider-cheqd]: verify presentation: decodedCredential.payload.vc is required');
|
|
1008
|
+
credential = decodedCredential.payload.vc;
|
|
1009
|
+
}
|
|
1010
|
+
switch (credential.credentialStatus?.statusPurpose) {
|
|
1011
|
+
case 'revocation':
|
|
1012
|
+
if (await Cheqd.checkRevoked(credential, { ...args.options, topArgs: args }))
|
|
1013
|
+
return { verified: false, revoked: true };
|
|
1014
|
+
break;
|
|
1015
|
+
case 'suspension':
|
|
1016
|
+
if (await Cheqd.checkSuspended(credential, { ...args.options, topArgs: args }))
|
|
1017
|
+
return { verified: false, suspended: true };
|
|
1018
|
+
break;
|
|
1019
|
+
default:
|
|
1020
|
+
throw new Error(`[did-provider-cheqd]: verify presentation: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return { verified: true };
|
|
1024
|
+
}
|
|
1025
|
+
async CheckCredentialStatusWithStatusList2021(args, context) {
|
|
1026
|
+
switch (args.credential.credentialStatus?.statusPurpose) {
|
|
1027
|
+
case 'revocation':
|
|
1028
|
+
if (await Cheqd.checkRevoked(args.credential, { ...args.options, topArgs: args }))
|
|
1029
|
+
return { revoked: true };
|
|
1030
|
+
return { revoked: false };
|
|
1031
|
+
case 'suspension':
|
|
1032
|
+
if (await Cheqd.checkSuspended(args.credential, { ...args.options, topArgs: args }))
|
|
1033
|
+
return { suspended: true };
|
|
1034
|
+
return { suspended: false };
|
|
1035
|
+
default:
|
|
1036
|
+
throw new Error(`[did-provider-cheqd]: check status: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
async RevokeCredentialWithStatusList2021(args, context) {
|
|
1040
|
+
// validate status purpose
|
|
1041
|
+
if (args.credential.credentialStatus?.statusPurpose !== 'revocation') {
|
|
1042
|
+
throw new Error(`[did-provider-cheqd]: revocation: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
|
|
1043
|
+
}
|
|
1044
|
+
// validate args in pairs - case: statusListFile and statusList
|
|
1045
|
+
if (args.options?.statusListFile && args.options?.statusList) {
|
|
1046
|
+
throw new Error('[did-provider-cheqd]: revocation: statusListFile and statusList are mutually exclusive');
|
|
1047
|
+
}
|
|
1048
|
+
// validate args in pairs - case: statusListFile and fetchList
|
|
1049
|
+
if (args.options?.statusListFile && args.options?.fetchList) {
|
|
1050
|
+
throw new Error('[did-provider-cheqd]: revocation: statusListFile and fetchList are mutually exclusive');
|
|
1051
|
+
}
|
|
1052
|
+
// validate args in pairs - case: statusList and fetchList
|
|
1053
|
+
if (args.options?.statusList && args.options?.fetchList) {
|
|
1054
|
+
throw new Error('[did-provider-cheqd]: revocation: statusList and fetchList are mutually exclusive');
|
|
1055
|
+
}
|
|
1056
|
+
// validate args in pairs - case: publish
|
|
1057
|
+
if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
|
|
1058
|
+
throw new Error('[did-provider-cheqd]: revocation: publish requires statusListFile or statusList, if fetchList is disabled');
|
|
1059
|
+
}
|
|
1060
|
+
// revoke credential
|
|
1061
|
+
return await Cheqd.revokeCredential(args.credential, {
|
|
1062
|
+
...args.options,
|
|
1063
|
+
topArgs: args,
|
|
1064
|
+
publishOptions: {
|
|
1065
|
+
context,
|
|
1066
|
+
resourceId: args?.options?.resourceId,
|
|
1067
|
+
resourceVersion: args?.options?.resourceVersion,
|
|
1068
|
+
signInputs: args?.options?.signInputs,
|
|
1069
|
+
fee: args?.options?.fee
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
async RevokeBulkCredentialsWithStatusList2021(args, context) {
|
|
1074
|
+
// TODO: implement
|
|
1075
|
+
throw new Error('[did-provider-cheqd]: revocation: bulk revocation is not implemented yet');
|
|
1076
|
+
}
|
|
1077
|
+
async SuspendCredentialWithStatusList2021(args, context) {
|
|
1078
|
+
// validate status purpose
|
|
1079
|
+
if (args.credential.credentialStatus?.statusPurpose !== 'suspension') {
|
|
1080
|
+
throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
|
|
1081
|
+
}
|
|
1082
|
+
// validate args in pairs - case: statusListFile and statusList
|
|
1083
|
+
if (args.options?.statusListFile && args.options?.statusList) {
|
|
1084
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListFile and statusList are mutually exclusive');
|
|
1085
|
+
}
|
|
1086
|
+
// validate args in pairs - case: statusListFile and fetchList
|
|
1087
|
+
if (args.options?.statusListFile && args.options?.fetchList) {
|
|
1088
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListFile and fetchList are mutually exclusive');
|
|
1089
|
+
}
|
|
1090
|
+
// validate args in pairs - case: statusList and fetchList
|
|
1091
|
+
if (args.options?.statusList && args.options?.fetchList) {
|
|
1092
|
+
throw new Error('[did-provider-cheqd]: suspension: statusList and fetchList are mutually exclusive');
|
|
1093
|
+
}
|
|
1094
|
+
// validate args in pairs - case: publish
|
|
1095
|
+
if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
|
|
1096
|
+
throw new Error('[did-provider-cheqd]: suspension: publish requires statusListFile or statusList, if fetchList is disabled');
|
|
1097
|
+
}
|
|
1098
|
+
// suspend credential
|
|
1099
|
+
return await Cheqd.suspendCredential(args.credential, {
|
|
1100
|
+
...args.options,
|
|
1101
|
+
topArgs: args,
|
|
1102
|
+
publishOptions: {
|
|
1103
|
+
context,
|
|
1104
|
+
resourceId: args?.options?.resourceId,
|
|
1105
|
+
resourceVersion: args?.options?.resourceVersion,
|
|
1106
|
+
signInputs: args?.options?.signInputs,
|
|
1107
|
+
fee: args?.options?.fee
|
|
1108
|
+
}
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
async SuspendBulkCredentialsWithStatusList2021(args, context) {
|
|
1112
|
+
// TODO: implement
|
|
1113
|
+
throw new Error('[did-provider-cheqd]: suspension: bulk suspension is not implemented yet');
|
|
1114
|
+
}
|
|
1115
|
+
async UnsuspendCredentialWithStatusList2021(args, context) {
|
|
1116
|
+
// validate status purpose
|
|
1117
|
+
if (args.credential.credentialStatus?.statusPurpose !== 'suspension') {
|
|
1118
|
+
throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`);
|
|
1119
|
+
}
|
|
1120
|
+
// validate args in pairs - case: statusListFile and statusList
|
|
1121
|
+
if (args.options?.statusListFile && args.options?.statusList) {
|
|
1122
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListFile and statusList are mutually exclusive');
|
|
1123
|
+
}
|
|
1124
|
+
// validate args in pairs - case: statusListFile and fetchList
|
|
1125
|
+
if (args.options?.statusListFile && args.options?.fetchList) {
|
|
1126
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListFile and fetchList are mutually exclusive');
|
|
1127
|
+
}
|
|
1128
|
+
// validate args in pairs - case: statusList and fetchList
|
|
1129
|
+
if (args.options?.statusList && args.options?.fetchList) {
|
|
1130
|
+
throw new Error('[did-provider-cheqd]: suspension: statusList and fetchList are mutually exclusive');
|
|
1131
|
+
}
|
|
1132
|
+
// validate args in pairs - case: publish
|
|
1133
|
+
if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
|
|
1134
|
+
throw new Error('[did-provider-cheqd]: suspension: publish requires statusListFile or statusList, if fetchList is disabled');
|
|
1135
|
+
}
|
|
1136
|
+
// suspend credential
|
|
1137
|
+
return await Cheqd.unsuspendCredential(args.credential, {
|
|
1138
|
+
...args.options,
|
|
1139
|
+
topArgs: args,
|
|
1140
|
+
publishOptions: {
|
|
1141
|
+
context,
|
|
1142
|
+
resourceId: args?.options?.resourceId,
|
|
1143
|
+
resourceVersion: args?.options?.resourceVersion,
|
|
1144
|
+
signInputs: args?.options?.signInputs,
|
|
1145
|
+
fee: args?.options?.fee
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
async UnsuspendBulkCredentialsWithStatusList2021(args, context) {
|
|
1150
|
+
// TODO: implement
|
|
1151
|
+
throw new Error('[did-provider-cheqd]: suspension: bulk unsuspension is not implemented yet');
|
|
1152
|
+
}
|
|
1153
|
+
async TransactVerifierPaysIssuer(args, context) {
|
|
1154
|
+
try {
|
|
1155
|
+
// delegate to provider
|
|
1156
|
+
const transactionResult = await this.didProvider.transactSendTokens({
|
|
1157
|
+
recipientAddress: args.recipientAddress,
|
|
1158
|
+
amount: args.amount,
|
|
1159
|
+
memoNonce: args.memoNonce,
|
|
1160
|
+
txBytes: args.txBytes,
|
|
1161
|
+
});
|
|
1162
|
+
// return transaction result
|
|
1163
|
+
return {
|
|
1164
|
+
successful: !transactionResult.code,
|
|
1165
|
+
transactionHash: transactionResult.transactionHash,
|
|
1166
|
+
events: transactionResult.events,
|
|
1167
|
+
rawLog: transactionResult.rawLog,
|
|
1168
|
+
txResponse: args?.returnTxResponse ? transactionResult : undefined
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
catch (error) {
|
|
1172
|
+
// return error
|
|
1173
|
+
return {
|
|
1174
|
+
successful: false,
|
|
1175
|
+
error: error
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
async ObserveVerifierPaysIssuer(args, context) {
|
|
1180
|
+
// verify with raw unified access control conditions, if any
|
|
1181
|
+
if (args?.unifiedAccessControlCondition) {
|
|
1182
|
+
try {
|
|
1183
|
+
// define network
|
|
1184
|
+
const network = (function () {
|
|
1185
|
+
switch (args.unifiedAccessControlCondition.chain) {
|
|
1186
|
+
case LitCompatibleCosmosChains.cheqdMainnet:
|
|
1187
|
+
return CheqdNetwork.Mainnet;
|
|
1188
|
+
case LitCompatibleCosmosChains.cheqdTestnet:
|
|
1189
|
+
return CheqdNetwork.Testnet;
|
|
1190
|
+
default:
|
|
1191
|
+
throw new Error(`[did-provider-cheqd]: observe: Unsupported chain: ${args.unifiedAccessControlCondition.chain}`);
|
|
1192
|
+
}
|
|
1193
|
+
}());
|
|
1194
|
+
// construct url
|
|
1195
|
+
const url = `${DefaultRESTUrls[network]}${args.unifiedAccessControlCondition.path}`;
|
|
1196
|
+
// fetch relevant txs
|
|
1197
|
+
const txs = await (await fetch(url)).json();
|
|
1198
|
+
// skim through txs for relevant events, in which case memoNonce is present and strict equals to the one provided
|
|
1199
|
+
const meetsConditionTxIndex = txs?.txs?.findIndex(tx => unescapeUnicode(tx.body.memo) === unescapeUnicode(args.unifiedAccessControlCondition.returnValueTest.value));
|
|
1200
|
+
// define meetsCondition
|
|
1201
|
+
const meetsCondition = (typeof meetsConditionTxIndex !== 'undefined' && meetsConditionTxIndex !== -1);
|
|
1202
|
+
// return observation result
|
|
1203
|
+
return {
|
|
1204
|
+
subscribed: true,
|
|
1205
|
+
meetsCondition: meetsCondition,
|
|
1206
|
+
transactionHash: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].txhash : undefined,
|
|
1207
|
+
events: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].events : undefined,
|
|
1208
|
+
rawLog: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].raw_log : undefined,
|
|
1209
|
+
txResponse: meetsCondition ? (args?.returnTxResponse ? txs.tx_responses[meetsConditionTxIndex] : undefined) : undefined
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
catch (error) {
|
|
1213
|
+
// return error
|
|
1214
|
+
return {
|
|
1215
|
+
subscribed: false,
|
|
1216
|
+
meetsCondition: false,
|
|
1217
|
+
error: error
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
// validate access control conditions components - case: senderAddress
|
|
1222
|
+
if (!args.senderAddress) {
|
|
1223
|
+
throw new Error('[did-provider-cheqd]: observation: senderAddress is required');
|
|
1224
|
+
}
|
|
1225
|
+
// validate access control conditions components - case: recipientAddress
|
|
1226
|
+
if (!args.recipientAddress) {
|
|
1227
|
+
throw new Error('[did-provider-cheqd]: observation: recipientAddress is required');
|
|
1228
|
+
}
|
|
1229
|
+
// validate access control conditions components - case: amount
|
|
1230
|
+
if (!args.amount || !args.amount.amount || !args.amount.denom || args.amount.denom !== 'ncheq') {
|
|
1231
|
+
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`');
|
|
1232
|
+
}
|
|
1233
|
+
// validate access control conditions components - case: memoNonce
|
|
1234
|
+
if (!args.memoNonce) {
|
|
1235
|
+
throw new Error('[did-provider-cheqd]: observation: memoNonce is required');
|
|
1236
|
+
}
|
|
1237
|
+
// validate access control conditions components - case: network
|
|
1238
|
+
if (!args.network) {
|
|
1239
|
+
throw new Error('[did-provider-cheqd]: observation: network is required');
|
|
1240
|
+
}
|
|
1241
|
+
try {
|
|
1242
|
+
// otherwise, construct url, as per components
|
|
1243
|
+
const url = `${DefaultRESTUrls[args.network]}/cosmos/tx/v1beta1/txs?events=transfer.recipient='${args.recipientAddress}'&events=transfer.sender='${args.senderAddress}'&events=transfer.amount='${args.amount.amount}${args.amount.denom}'`;
|
|
1244
|
+
// fetch relevant txs
|
|
1245
|
+
const txs = await (await fetch(url)).json();
|
|
1246
|
+
// skim through txs for relevant events, in which case memoNonce is present and strict equals to the one provided
|
|
1247
|
+
const meetsConditionTxIndex = txs?.txs?.findIndex(tx => unescapeUnicode(tx.body.memo) === unescapeUnicode(args.memoNonce));
|
|
1248
|
+
// define meetsCondition
|
|
1249
|
+
const meetsCondition = (typeof meetsConditionTxIndex !== 'undefined' && meetsConditionTxIndex !== -1);
|
|
1250
|
+
// return observation result
|
|
1251
|
+
return {
|
|
1252
|
+
subscribed: true,
|
|
1253
|
+
meetsCondition: meetsCondition,
|
|
1254
|
+
transactionHash: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].txhash : undefined,
|
|
1255
|
+
events: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].events : undefined,
|
|
1256
|
+
rawLog: meetsCondition ? txs.tx_responses[meetsConditionTxIndex].raw_log : undefined,
|
|
1257
|
+
txResponse: meetsCondition ? (args?.returnTxResponse ? txs.tx_responses[meetsConditionTxIndex] : undefined) : undefined
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
catch (error) {
|
|
1261
|
+
// return error
|
|
1262
|
+
return {
|
|
1263
|
+
subscribed: false,
|
|
1264
|
+
meetsCondition: false,
|
|
1265
|
+
error: error
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
static async revokeCredential(credential, options) {
|
|
1270
|
+
try {
|
|
1271
|
+
// validate status purpose
|
|
1272
|
+
if (credential?.credentialStatus?.statusPurpose !== 'revocation')
|
|
1273
|
+
throw new Error('[did-provider-cheqd]: revocation: Invalid status purpose');
|
|
1274
|
+
// fetch status list 2021 metadata
|
|
1275
|
+
const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
|
|
1276
|
+
// detect if encrypted
|
|
1277
|
+
const isEncrypted = function () {
|
|
1278
|
+
switch (metadata.mediaType) {
|
|
1279
|
+
case 'application/octet-stream':
|
|
1280
|
+
return true;
|
|
1281
|
+
case 'application/gzip':
|
|
1282
|
+
return false;
|
|
1283
|
+
default:
|
|
1284
|
+
throw new Error(`[did-provider-cheqd]: revocation: Unsupported media type: ${metadata.mediaType}`);
|
|
1285
|
+
}
|
|
1286
|
+
}();
|
|
1287
|
+
// early return, if encrypted and no decryption key provided
|
|
1288
|
+
if (isEncrypted && !options?.topArgs?.symmetricKey)
|
|
1289
|
+
throw new Error('[did-provider-cheqd]: revocation: symmetricKey is required, if status list 2021 is encrypted');
|
|
1290
|
+
// fetch status list 2021 inscribed in credential
|
|
1291
|
+
const statusList2021 = options?.topArgs?.fetchList
|
|
1292
|
+
? (await async function () {
|
|
1293
|
+
// if not encrypted, return bitstring
|
|
1294
|
+
if (!isEncrypted)
|
|
1295
|
+
return await Cheqd.fetchStatusList2021(credential);
|
|
1296
|
+
// otherwise, decrypt and return bitstring
|
|
1297
|
+
const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
|
|
1298
|
+
// decrypt
|
|
1299
|
+
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
1300
|
+
}())
|
|
1301
|
+
: (await async function () {
|
|
1302
|
+
// if status list 2021 is not fetched, read from file
|
|
1303
|
+
if (options?.statusListFile) {
|
|
1304
|
+
// if not encrypted, return bitstring
|
|
1305
|
+
if (!isEncrypted)
|
|
1306
|
+
return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
1307
|
+
// otherwise, decrypt and return bitstring
|
|
1308
|
+
const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
|
|
1309
|
+
// decrypt
|
|
1310
|
+
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
1311
|
+
}
|
|
1312
|
+
if (!options?.statusListInlineBitstring)
|
|
1313
|
+
throw new Error('[did-provider-cheqd]: revocation: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
1314
|
+
// otherwise, read from inline bitstring
|
|
1315
|
+
return options?.statusListInlineBitstring;
|
|
1316
|
+
}());
|
|
1317
|
+
// parse status list 2021
|
|
1318
|
+
const statusList = await StatusList.decode({ encodedList: statusList2021 });
|
|
1319
|
+
// early exit, if credential is already revoked
|
|
1320
|
+
if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex)))
|
|
1321
|
+
return { revoked: false };
|
|
1322
|
+
// update revocation status
|
|
1323
|
+
statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true);
|
|
1324
|
+
// set in-memory status list ref
|
|
1325
|
+
const bitstring = await statusList.encode();
|
|
1326
|
+
// cast top-level args
|
|
1327
|
+
const topArgs = options?.topArgs;
|
|
1328
|
+
// write status list 2021 to file, if provided
|
|
1329
|
+
if (topArgs?.writeToFile) {
|
|
1330
|
+
await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile);
|
|
1331
|
+
}
|
|
1332
|
+
// publish status list 2021, if provided
|
|
1333
|
+
const published = topArgs?.publish
|
|
1334
|
+
? (await async function () {
|
|
1335
|
+
// fetch status list 2021 metadata
|
|
1336
|
+
const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
|
|
1337
|
+
// publish status list 2021 as new version
|
|
1338
|
+
const scoped = topArgs.publishEncrypted
|
|
1339
|
+
? (await async function () {
|
|
1340
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
1341
|
+
const lit = await LitProtocol.create({
|
|
1342
|
+
chain: options?.topArgs?.bootstrapOptions?.chain,
|
|
1343
|
+
litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
|
|
1344
|
+
});
|
|
1345
|
+
// encrypt
|
|
1346
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true);
|
|
1347
|
+
// return tuple of publish result and encryption relevant metadata
|
|
1348
|
+
return [
|
|
1349
|
+
await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
|
|
1350
|
+
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
1351
|
+
];
|
|
1352
|
+
}())
|
|
1353
|
+
: [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined];
|
|
1354
|
+
// early exit, if publish failed
|
|
1355
|
+
if (!scoped[0])
|
|
1356
|
+
throw new Error('[did-provider-cheqd]: revocation: Failed to publish status list 2021');
|
|
1357
|
+
// return publish result
|
|
1358
|
+
return scoped;
|
|
1359
|
+
}())
|
|
1360
|
+
: undefined;
|
|
1361
|
+
return {
|
|
1362
|
+
revoked: true,
|
|
1363
|
+
published: topArgs?.publish ? true : undefined,
|
|
1364
|
+
statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
|
|
1365
|
+
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
1366
|
+
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
1367
|
+
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
1368
|
+
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
catch (error) {
|
|
1372
|
+
// silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
|
|
1373
|
+
console.error(error);
|
|
1374
|
+
return { revoked: false, error: error };
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
static async suspendCredential(credential, options) {
|
|
1378
|
+
try {
|
|
1379
|
+
// validate status purpose
|
|
1380
|
+
if (credential?.credentialStatus?.statusPurpose !== 'suspension')
|
|
1381
|
+
throw new Error('[did-provider-cheqd]: suspension: Invalid status purpose');
|
|
1382
|
+
// fetch status list 2021 metadata
|
|
1383
|
+
const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
|
|
1384
|
+
// detect if encrypted
|
|
1385
|
+
const isEncrypted = function () {
|
|
1386
|
+
switch (metadata.mediaType) {
|
|
1387
|
+
case 'application/octet-stream':
|
|
1388
|
+
return true;
|
|
1389
|
+
case 'application/gzip':
|
|
1390
|
+
return false;
|
|
1391
|
+
default:
|
|
1392
|
+
throw new Error(`[did-provider-cheqd]: suspension: Unsupported media type: ${metadata.mediaType}`);
|
|
1393
|
+
}
|
|
1394
|
+
}();
|
|
1395
|
+
// early return, if encrypted and no decryption key provided
|
|
1396
|
+
if (isEncrypted && !options?.topArgs?.symmetricKey)
|
|
1397
|
+
throw new Error('[did-provider-cheqd]: suspension: symmetricKey is required, if status list 2021 is encrypted');
|
|
1398
|
+
// fetch status list 2021 inscribed in credential
|
|
1399
|
+
const statusList2021 = options?.topArgs?.fetchList
|
|
1400
|
+
? (await async function () {
|
|
1401
|
+
// if not encrypted, return bitstring
|
|
1402
|
+
if (!isEncrypted)
|
|
1403
|
+
return await Cheqd.fetchStatusList2021(credential);
|
|
1404
|
+
// otherwise, decrypt and return bitstring
|
|
1405
|
+
const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
|
|
1406
|
+
// decrypt
|
|
1407
|
+
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
1408
|
+
}())
|
|
1409
|
+
: (await async function () {
|
|
1410
|
+
// if status list 2021 is not fetched, read from file
|
|
1411
|
+
if (options?.statusListFile) {
|
|
1412
|
+
// if not encrypted, return bitstring
|
|
1413
|
+
if (!isEncrypted)
|
|
1414
|
+
return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
1415
|
+
// otherwise, decrypt and return bitstring
|
|
1416
|
+
const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
|
|
1417
|
+
// decrypt
|
|
1418
|
+
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
1419
|
+
}
|
|
1420
|
+
if (!options?.statusListInlineBitstring)
|
|
1421
|
+
throw new Error('[did-provider-cheqd]: suspension: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
1422
|
+
// otherwise, read from inline bitstring
|
|
1423
|
+
return options?.statusListInlineBitstring;
|
|
1424
|
+
}());
|
|
1425
|
+
// parse status list 2021
|
|
1426
|
+
const statusList = await StatusList.decode({ encodedList: statusList2021 });
|
|
1427
|
+
// early exit, if already suspended
|
|
1428
|
+
if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex)))
|
|
1429
|
+
return { suspended: false };
|
|
1430
|
+
// update suspension status
|
|
1431
|
+
statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true);
|
|
1432
|
+
// set in-memory status list ref
|
|
1433
|
+
const bitstring = await statusList.encode();
|
|
1434
|
+
// cast top-level args
|
|
1435
|
+
const topArgs = options?.topArgs;
|
|
1436
|
+
// write status list 2021 to file, if provided
|
|
1437
|
+
if (topArgs?.writeToFile) {
|
|
1438
|
+
await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile);
|
|
1439
|
+
}
|
|
1440
|
+
// publish status list 2021, if provided
|
|
1441
|
+
const published = topArgs?.publish
|
|
1442
|
+
? (await async function () {
|
|
1443
|
+
// fetch status list 2021 metadata
|
|
1444
|
+
const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
|
|
1445
|
+
// publish status list 2021 as new version
|
|
1446
|
+
const scoped = topArgs.publishEncrypted
|
|
1447
|
+
? (await async function () {
|
|
1448
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
1449
|
+
const lit = await LitProtocol.create({
|
|
1450
|
+
chain: options?.topArgs?.bootstrapOptions?.chain,
|
|
1451
|
+
litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
|
|
1452
|
+
});
|
|
1453
|
+
// encrypt
|
|
1454
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true);
|
|
1455
|
+
// return tuple of publish result and encryption relevant metadata
|
|
1456
|
+
return [
|
|
1457
|
+
await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
|
|
1458
|
+
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
1459
|
+
];
|
|
1460
|
+
}())
|
|
1461
|
+
: [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined];
|
|
1462
|
+
// early exit, if publish failed
|
|
1463
|
+
if (!scoped[0])
|
|
1464
|
+
throw new Error('[did-provider-cheqd]: suspension: Failed to publish status list 2021');
|
|
1465
|
+
// return publish result
|
|
1466
|
+
return scoped;
|
|
1467
|
+
}())
|
|
1468
|
+
: undefined;
|
|
1469
|
+
return {
|
|
1470
|
+
suspended: true,
|
|
1471
|
+
published: topArgs?.publish ? true : undefined,
|
|
1472
|
+
statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
|
|
1473
|
+
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
1474
|
+
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
1475
|
+
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
1476
|
+
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
catch (error) {
|
|
1480
|
+
// silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
|
|
1481
|
+
console.error(error);
|
|
1482
|
+
return { suspended: false, error: error };
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
static async unsuspendCredential(credential, options) {
|
|
1486
|
+
try {
|
|
1487
|
+
// validate status purpose
|
|
1488
|
+
if (credential?.credentialStatus?.statusPurpose !== 'suspension')
|
|
1489
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Invalid status purpose');
|
|
1490
|
+
// fetch status list 2021 metadata
|
|
1491
|
+
const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
|
|
1492
|
+
// detect if encrypted
|
|
1493
|
+
const isEncrypted = function () {
|
|
1494
|
+
switch (metadata.mediaType) {
|
|
1495
|
+
case 'application/octet-stream':
|
|
1496
|
+
return true;
|
|
1497
|
+
case 'application/gzip':
|
|
1498
|
+
return false;
|
|
1499
|
+
default:
|
|
1500
|
+
throw new Error(`[did-provider-cheqd]: unsuspension: Unsupported media type: ${metadata.mediaType}`);
|
|
1501
|
+
}
|
|
1502
|
+
}();
|
|
1503
|
+
// early return, if encrypted and no decryption key provided
|
|
1504
|
+
if (isEncrypted && !options?.topArgs?.symmetricKey)
|
|
1505
|
+
throw new Error('[did-provider-cheqd]: unsuspension: symmetricKey is required, if status list 2021 is encrypted');
|
|
1506
|
+
// fetch status list 2021 inscribed in credential
|
|
1507
|
+
const statusList2021 = options?.topArgs?.fetchList
|
|
1508
|
+
? (await async function () {
|
|
1509
|
+
// if not encrypted, return bitstring
|
|
1510
|
+
if (!isEncrypted)
|
|
1511
|
+
return await Cheqd.fetchStatusList2021(credential);
|
|
1512
|
+
// otherwise, decrypt and return bitstring
|
|
1513
|
+
const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
|
|
1514
|
+
// decrypt
|
|
1515
|
+
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
1516
|
+
}())
|
|
1517
|
+
: (await async function () {
|
|
1518
|
+
// if status list 2021 is not fetched, read from file
|
|
1519
|
+
if (options?.statusListFile) {
|
|
1520
|
+
// if not encrypted, return bitstring
|
|
1521
|
+
if (!isEncrypted)
|
|
1522
|
+
return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
1523
|
+
// otherwise, decrypt and return bitstring
|
|
1524
|
+
const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
|
|
1525
|
+
// decrypt
|
|
1526
|
+
return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'));
|
|
1527
|
+
}
|
|
1528
|
+
if (!options?.statusListInlineBitstring)
|
|
1529
|
+
throw new Error('[did-provider-cheqd]: unsuspension: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
1530
|
+
// otherwise, read from inline bitstring
|
|
1531
|
+
return options?.statusListInlineBitstring;
|
|
1532
|
+
}());
|
|
1533
|
+
// parse status list 2021
|
|
1534
|
+
const statusList = await StatusList.decode({ encodedList: statusList2021 });
|
|
1535
|
+
// early exit, if already suspended
|
|
1536
|
+
if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex)))
|
|
1537
|
+
return { unsuspended: false };
|
|
1538
|
+
// update suspension status
|
|
1539
|
+
statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true);
|
|
1540
|
+
// set in-memory status list ref
|
|
1541
|
+
const bitstring = await statusList.encode();
|
|
1542
|
+
// cast top-level args
|
|
1543
|
+
const topArgs = options?.topArgs;
|
|
1544
|
+
// write status list 2021 to file, if provided
|
|
1545
|
+
if (topArgs?.writeToFile) {
|
|
1546
|
+
await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile);
|
|
1547
|
+
}
|
|
1548
|
+
// publish status list 2021, if provided
|
|
1549
|
+
const published = topArgs?.publish
|
|
1550
|
+
? (await async function () {
|
|
1551
|
+
// fetch status list 2021 metadata
|
|
1552
|
+
const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential);
|
|
1553
|
+
// publish status list 2021 as new version
|
|
1554
|
+
const scoped = topArgs.publishEncrypted
|
|
1555
|
+
? (await async function () {
|
|
1556
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
1557
|
+
const lit = await LitProtocol.create({
|
|
1558
|
+
chain: options?.topArgs?.bootstrapOptions?.chain,
|
|
1559
|
+
litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
|
|
1560
|
+
});
|
|
1561
|
+
// encrypt
|
|
1562
|
+
const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true);
|
|
1563
|
+
// return tuple of publish result and encryption relevant metadata
|
|
1564
|
+
return [
|
|
1565
|
+
await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
|
|
1566
|
+
{ encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey, 'hex') }
|
|
1567
|
+
];
|
|
1568
|
+
}())
|
|
1569
|
+
: [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined];
|
|
1570
|
+
// early exit, if publish failed
|
|
1571
|
+
if (!scoped[0])
|
|
1572
|
+
throw new Error('[did-provider-cheqd]: unsuspension: Failed to publish status list 2021');
|
|
1573
|
+
// return publish result
|
|
1574
|
+
return scoped;
|
|
1575
|
+
}())
|
|
1576
|
+
: undefined;
|
|
1577
|
+
return {
|
|
1578
|
+
unsuspended: true,
|
|
1579
|
+
published: topArgs?.publish ? true : undefined,
|
|
1580
|
+
statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
|
|
1581
|
+
encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString(published?.[1]?.encryptedString) : undefined,
|
|
1582
|
+
encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? published?.[1]?.encryptedSymmetricKey : undefined,
|
|
1583
|
+
symmetricKey: topArgs?.returnSymmetricKey ? published?.[1]?.symmetricKey : undefined,
|
|
1584
|
+
resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
catch (error) {
|
|
1588
|
+
// silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
|
|
1589
|
+
console.error(error);
|
|
1590
|
+
return { unsuspended: false, error: error };
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
static async checkRevoked(credential, options = { fetchList: true }) {
|
|
1594
|
+
// validate status purpose
|
|
1595
|
+
if (credential.credentialStatus?.statusPurpose !== 'revocation') {
|
|
1596
|
+
throw new Error(`[did-provider-cheqd]: revocation: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
|
|
1597
|
+
}
|
|
1598
|
+
// fetch status list 2021 metadata
|
|
1599
|
+
const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
|
|
1600
|
+
// detect if encrypted
|
|
1601
|
+
const isEncrypted = function () {
|
|
1602
|
+
switch (metadata.mediaType) {
|
|
1603
|
+
case 'application/octet-stream':
|
|
1604
|
+
return true;
|
|
1605
|
+
case 'application/gzip':
|
|
1606
|
+
return false;
|
|
1607
|
+
default:
|
|
1608
|
+
throw new Error(`[did-provider-cheqd]: revocation: Unsupported media type: ${metadata.mediaType}`);
|
|
1609
|
+
}
|
|
1610
|
+
}();
|
|
1611
|
+
// early return, if encrypted and decryption key is not provided
|
|
1612
|
+
if (isEncrypted && !options?.topArgs?.encryptedSymmetricKey)
|
|
1613
|
+
throw new Error('[did-provider-cheqd]: revocation: encryptedSymmetricKey is required, if status list 2021 is encrypted');
|
|
1614
|
+
// fetch status list 2021 inscribed in credential
|
|
1615
|
+
const statusList2021 = options?.topArgs?.fetchList
|
|
1616
|
+
? (await async function () {
|
|
1617
|
+
// if not encrypted, return bitstring
|
|
1618
|
+
if (!isEncrypted)
|
|
1619
|
+
return await Cheqd.fetchStatusList2021(credential);
|
|
1620
|
+
// otherwise, decrypt and return bitstring
|
|
1621
|
+
const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
|
|
1622
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
1623
|
+
const lit = await LitProtocol.create({
|
|
1624
|
+
chain: options?.topArgs?.bootstrapOptions?.chain,
|
|
1625
|
+
litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
|
|
1626
|
+
});
|
|
1627
|
+
// decrypt
|
|
1628
|
+
return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions);
|
|
1629
|
+
}())
|
|
1630
|
+
: (await async function () {
|
|
1631
|
+
// if status list 2021 is not fetched, read from file
|
|
1632
|
+
if (options?.statusListFile) {
|
|
1633
|
+
// if not encrypted, return bitstring
|
|
1634
|
+
if (!isEncrypted)
|
|
1635
|
+
return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
1636
|
+
// otherwise, decrypt and return bitstring
|
|
1637
|
+
const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
|
|
1638
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
1639
|
+
const lit = await LitProtocol.create({
|
|
1640
|
+
chain: options?.topArgs?.bootstrapOptions?.chain,
|
|
1641
|
+
litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
|
|
1642
|
+
});
|
|
1643
|
+
// decrypt
|
|
1644
|
+
return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions);
|
|
1645
|
+
}
|
|
1646
|
+
if (!options?.statusListInlineBitstring)
|
|
1647
|
+
throw new Error(' [did-provider-cheqd]: revocation: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
1648
|
+
// otherwise, read from inline bitstring
|
|
1649
|
+
return options?.statusListInlineBitstring;
|
|
1650
|
+
}());
|
|
1651
|
+
// parse status list 2021
|
|
1652
|
+
const statusList = await StatusList.decode({ encodedList: statusList2021 });
|
|
1653
|
+
// get status by index
|
|
1654
|
+
return !!statusList.getStatus(Number(credential.credentialStatus.statusListIndex));
|
|
1655
|
+
}
|
|
1656
|
+
static async checkSuspended(credential, options = { fetchList: true }) {
|
|
1657
|
+
// validate status purpose
|
|
1658
|
+
if (credential.credentialStatus?.statusPurpose !== 'suspension') {
|
|
1659
|
+
throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`);
|
|
1660
|
+
}
|
|
1661
|
+
// fetch status list 2021 metadata
|
|
1662
|
+
const metadata = (await Cheqd.fetchStatusList2021Metadata(credential));
|
|
1663
|
+
// detect if encrypted
|
|
1664
|
+
const isEncrypted = function () {
|
|
1665
|
+
switch (metadata.mediaType) {
|
|
1666
|
+
case 'application/octet-stream':
|
|
1667
|
+
return true;
|
|
1668
|
+
case 'application/gzip':
|
|
1669
|
+
return false;
|
|
1670
|
+
default:
|
|
1671
|
+
throw new Error(`[did-provider-cheqd]: suspension: Unsupported media type: ${metadata.mediaType}`);
|
|
1672
|
+
}
|
|
1673
|
+
}();
|
|
1674
|
+
// early return, if encrypted and decryption key is not provided
|
|
1675
|
+
if (isEncrypted && !options?.topArgs?.encryptedSymmetricKey)
|
|
1676
|
+
throw new Error('[did-provider-cheqd]: suspension: encryptedSymmetricKey is required, if status list 2021 is encrypted');
|
|
1677
|
+
// fetch status list 2021 inscribed in credential
|
|
1678
|
+
const statusList2021 = options?.topArgs?.fetchList
|
|
1679
|
+
? (await async function () {
|
|
1680
|
+
// if not encrypted, return bitstring
|
|
1681
|
+
if (!isEncrypted)
|
|
1682
|
+
return await Cheqd.fetchStatusList2021(credential);
|
|
1683
|
+
// otherwise, decrypt and return bitstring
|
|
1684
|
+
const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true));
|
|
1685
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
1686
|
+
const lit = await LitProtocol.create({
|
|
1687
|
+
chain: options?.topArgs?.bootstrapOptions?.chain,
|
|
1688
|
+
litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
|
|
1689
|
+
});
|
|
1690
|
+
// decrypt
|
|
1691
|
+
return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions);
|
|
1692
|
+
}())
|
|
1693
|
+
: (await async function () {
|
|
1694
|
+
// if status list 2021 is not fetched, read from file
|
|
1695
|
+
if (options?.statusListFile) {
|
|
1696
|
+
// if not encrypted, return bitstring
|
|
1697
|
+
if (!isEncrypted)
|
|
1698
|
+
return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode();
|
|
1699
|
+
// otherwise, decrypt and return bitstring
|
|
1700
|
+
const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile));
|
|
1701
|
+
// instantiate dkg-threshold client, in which case lit-protocol is used
|
|
1702
|
+
const lit = await LitProtocol.create({
|
|
1703
|
+
chain: options?.topArgs?.bootstrapOptions?.chain,
|
|
1704
|
+
litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
|
|
1705
|
+
});
|
|
1706
|
+
// decrypt
|
|
1707
|
+
return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions);
|
|
1708
|
+
}
|
|
1709
|
+
if (!options?.statusListInlineBitstring)
|
|
1710
|
+
throw new Error(' [did-provider-cheqd]: suspension: statusListInlineBitstring is required, if statusListFile is not provided');
|
|
1711
|
+
// otherwise, read from inline bitstring
|
|
1712
|
+
return options?.statusListInlineBitstring;
|
|
1713
|
+
}());
|
|
1714
|
+
// parse status list 2021
|
|
1715
|
+
const statusList = await StatusList.decode({ encodedList: statusList2021 });
|
|
1716
|
+
// get status by index
|
|
1717
|
+
return !!statusList.getStatus(Number(credential.credentialStatus.statusListIndex));
|
|
1718
|
+
}
|
|
1719
|
+
static async publishStatusList2021(statusList2021Raw, statusList2021Metadata, options) {
|
|
1720
|
+
// construct status list 2021 payload from previous version + new version
|
|
1721
|
+
const payload = {
|
|
1722
|
+
collectionId: statusList2021Metadata.resourceCollectionId,
|
|
1723
|
+
id: options?.resourceId || v4(),
|
|
1724
|
+
name: statusList2021Metadata.resourceName,
|
|
1725
|
+
version: options?.resourceVersion || new Date().toISOString(),
|
|
1726
|
+
resourceType: 'StatusList2021',
|
|
1727
|
+
data: statusList2021Raw
|
|
1728
|
+
};
|
|
1729
|
+
return await options.context.agent[CreateStatusList2021MethodName]({
|
|
1730
|
+
kms: (await options.context.agent.keyManagerGetKeyManagementSystems())[0],
|
|
1731
|
+
payload,
|
|
1732
|
+
network: statusList2021Metadata.resourceURI.split(':')[2],
|
|
1733
|
+
signInputs: options?.signInputs,
|
|
1734
|
+
fee: options?.fee
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
static async fetchStatusList2021(credential, returnRaw = false) {
|
|
1738
|
+
// validate credential status
|
|
1739
|
+
if (!credential.credentialStatus)
|
|
1740
|
+
throw new Error('[did-provider-cheqd]: fetch status list: Credential status is not present');
|
|
1741
|
+
// validate credential status type
|
|
1742
|
+
if (credential.credentialStatus.type !== 'StatusList2021Entry')
|
|
1743
|
+
throw new Error('[did-provider-cheqd]: fetch status list: Credential status type is not valid');
|
|
1744
|
+
// validate credential status list status purpose
|
|
1745
|
+
if (credential.credentialStatus.statusPurpose !== 'revocation' && credential.credentialStatus.statusPurpose !== 'suspension')
|
|
1746
|
+
throw new Error('[did-provider-cheqd]: fetch status list: Credential status purpose is not valid');
|
|
1747
|
+
// validate credential status list status list credential
|
|
1748
|
+
if (!credential.credentialStatus.statusListCredential)
|
|
1749
|
+
throw new Error('[did-provider-cheqd]: fetch status list: Credential status list credential is not present');
|
|
1750
|
+
// fetch status list 2021
|
|
1751
|
+
const raw = await (await fetch(credential.credentialStatus.statusListCredential)).arrayBuffer();
|
|
1752
|
+
// return raw if requested
|
|
1753
|
+
if (returnRaw)
|
|
1754
|
+
return new Uint8Array(raw);
|
|
1755
|
+
// otherwise, parse to bitstring and return
|
|
1756
|
+
const bitstring = toString(new Uint8Array(raw), 'base64url');
|
|
1757
|
+
return bitstring;
|
|
1758
|
+
}
|
|
1759
|
+
static async fetchStatusList2021Metadata(credential) {
|
|
1760
|
+
// get base url
|
|
1761
|
+
const baseUrl = new URL(credential.credentialStatus?.statusListCredential);
|
|
1762
|
+
// get resource name
|
|
1763
|
+
const resourceName = baseUrl.searchParams.get('resourceName');
|
|
1764
|
+
// unset resource name
|
|
1765
|
+
baseUrl.searchParams.delete('resourceName');
|
|
1766
|
+
// construct metadata url
|
|
1767
|
+
const metadataUrl = `${baseUrl.toString()}/metadata`;
|
|
1768
|
+
// fetch collection metadata
|
|
1769
|
+
const collectionMetadata = await (await fetch(metadataUrl)).json();
|
|
1770
|
+
// early exit if no linked resources
|
|
1771
|
+
if (!collectionMetadata?.contentStream?.linkedResourceMetadata)
|
|
1772
|
+
throw new Error('[did-provider-cheqd]: fetch status list metadata: No linked resources found');
|
|
1773
|
+
// find relevant resources by resource name
|
|
1774
|
+
const resourceVersioning = collectionMetadata.contentStream.linkedResourceMetadata.filter((resource) => resource.resourceName === resourceName);
|
|
1775
|
+
// early exit if no relevant resources
|
|
1776
|
+
if (!resourceVersioning.length || resourceVersioning.length === 0)
|
|
1777
|
+
throw new Error(`[did-provider-cheqd]: fetch status list metadata: No relevant resources found by resource name ${resourceName}`);
|
|
1778
|
+
// get latest resource version by nextVersionId null pointer, or by latest created date as fallback
|
|
1779
|
+
return resourceVersioning.find((resource) => !resource.nextVersionId) || resourceVersioning.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime())[0];
|
|
1780
|
+
}
|
|
358
1781
|
static async loadProvider(document, providers) {
|
|
359
1782
|
const provider = providers.find((provider) => document.id.includes(`${DidPrefix}:${CheqdDidMethod}:${provider.network}`));
|
|
360
1783
|
if (!provider) {
|
|
@@ -381,5 +1804,23 @@ export class Cheqd {
|
|
|
381
1804
|
resolve(new Uint8Array(content));
|
|
382
1805
|
});
|
|
383
1806
|
}
|
|
1807
|
+
static async writeFile(content, filename) {
|
|
1808
|
+
if (!filename) {
|
|
1809
|
+
filename = `statusList2021-${v4()}`;
|
|
1810
|
+
}
|
|
1811
|
+
// alert if file exists
|
|
1812
|
+
if (fs.existsSync(filename)) {
|
|
1813
|
+
debug(`[did-provider-cheqd]: File ${filename} already exists`);
|
|
1814
|
+
console.warn(`[did-provider-cheqd]: File ${filename} already exists. Overwriting...`);
|
|
1815
|
+
}
|
|
1816
|
+
return new Promise((resolve, reject) => {
|
|
1817
|
+
fs.writeFile(filename, content, (err) => {
|
|
1818
|
+
if (err) {
|
|
1819
|
+
reject(new Error(`[did-provider-cheqd]: Error writing file ${filename}: reason: ${err}`));
|
|
1820
|
+
}
|
|
1821
|
+
resolve();
|
|
1822
|
+
});
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
384
1825
|
}
|
|
385
1826
|
//# sourceMappingURL=ICheqd.js.map
|