@cheqd/did-provider-cheqd 3.2.0 → 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.
Files changed (86) hide show
  1. package/build/cjs/agent/ICheqd.d.ts +513 -14
  2. package/build/cjs/agent/ICheqd.d.ts.map +1 -1
  3. package/build/cjs/agent/ICheqd.js +1446 -5
  4. package/build/cjs/agent/ICheqd.js.map +1 -1
  5. package/build/cjs/did-manager/cheqd-did-provider.d.ts +26 -7
  6. package/build/cjs/did-manager/cheqd-did-provider.d.ts.map +1 -1
  7. package/build/cjs/did-manager/cheqd-did-provider.js +30 -8
  8. package/build/cjs/did-manager/cheqd-did-provider.js.map +1 -1
  9. package/build/cjs/did-manager/cheqd-did-resolver.d.ts +5 -0
  10. package/build/cjs/did-manager/cheqd-did-resolver.d.ts.map +1 -1
  11. package/build/cjs/did-manager/cheqd-did-resolver.js +7 -2
  12. package/build/cjs/did-manager/cheqd-did-resolver.js.map +1 -1
  13. package/build/cjs/dkg-threshold/lit-protocol.d.ts +92 -0
  14. package/build/cjs/dkg-threshold/lit-protocol.d.ts.map +1 -0
  15. package/build/cjs/dkg-threshold/lit-protocol.js +170 -0
  16. package/build/cjs/dkg-threshold/lit-protocol.js.map +1 -0
  17. package/build/cjs/global.d..d.ts +2 -0
  18. package/build/cjs/global.d..d.ts.map +1 -0
  19. package/build/cjs/global.d..js +2 -0
  20. package/build/cjs/global.d..js.map +1 -0
  21. package/build/cjs/index.js +1 -2
  22. package/build/cjs/index.js.map +1 -1
  23. package/build/cjs/utils/env.d.ts +7 -0
  24. package/build/cjs/utils/env.d.ts.map +1 -0
  25. package/build/cjs/utils/env.js +10 -0
  26. package/build/cjs/utils/env.js.map +1 -0
  27. package/build/cjs/utils/helpers.d.ts +12 -0
  28. package/build/cjs/utils/helpers.d.ts.map +1 -0
  29. package/build/cjs/utils/helpers.js +63 -0
  30. package/build/cjs/utils/helpers.js.map +1 -0
  31. package/build/esm/agent/ICheqd.d.ts +513 -14
  32. package/build/esm/agent/ICheqd.d.ts.map +1 -1
  33. package/build/esm/agent/ICheqd.js +1446 -5
  34. package/build/esm/agent/ICheqd.js.map +1 -1
  35. package/build/esm/did-manager/cheqd-did-provider.d.ts +26 -7
  36. package/build/esm/did-manager/cheqd-did-provider.d.ts.map +1 -1
  37. package/build/esm/did-manager/cheqd-did-provider.js +29 -7
  38. package/build/esm/did-manager/cheqd-did-provider.js.map +1 -1
  39. package/build/esm/did-manager/cheqd-did-resolver.d.ts +5 -0
  40. package/build/esm/did-manager/cheqd-did-resolver.d.ts.map +1 -1
  41. package/build/esm/did-manager/cheqd-did-resolver.js +6 -1
  42. package/build/esm/did-manager/cheqd-did-resolver.js.map +1 -1
  43. package/build/esm/dkg-threshold/lit-protocol.d.ts +92 -0
  44. package/build/esm/dkg-threshold/lit-protocol.d.ts.map +1 -0
  45. package/build/esm/dkg-threshold/lit-protocol.js +166 -0
  46. package/build/esm/dkg-threshold/lit-protocol.js.map +1 -0
  47. package/build/esm/global.d..d.ts +2 -0
  48. package/build/esm/global.d..d.ts.map +1 -0
  49. package/build/esm/global.d..js +2 -0
  50. package/build/esm/global.d..js.map +1 -0
  51. package/build/esm/index.js +1 -1
  52. package/build/esm/index.js.map +1 -1
  53. package/build/esm/utils/env.d.ts +7 -0
  54. package/build/esm/utils/env.d.ts.map +1 -0
  55. package/build/esm/utils/env.js +7 -0
  56. package/build/esm/utils/env.js.map +1 -0
  57. package/build/esm/utils/helpers.d.ts +12 -0
  58. package/build/esm/utils/helpers.d.ts.map +1 -0
  59. package/build/esm/utils/helpers.js +51 -0
  60. package/build/esm/utils/helpers.js.map +1 -0
  61. package/build/tsconfig.cjs.tsbuildinfo +1 -1
  62. package/build/tsconfig.esm.tsbuildinfo +1 -1
  63. package/build/tsconfig.types.tsbuildinfo +1 -1
  64. package/build/types/agent/ICheqd.d.ts +513 -14
  65. package/build/types/agent/ICheqd.d.ts.map +1 -1
  66. package/build/types/did-manager/cheqd-did-provider.d.ts +26 -7
  67. package/build/types/did-manager/cheqd-did-provider.d.ts.map +1 -1
  68. package/build/types/did-manager/cheqd-did-resolver.d.ts +5 -0
  69. package/build/types/did-manager/cheqd-did-resolver.d.ts.map +1 -1
  70. package/build/types/dkg-threshold/lit-protocol.d.ts +92 -0
  71. package/build/types/dkg-threshold/lit-protocol.d.ts.map +1 -0
  72. package/build/types/global.d..d.ts +2 -0
  73. package/build/types/global.d..d.ts.map +1 -0
  74. package/build/types/utils/env.d.ts +7 -0
  75. package/build/types/utils/env.d.ts.map +1 -0
  76. package/build/types/utils/helpers.d.ts +12 -0
  77. package/build/types/utils/helpers.d.ts.map +1 -0
  78. package/package.json +13 -7
  79. package/src/agent/ICheqd.ts +2209 -232
  80. package/src/did-manager/cheqd-did-provider.ts +55 -8
  81. package/src/did-manager/cheqd-did-resolver.ts +7 -1
  82. package/src/dkg-threshold/lit-protocol.ts +238 -0
  83. package/src/global.d..ts +1 -0
  84. package/src/utils/env.ts +6 -0
  85. package/src/utils/helpers.ts +66 -0
  86. package/tsconfig.json +1 -0
@@ -5,7 +5,9 @@
5
5
  import {
6
6
  CheqdNetwork,
7
7
  DIDDocument,
8
+ DidStdFee,
8
9
  IKeyPair,
10
+ ISignInputs,
9
11
  MethodSpecificIdAlgo,
10
12
  VerificationMethods,
11
13
  createDidPayload,
@@ -14,54 +16,412 @@ import {
14
16
  createKeyPairHex,
15
17
  createVerificationKeys
16
18
  } from '@cheqd/sdk'
19
+ import {
20
+ Coin,
21
+ DeliverTxResponse
22
+ } from '@cosmjs/stargate'
17
23
  import {
18
24
  IAgentContext,
19
25
  IKeyManager,
20
26
  IAgentPlugin,
21
27
  IPluginMethodMap,
22
28
  IAgentPluginSchema,
23
- IIdentifier
29
+ IIdentifier,
30
+ VerifiableCredential,
31
+ IVerifyCredentialArgs,
32
+ IVerifyResult,
33
+ VerifiablePresentation,
34
+ IVerifyPresentationArgs,
35
+ IError,
36
+ ICreateVerifiableCredentialArgs,
37
+ ICredentialIssuer,
38
+ IDIDManager,
39
+ IDataStore,
40
+ IResolver
24
41
  } from '@veramo/core'
25
42
  import {
26
43
  CheqdDIDProvider,
27
44
  LinkedResource,
28
- TImportableEd25519Key
45
+ TImportableEd25519Key,
46
+ ResourcePayload,
47
+ StatusList2021ResourcePayload,
48
+ DefaultRESTUrls
29
49
  } from '../did-manager/cheqd-did-provider.js'
30
50
  import {
31
51
  fromString,
32
52
  toString
33
53
  } from 'uint8arrays'
54
+ import { decodeJWT } from 'did-jwt'
55
+ import { StatusList } from '@digitalbazaar/vc-status-list'
34
56
  import { v4 } from 'uuid'
35
57
  import fs from 'fs'
36
58
  import Debug from 'debug'
59
+ import {
60
+ CosmosAccessControlCondition,
61
+ LitCompatibleCosmosChain,
62
+ LitCompatibleCosmosChains,
63
+ LitNetwork,
64
+ LitProtocol,
65
+ TxNonceFormat
66
+ } from '../dkg-threshold/lit-protocol.js';
67
+ import { blobToHexString, randomFromRange, toBlob, unescapeUnicode } from '../utils/helpers.js'
68
+ import { resolverUrl } from '../did-manager/cheqd-did-resolver.js'
37
69
 
38
70
  const debug = Debug('veramo:did-provider-cheqd')
39
71
 
40
- type IContext = IAgentContext<IKeyManager>
41
- type TExportedDIDDocWithKeys = { didDoc: DIDDocument, keys: TImportableEd25519Key[], versionId?: string }
42
- type TExportedDIDDocWithLinkedResourceWithKeys = TExportedDIDDocWithKeys & { linkedResource: LinkedResource }
72
+ export type IContext = IAgentContext<IDIDManager & IKeyManager & IDataStore & IResolver & ICredentialIssuer & ICheqd>
73
+ export type TExportedDIDDocWithKeys = { didDoc: DIDDocument, keys: TImportableEd25519Key[], versionId?: string }
74
+ export type TExportedDIDDocWithLinkedResourceWithKeys = TExportedDIDDocWithKeys & { linkedResource: LinkedResource }
75
+ export type LinkedResourceMetadataResolutionResult = { resourceURI: string, resourceCollectionId: string, resourceId: string, resourceName: string, resourceType: string, mediaType: string, resourceVersion?: string, created: string, checksum: string, previousVersionId: string | null, nextVersionId: string | null }
76
+ export type DIDMetadataDereferencingResult = { '@context': 'https://w3id.org/did-resolution/v1', dereferencingMetadata: { contentType: string, retrieved: string, did: { didString: string, methodSpecificId: string, method: string } }, contentStream: { created: string, versionId: string, linkedResourceMetadata: LinkedResourceMetadataResolutionResult[] }, contentMetadata: Record<string, any> }
77
+ export type ShallowTypedTx = { body: { messages: any[], memo: string, timeout_height: string, extension_options: any[], non_critical_extension_options: any[] }, auth_info: { signer_infos: { public_key: { '@type': string, key: string }, mode_info: { single: { mode: string } }, sequence: string }[], fee: { amount: Coin[], gas_limit: string, payer: string, granter: string }, tip: any | null }, signatures: string[] }
78
+ export type ShallowTypedTxTxResponses = { height: string, txhash: string, codespace: string, code: number, data: string, raw_log: string, logs: any[], info: string, gas_wanted: string, gas_used: string, tx: ShallowTypedTx, timestamp: string, events: any[] }
79
+ export type ShallowTypedTxsResponse = { txs: ShallowTypedTx[], tx_responses: ShallowTypedTxTxResponses[], pagination: string | null, total: string } | undefined
80
+ export type VerificationResult = { verified: boolean, revoked?: boolean, suspended?: boolean, error?: IVerifyResult['error'] }
81
+ export type StatusCheckResult = { revoked?: boolean, suspended?: boolean, error?: IError }
82
+ export type RevocationResult = { revoked: boolean, error?: IError, statusList?: Bitstring, encryptedStatusList?: string, encryptedSymmetricKey?: string, symmetricKey?: string, published?: boolean, resourceMetadata?: LinkedResourceMetadataResolutionResult }
83
+ export type SuspensionResult = { suspended: boolean, error?: IError, statusList?: Bitstring, encryptedStatusList?: string, encryptedSymmetricKey?: string, symmetricKey?: string, published?: boolean, resourceMetadata?: LinkedResourceMetadataResolutionResult }
84
+ export type UnsuspensionResult = { unsuspended: boolean, error?: IError, statusList?: Bitstring, encryptedStatusList?: string, encryptedSymmetricKey?: string, symmetricKey?: string, published?: boolean, resourceMetadata?: LinkedResourceMetadataResolutionResult }
85
+ export type Bitstring = string
86
+ export type AccessControlConditionType = typeof AccessControlConditionTypes[keyof typeof AccessControlConditionTypes]
87
+ export type AccessControlConditionReturnValueComparator = typeof AccessControlConditionReturnValueComparators[keyof typeof AccessControlConditionReturnValueComparators]
88
+ export type AccessControlConditionMemoNonceArgs = { senderAddressObserved: string, recipientAddressObserved: string, amountObserved: string, specificNonce?: string, nonceFormat?: TxNonceFormat, type: Extract<AccessControlConditionType, 'memoNonce'> }
89
+ export type AccessControlConditionBalanceArgs = { addressObserved: string, amountObserved: string, comparator: AccessControlConditionReturnValueComparator, type: Extract<AccessControlConditionType, 'balance'>}
90
+ export type CreateEncryptedStatusList2021Result = { created: boolean, error?: Error, encryptedSymmetricKey: string, symmetricKey?: string, encryptedStatusList2021: string, unifiedAccessControlConditions: CosmosAccessControlCondition[] }
91
+ export type GenerateEncryptedStatusList2021Result = { encryptedSymmetricKey: string, encryptedStatusList2021: string, unifiedAccessControlConditions: CosmosAccessControlCondition[] }
92
+ export type TransactionResult = { successful: boolean, transactionHash?: string, events?: DeliverTxResponse['events'], rawLog?: string, txResponse?: DeliverTxResponse, error?: IError }
93
+ export type ObservationResult = { subscribed: boolean, meetsCondition: boolean, transactionHash?: string, events?: DeliverTxResponse['events'], rawLog?: string, txResponse?: ShallowTypedTxTxResponses, error?: IError }
94
+
95
+ export const AccessControlConditionTypes = { memoNonce: 'memoNonce', balance: 'balance' } as const
96
+ export const AccessControlConditionReturnValueComparators = { lessThan: '<', greaterThan: '>', equalTo: '=', lessThanOrEqualTo: '<=', greaterThanOrEqualTo: '>=' } as const
43
97
 
44
98
  const CreateIdentifierMethodName = 'cheqdCreateIdentifier'
45
99
  const UpdateIdentifierMethodName = 'cheqdUpdateIdentifier'
46
100
  const DeactivateIdentifierMethodName = 'cheqdDeactivateIdentifier'
47
101
  const CreateResourceMethodName = 'cheqdCreateLinkedResource'
102
+ const CreateStatusList2021MethodName = 'cheqdCreateStatusList2021'
103
+ const CreateEncryptedStatusList2021MethodName = 'cheqdCreateEncryptedStatusList2021'
48
104
  const GenerateDidDocMethodName = 'cheqdGenerateDidDoc'
49
105
  const GenerateDidDocWithLinkedResourceMethodName = 'cheqdGenerateDidDocWithLinkedResource'
50
106
  const GenerateKeyPairMethodName = 'cheqdGenerateIdentityKeys'
51
107
  const GenerateVersionIdMethodName = 'cheqdGenerateVersionId'
108
+ const GenerateStatusList2021MethodName = 'cheqdGenerateStatusList2021'
109
+ const GenerateEncryptedStatusList2021MethodName = 'cheqdGenerateEncryptedStatusList2021'
110
+ const IssueRevocableCredentialWithStatusList2021MethodName = 'cheqdIssueRevocableCredentialWithStatusList2021'
111
+ const IssueSuspendableCredentialWithStatusList2021MethodName = 'cheqdIssueSuspendableCredentialWithStatusList2021'
112
+ const VerifyCredentialMethodName = 'cheqdVerifyCredential'
113
+ const VerifyPresentationMethodName = 'cheqdVerifyPresentation'
114
+ const CheckCredentialStatusMethodName = 'cheqdCheckCredentialStatus'
115
+ const RevokeCredentialMethodName = 'cheqdRevokeCredential'
116
+ const RevokeCredentialsMethodName = 'cheqdRevokeCredentials'
117
+ const SuspendCredentialMethodName = 'cheqdSuspendCredential'
118
+ const SuspendCredentialsMethodName = 'cheqdSuspendCredentials'
119
+ const UnsuspendCredentialMethodName = 'cheqdUnsuspendCredential'
120
+ const UnsuspendCredentialsMethodName = 'cheqdUnsuspendCredentials'
121
+ const TransactVerifierPaysIssuerMethodName = 'cheqdTransactVerifierPaysIssuer'
122
+ const ObserveVerifierPaysIssuerMethodName = 'cheqdObserveVerifierPaysIssuer'
52
123
 
53
124
  const DidPrefix = 'did'
54
125
  const CheqdDidMethod = 'cheqd'
55
126
 
127
+ export interface ICheqdCreateIdentifierArgs {
128
+ kms: string
129
+ alias: string
130
+ document: DIDDocument
131
+ keys?: TImportableEd25519Key[]
132
+ versionId?: string
133
+ fee?: DidStdFee
134
+ }
135
+
136
+ export interface ICheqdUpdateIdentifierArgs {
137
+ kms: string
138
+ document: DIDDocument
139
+ keys?: TImportableEd25519Key[]
140
+ versionId?: string
141
+ fee?: DidStdFee
142
+ }
143
+
144
+ export interface ICheqdDeactivateIdentifierArgs {
145
+ kms: string
146
+ document: DIDDocument
147
+ keys?: TImportableEd25519Key[]
148
+ fee?: DidStdFee
149
+ }
150
+
151
+ export interface ICheqdCreateLinkedResourceArgs {
152
+ kms: string
153
+ payload: ResourcePayload
154
+ network: CheqdNetwork
155
+ file?: string
156
+ signInputs?: ISignInputs[]
157
+ fee?: DidStdFee
158
+ }
159
+
160
+ export interface ICheqdCreateStatusList2021Args {
161
+ kms: string
162
+ payload: StatusList2021ResourcePayload
163
+ network: CheqdNetwork
164
+ file?: string
165
+ signInputs?: ISignInputs[]
166
+ fee?: DidStdFee
167
+ }
168
+
169
+ export interface ICheqdCreateEncryptedStatusList2021Args extends ICheqdCreateStatusList2021Args {
170
+ encryptionOptions: {
171
+ accessControlConditions: (AccessControlConditionMemoNonceArgs | AccessControlConditionBalanceArgs)[]
172
+ returnSymmetricKey?: boolean
173
+ }
174
+ bootstrapOptions: {
175
+ chain?: LitCompatibleCosmosChain,
176
+ litNetwork?: LitNetwork,
177
+ }
178
+ [key: string]: any
179
+ }
180
+
181
+ export interface ICheqdGenerateDidDocArgs {
182
+ verificationMethod: VerificationMethods
183
+ methodSpecificIdAlgo: MethodSpecificIdAlgo
184
+ network: CheqdNetwork
185
+ }
186
+
187
+ export interface ICheqdGenerateDidDocWithLinkedResourceArgs extends ICheqdGenerateDidDocArgs {
188
+ [key: string]: any
189
+ }
190
+
191
+ export interface ICheqdGenerateKeyPairArgs {
192
+ [key: string]: any
193
+ }
194
+
195
+ export interface ICheqdGenerateVersionIdArgs {
196
+ [key: string]: any
197
+ }
198
+
199
+ export interface ICheqdGenerateStatusList2021Args {
200
+ length?: number
201
+ buffer?: Uint8Array
202
+ bitstringEncoding?: 'base64' | 'base64url' | 'hex'
203
+ [key: string]: any
204
+ }
205
+
206
+ export interface ICheqdGenerateEncryptedStatusList2021Args extends ICheqdGenerateStatusList2021Args {
207
+ encryptionOptions: {
208
+ accessControlConditions: (AccessControlConditionMemoNonceArgs | AccessControlConditionBalanceArgs)[]
209
+ returnSymmetricKey?: boolean
210
+ }
211
+ bootstrapOptions: {
212
+ chain?: LitCompatibleCosmosChain,
213
+ litNetwork?: LitNetwork,
214
+ }
215
+ }
216
+
217
+ export interface ICheqdIssueRevocableCredentialWithStatusList2021Args {
218
+ issuanceOptions: ICreateVerifiableCredentialArgs
219
+ statusOptions: {
220
+ statusPurpose: 'revocation'
221
+ statusListName: string
222
+ statusListIndex?: number
223
+ statusListVersion?: string
224
+ statusListRangeStart?: number
225
+ statusListRangeEnd?: number
226
+ indexNotIn?: number[]
227
+ }
228
+ }
229
+
230
+ export interface ICheqdIssueSuspendableCredentialWithStatusList2021Args {
231
+ issuanceOptions: ICreateVerifiableCredentialArgs
232
+ statusOptions: {
233
+ statusPurpose: 'suspension'
234
+ statusListName: string
235
+ statusListIndex?: number
236
+ statusListVersion?: string
237
+ statusListRangeStart?: number
238
+ statusListRangeEnd?: number
239
+ indexNotIn?: number[]
240
+ }
241
+ }
242
+
243
+ export interface ICheqdVerifyCredentialWithStatusList2021Args {
244
+ credential: VerifiableCredential
245
+ fetchList?: boolean
246
+ encryptedSymmetricKey?: string
247
+ options?: ICheqdStatusList2021Options
248
+ decryptionOptions: {
249
+ unifiedAccessControlConditions: CosmosAccessControlCondition[]
250
+ }
251
+ bootstrapOptions: {
252
+ chain?: LitCompatibleCosmosChain,
253
+ litNetwork?: LitNetwork,
254
+ }
255
+ }
256
+
257
+ export interface ICheqdVerifyPresentationWithStatusList2021Args {
258
+ presentation: VerifiablePresentation
259
+ fetchList?: boolean
260
+ encryptedSymmetricKey?: string
261
+ options?: ICheqdStatusList2021Options
262
+ decryptionOptions: {
263
+ accessControlConditions: (AccessControlConditionMemoNonceArgs | AccessControlConditionBalanceArgs)[]
264
+ }
265
+ bootstrapOptions: {
266
+ chain?: LitCompatibleCosmosChain,
267
+ litNetwork?: LitNetwork,
268
+ }
269
+ }
270
+
271
+ export interface ICheqdCheckCredentialStatusWithStatusList2021Args {
272
+ credential: VerifiableCredential
273
+ fetchList?: boolean
274
+ encryptedSymmetricKey?: string
275
+ options?: ICheqdStatusList2021Options
276
+ decryptionOptions: {
277
+ accessControlConditions: (AccessControlConditionMemoNonceArgs | AccessControlConditionBalanceArgs)[]
278
+ }
279
+ bootstrapOptions: {
280
+ chain?: LitCompatibleCosmosChain,
281
+ litNetwork?: LitNetwork,
282
+ }
283
+ }
284
+
285
+ export interface ICheqdRevokeCredentialWithStatusList2021Args {
286
+ credential: VerifiableCredential
287
+ fetchList?: boolean
288
+ publish?: boolean
289
+ publishEncrypted?: boolean
290
+ symmetricKey?: string
291
+ writeToFile?: boolean
292
+ returnUpdatedStatusList?: boolean
293
+ returnUpdatedEncryptedStatusList?: boolean
294
+ returnEncryptedSymmetricKey?: boolean
295
+ returnSymmetricKey?: boolean
296
+ returnStatusListMetadata?: boolean
297
+ options?: ICheqdStatusList2021Options
298
+ }
299
+
300
+ export interface ICheqdRevokeBulkCredentialsWithStatusList2021Args {
301
+ credentials: VerifiableCredential[]
302
+ fetchList?: boolean
303
+ publish?: boolean
304
+ publishEncrypted?: boolean
305
+ symmetricKey?: string
306
+ writeToFile?: boolean
307
+ returnUpdatedStatusList?: boolean
308
+ returnUpdatedEncryptedStatusList?: boolean
309
+ returnEncryptedSymmetricKey?: boolean
310
+ returnSymmetricKey?: boolean
311
+ returnStatusListMetadata?: boolean
312
+ options?: ICheqdStatusList2021Options
313
+ }
314
+
315
+ export interface ICheqdSuspendCredentialWithStatusList2021Args {
316
+ credential: VerifiableCredential
317
+ fetchList?: boolean
318
+ publish?: boolean
319
+ publishEncrypted?: boolean
320
+ symmetricKey?: string
321
+ writeToFile?: boolean
322
+ returnUpdatedStatusList?: boolean
323
+ returnUpdatedEncryptedStatusList?: boolean
324
+ returnEncryptedSymmetricKey?: boolean
325
+ returnSymmetricKey?: boolean
326
+ returnStatusListMetadata?: boolean
327
+ options?: ICheqdStatusList2021Options
328
+ }
329
+
330
+ export interface ICheqdSuspendBulkCredentialsWithStatusList2021Args {
331
+ credentials: VerifiableCredential[]
332
+ fetchList?: boolean
333
+ publish?: boolean
334
+ publishEncrypted?: boolean
335
+ symmetricKey?: string
336
+ writeToFile?: boolean
337
+ returnUpdatedStatusList?: boolean
338
+ returnUpdatedEncryptedStatusList?: boolean
339
+ returnEncryptedSymmetricKey?: boolean
340
+ returnSymmetricKey?: boolean
341
+ returnStatusListMetadata?: boolean
342
+ options?: ICheqdStatusList2021Options
343
+ }
344
+
345
+ export interface ICheqdUnsuspendCredentialWithStatusList2021Args {
346
+ credential: VerifiableCredential
347
+ fetchList?: boolean
348
+ publish?: boolean
349
+ publishEncrypted?: boolean
350
+ symmetricKey?: string
351
+ writeToFile?: boolean
352
+ returnUpdatedStatusList?: boolean
353
+ returnUpdatedEncryptedStatusList?: boolean
354
+ returnEncryptedSymmetricKey?: boolean
355
+ returnSymmetricKey?: boolean
356
+ returnStatusListMetadata?: boolean
357
+ options?: ICheqdStatusList2021Options
358
+ }
359
+
360
+ export interface ICheqdUnsuspendBulkCredentialsWithStatusList2021Args {
361
+ credentials: VerifiableCredential[]
362
+ fetchList?: boolean
363
+ publish?: boolean
364
+ publishEncrypted?: boolean
365
+ symmetricKey?: string
366
+ writeToFile?: boolean
367
+ returnUpdatedStatusList?: boolean
368
+ returnUpdatedEncryptedStatusList?: boolean
369
+ returnEncryptedSymmetricKey?: boolean
370
+ returnSymmetricKey?: boolean
371
+ returnStatusListMetadata?: boolean
372
+ options?: ICheqdStatusList2021Options
373
+ }
374
+
375
+ export interface ICheqdTransactVerifierPaysIssuerArgs {
376
+ recipientAddress: string
377
+ amount: Coin
378
+ memoNonce: string
379
+ txBytes?: Uint8Array
380
+ returnTxResponse?: boolean
381
+ }
382
+
383
+ export interface ICheqdObserveVerifierPaysIssuerArgs {
384
+ senderAddress: string
385
+ recipientAddress: string
386
+ amount: Coin
387
+ memoNonce: string
388
+ network?: CheqdNetwork
389
+ unifiedAccessControlCondition?: Required<CosmosAccessControlCondition>
390
+ returnTxResponse?: boolean
391
+ }
392
+
393
+ export interface ICheqdStatusList2021Options {
394
+ statusListFile?: string
395
+ statusListInlineBitstring?: string
396
+ [key: string]: any
397
+ }
398
+
56
399
  export interface ICheqd extends IPluginMethodMap {
57
- [CreateIdentifierMethodName]: (args: any, context: IContext) => Promise<Omit<IIdentifier, 'provider'>>
58
- [UpdateIdentifierMethodName]: (args: any, context: IContext) => Promise<Omit<IIdentifier, 'provider'>>,
59
- [DeactivateIdentifierMethodName]: (args: any, context: IContext) => Promise<boolean>,
60
- [CreateResourceMethodName]: (args: any, context: IContext) => Promise<boolean>,
61
- [GenerateDidDocMethodName]: (args: any, context: IContext) => Promise<TExportedDIDDocWithKeys>,
62
- [GenerateDidDocWithLinkedResourceMethodName]: (args: any, context: IContext) => Promise<TExportedDIDDocWithLinkedResourceWithKeys>,
63
- [GenerateKeyPairMethodName]: (args: any, context: IContext) => Promise<TImportableEd25519Key>
64
- [GenerateVersionIdMethodName]: (args: any, context: IContext) => Promise<string>
400
+ [CreateIdentifierMethodName]: (args: ICheqdCreateIdentifierArgs, context: IContext) => Promise<Omit<IIdentifier, 'provider'>>
401
+ [UpdateIdentifierMethodName]: (args: ICheqdUpdateIdentifierArgs, context: IContext) => Promise<Omit<IIdentifier, 'provider'>>,
402
+ [DeactivateIdentifierMethodName]: (args: ICheqdDeactivateIdentifierArgs, context: IContext) => Promise<boolean>,
403
+ [CreateResourceMethodName]: (args: ICheqdCreateLinkedResourceArgs, context: IContext) => Promise<boolean>,
404
+ [CreateStatusList2021MethodName]: (args: ICheqdCreateStatusList2021Args, context: IContext) => Promise<boolean>,
405
+ [CreateEncryptedStatusList2021MethodName]: (args: ICheqdCreateEncryptedStatusList2021Args, context: IContext) => Promise<CreateEncryptedStatusList2021Result>,
406
+ [GenerateDidDocMethodName]: (args: ICheqdGenerateDidDocArgs, context: IContext) => Promise<TExportedDIDDocWithKeys>,
407
+ [GenerateDidDocWithLinkedResourceMethodName]: (args: ICheqdGenerateDidDocWithLinkedResourceArgs, context: IContext) => Promise<TExportedDIDDocWithLinkedResourceWithKeys>,
408
+ [GenerateKeyPairMethodName]: (args: ICheqdGenerateKeyPairArgs, context: IContext) => Promise<TImportableEd25519Key>
409
+ [GenerateVersionIdMethodName]: (args: ICheqdGenerateVersionIdArgs, context: IContext) => Promise<string>
410
+ [GenerateStatusList2021MethodName]: (args: ICheqdGenerateStatusList2021Args, context: IContext) => Promise<string>
411
+ [GenerateEncryptedStatusList2021MethodName]: (args: ICheqdGenerateEncryptedStatusList2021Args, context: IContext) => Promise<GenerateEncryptedStatusList2021Result>
412
+ [IssueRevocableCredentialWithStatusList2021MethodName]: (args: ICheqdIssueRevocableCredentialWithStatusList2021Args, context: IContext) => Promise<VerifiableCredential>
413
+ [IssueSuspendableCredentialWithStatusList2021MethodName]: (args: ICheqdIssueSuspendableCredentialWithStatusList2021Args, context: IContext) => Promise<VerifiableCredential>
414
+ [VerifyCredentialMethodName]: (args: ICheqdVerifyCredentialWithStatusList2021Args, context: IContext) => Promise<VerificationResult>
415
+ [VerifyPresentationMethodName]: (args: ICheqdVerifyPresentationWithStatusList2021Args, context: IContext) => Promise<VerificationResult>
416
+ [CheckCredentialStatusMethodName]: (args: ICheqdCheckCredentialStatusWithStatusList2021Args, context: IContext) => Promise<StatusCheckResult>
417
+ [RevokeCredentialMethodName]: (args: ICheqdRevokeCredentialWithStatusList2021Args, context: IContext) => Promise<RevocationResult>
418
+ [RevokeCredentialsMethodName]: (args: ICheqdRevokeBulkCredentialsWithStatusList2021Args, context: IContext) => Promise<RevocationResult[]>
419
+ [SuspendCredentialMethodName]: (args: ICheqdSuspendCredentialWithStatusList2021Args, context: IContext) => Promise<SuspensionResult>
420
+ [SuspendCredentialsMethodName]: (args: ICheqdSuspendBulkCredentialsWithStatusList2021Args, context: IContext) => Promise<SuspensionResult[]>
421
+ [UnsuspendCredentialMethodName]: (args: ICheqdUnsuspendCredentialWithStatusList2021Args, context: IContext) => Promise<UnsuspensionResult>
422
+ [UnsuspendCredentialsMethodName]: (args: ICheqdUnsuspendBulkCredentialsWithStatusList2021Args, context: IContext) => Promise<UnsuspensionResult[]>
423
+ [TransactVerifierPaysIssuerMethodName]: (args: ICheqdTransactVerifierPaysIssuerArgs, context: IContext) => Promise<TransactionResult>
424
+ [ObserveVerifierPaysIssuerMethodName]: (args: ICheqdObserveVerifierPaysIssuerArgs, context: IContext) => Promise<ObservationResult>
65
425
  }
66
426
 
67
427
  export class Cheqd implements IAgentPlugin {
@@ -138,6 +498,42 @@ export class Cheqd implements IAgentPlugin {
138
498
  "args"
139
499
  ]
140
500
  },
501
+ "returnType": {
502
+ "type": "boolean"
503
+ }
504
+ },
505
+ "cheqdCreateStatusList2021": {
506
+ "description": "Create a new Status List 2021",
507
+ "arguments": {
508
+ "type": "object",
509
+ "properties": {
510
+ "args": {
511
+ "type": "object",
512
+ "description": "A cheqdCreateStatusList2021Args object as any for extensibility"
513
+ }
514
+ },
515
+ "required": [
516
+ "args"
517
+ ]
518
+ },
519
+ "returnType": {
520
+ "type": "boolean"
521
+ }
522
+ },
523
+ "cheqdCreateEncryptedStatusList2021": {
524
+ "description": "Create a new Encrypted Status List 2021",
525
+ "arguments": {
526
+ "type": "object",
527
+ "properties": {
528
+ "args": {
529
+ "type": "object",
530
+ "description": "A cheqdCreateEncryptedStatusList2021Args object as any for extensibility"
531
+ }
532
+ },
533
+ "required": [
534
+ "args"
535
+ ]
536
+ },
141
537
  "returnType": {
142
538
  "type": "object"
143
539
  }
@@ -202,248 +598,1808 @@ export class Cheqd implements IAgentPlugin {
202
598
  "type": "object",
203
599
  "description": "A cheqdGenerateVersionIdArgs object as any for extensibility"
204
600
  }
205
- }
601
+ },
206
602
  },
207
603
  "returnType": {
208
604
  "type": "object"
209
605
  }
210
- }
211
- }
212
- }
213
- }
214
- private readonly supportedDidProviders: CheqdDIDProvider[]
215
- private didProvider: CheqdDIDProvider;
216
- private providerId: string;
217
-
218
- constructor(args: { providers: CheqdDIDProvider[] }) {
219
- if (typeof args.providers !== 'object') {
220
- throw new Error('[did-provider-cheqd]: at least one did provider is required')
221
- }
222
-
223
- this.supportedDidProviders = args.providers
224
- this.didProvider = args.providers[0]
225
- this.providerId = Cheqd.generateProviderId(this.didProvider.network)
226
-
227
- this.methods = {
228
- [CreateIdentifierMethodName]: this.CreateIdentifier.bind(this),
229
- [UpdateIdentifierMethodName]: this.UpdateIdentifier.bind(this),
230
- [DeactivateIdentifierMethodName]: this.DeactivateIdentifier.bind(this),
231
- [CreateResourceMethodName]: this.CreateResource.bind(this),
232
- [GenerateDidDocMethodName]: this.GenerateDidDoc.bind(this),
233
- [GenerateDidDocWithLinkedResourceMethodName]: this.GenerateDidDocWithLinkedResource.bind(this),
234
- [GenerateKeyPairMethodName]: this.GenerateIdentityKeys.bind(this),
235
- [GenerateVersionIdMethodName]: this.GenerateVersionId.bind(this)
236
- }
237
- }
238
-
239
- private async CreateIdentifier(args: any, context: IContext): Promise<Omit<IIdentifier, 'provider'>> {
240
- if (typeof args.kms !== 'string') {
241
- throw new Error('[did-provider-cheqd]: kms is required')
242
- }
243
-
244
- if (typeof args.alias !== 'string') {
245
- throw new Error('[did-provider-cheqd]: alias is required')
246
- }
247
-
248
- if (typeof args.document !== 'object') {
249
- throw new Error('[did-provider-cheqd]: document object is required')
250
- }
251
-
252
- const provider = await Cheqd.loadProvider(<DIDDocument>args.document, this.supportedDidProviders)
253
-
254
- this.didProvider = provider
255
- this.providerId = Cheqd.generateProviderId(this.didProvider.network)
256
-
257
- return await context.agent.didManagerCreate({
258
- kms: args.kms,
259
- alias: args.alias,
260
- provider: this.providerId,
261
- options: {
262
- document: args.document,
263
- keys: args.keys,
264
- versionId: args?.versionId,
265
- fee: args?.fee
266
- }
267
- })
268
- }
269
-
270
- private async UpdateIdentifier(args: any, context: IContext): Promise<Omit<IIdentifier, 'provider'>> {
271
- if (typeof args.kms !== 'string') {
272
- throw new Error('[did-provider-cheqd]: kms is required')
273
- }
274
-
275
- if (typeof args.document !== 'object') {
276
- throw new Error('[did-provider-cheqd]: document object is required')
277
- }
278
-
279
- const provider = await Cheqd.loadProvider(<DIDDocument>args.document, this.supportedDidProviders)
280
-
281
- this.didProvider = provider
282
- this.providerId = Cheqd.generateProviderId(this.didProvider.network)
283
-
284
- return await context.agent.didManagerUpdate({
285
- did: args.document.id,
286
- document: args.document,
287
- provider: this.providerId,
288
- options: {
289
- kms: args.kms,
290
- keys: args.keys,
291
- versionId: args?.versionId,
292
- fee: args?.fee
293
- }
294
- })
295
- }
296
-
297
- private async DeactivateIdentifier(args: any, context: IContext) {
298
- if (typeof args.kms !== 'string') {
299
- throw new Error('[did-provider-cheqd]: kms is required')
300
- }
301
-
302
- if (typeof args.document !== 'object') {
303
- throw new Error('[did-provider-cheqd]: document object is required')
304
- }
305
-
306
- const provider = await Cheqd.loadProvider(<DIDDocument>args.document, this.supportedDidProviders)
307
-
308
- this.didProvider = provider
309
- this.providerId = Cheqd.generateProviderId(this.didProvider.network)
310
-
311
- return await this.didProvider.deactivateIdentifier({
312
- did: args.document.id,
313
- document: args.document,
314
- options: {
315
- keys: args.keys,
316
- fee: args?.fee
317
- }
318
- }, context)
319
- }
320
-
321
- private async CreateResource(args: any, context: IContext) {
322
- if (typeof args.kms !== 'string') {
323
- throw new Error('[did-provider-cheqd]: kms is required')
324
- }
325
-
326
- if (typeof args.payload !== 'object') {
327
- throw new Error('[did-provider-cheqd]: payload object is required')
328
- }
329
-
330
- if (typeof args.network !== 'string') {
331
- throw new Error('[did-provider-cheqd]: network is required')
332
- }
333
-
334
- if (args?.file) {
335
- args.payload.data = toString(await Cheqd.getFile(args.file), 'base64')
336
- }
337
-
338
- if (typeof args?.payload?.data === 'string') {
339
- args.payload.data = fromString(args.payload.data, 'base64')
340
- }
341
-
342
- this.providerId = Cheqd.generateProviderId(args.network)
343
- this.didProvider = await Cheqd.loadProvider({ id: this.providerId } as DIDDocument, this.supportedDidProviders)
344
-
345
- return await this.didProvider.createResource({
346
- options: {
347
- kms: args.kms,
348
- payload: args.payload,
349
-
350
- signInputs: args.signInputs,
351
- fee: args?.fee
352
- }
353
- }, context)
354
- }
355
-
356
- private async GenerateDidDoc(
357
- args: { verificationMethod: VerificationMethods, methodSpecificIdAlgo: MethodSpecificIdAlgo, network: CheqdNetwork },
358
- context: IContext
359
- ): Promise<TExportedDIDDocWithKeys> {
360
- if (typeof args.verificationMethod !== 'string') {
361
- throw new Error('[did-provider-cheqd]: verificationMethod is required')
362
- }
363
-
364
- if (typeof args.methodSpecificIdAlgo !== 'string') {
365
- throw new Error('[did-provider-cheqd]: methodSpecificIdAlgo is required')
366
- }
367
-
368
- if (typeof args.network !== 'string') {
369
- throw new Error('[did-provider-cheqd]: network is required')
370
- }
371
-
372
- const keyPair = createKeyPairBase64()
373
- const keyPairHex: IKeyPair = { publicKey: toString(fromString(keyPair.publicKey, 'base64'), 'hex'), privateKey: toString(fromString(keyPair.privateKey, 'base64'), 'hex') }
374
- const verificationKeys = createVerificationKeys(keyPair.publicKey, args.methodSpecificIdAlgo, 'key-1', args.network)
375
- const verificationMethods = createDidVerificationMethod([args.verificationMethod], [verificationKeys])
606
+ },
607
+ "cheqdGenerateStatusList2021": {
608
+ "description": "Generate a new Status List 2021",
609
+ "arguments": {
610
+ "type": "object",
611
+ "properties": {
612
+ "args": {
613
+ "type": "object",
614
+ "description": "A cheqdGenerateStatusList2021Args object as any for extensibility"
615
+ }
616
+ },
617
+ },
618
+ "returnType": {
619
+ "type": "string"
620
+ }
621
+ },
622
+ "cheqdGenerateEncryptedStatusList2021": {
623
+ "description": "Generate a new encrypted Status List 2021",
624
+ "arguments": {
625
+ "type": "object",
626
+ "properties": {
627
+ "args": {
628
+ "type": "object",
629
+ "description": "A cheqdGenerateEncryptedStatusList2021Args object as any for extensibility"
630
+ }
631
+ },
632
+ "required": [
633
+ "args"
634
+ ]
635
+ },
636
+ "returnType": {
637
+ "type": "string"
638
+ }
639
+ },
640
+ "cheqdIssueRevocableCredentialWithStatusList2021": {
641
+ "description": "Issue a revocable credential with a Status List 2021 as credential status registry",
642
+ "arguments": {
643
+ "type": "object",
644
+ "properties": {
645
+ "args": {
646
+ "type": "object",
647
+ "description": "A cheqdIssueCredentialWithStatusList2021Args object as any for extensibility"
648
+ }
649
+ },
650
+ "required": [
651
+ "args"
652
+ ]
653
+ },
654
+ "returnType": {
655
+ "type": "object"
656
+ }
657
+ },
658
+ "cheqdIssueSuspendableCredentialWithStatusList2021": {
659
+ "description": "Issue a suspendable credential with a Status List 2021 as credential status registry",
660
+ "arguments": {
661
+ "type": "object",
662
+ "properties": {
663
+ "args": {
664
+ "type": "object",
665
+ "description": "A cheqdIssueCredentialWithStatusList2021Args object as any for extensibility"
666
+ }
667
+ },
668
+ "required": [
669
+ "args"
670
+ ]
671
+ },
672
+ "returnType": {
673
+ "type": "object"
674
+ }
675
+ },
676
+ "cheqdVerifyCredential": {
677
+ "description": "Verify a credential, enhanced by revocation / suspension check with a Status List 2021 as credential status registry",
678
+ "arguments": {
679
+ "type": "object",
680
+ "properties": {
681
+ "args": {
682
+ "type": "object",
683
+ "description": "A cheqdVerifyCredentialWithStatusList2021Args object as any for extensibility"
684
+ }
685
+ },
686
+ "required": [
687
+ "args"
688
+ ]
689
+ },
690
+ "returnType": {
691
+ "type": "object"
692
+ }
693
+ },
694
+ "cheqdVerifyPresentation": {
695
+ "description": "Verify a presentation, enhanced by revocation / suspension check with a Status List 2021 as credential status registry",
696
+ "arguments": {
697
+ "type": "object",
698
+ "properties": {
699
+ "args": {
700
+ "type": "object",
701
+ "description": "A cheqdVerifyPresentationWithStatusList2021Args object as any for extensibility"
702
+ }
703
+ },
704
+ "required": [
705
+ "args"
706
+ ]
707
+ },
708
+ "returnType": {
709
+ "type": "object"
710
+ }
711
+ },
712
+ "cheqdCheckCredentialStatus": {
713
+ "description": "Check the revocation / suspension status of a credential with a Status List 2021 as credential status registry",
714
+ "arguments": {
715
+ "type": "object",
716
+ "properties": {
717
+ "args": {
718
+ "type": "object",
719
+ "description": "A cheqdCheckCredentialStatusWithStatusList2021Args object as any for extensibility"
720
+ }
721
+ },
722
+ "required": [
723
+ "args"
724
+ ]
725
+ },
726
+ "returnType": {
727
+ "type": "object"
728
+ }
729
+ },
730
+ "cheqdRevokeCredential": {
731
+ "description": "Revoke a credential against a Status List 2021 as credential status registry",
732
+ "arguments": {
733
+ "type": "object",
734
+ "properties": {
735
+ "args": {
736
+ "type": "object",
737
+ "description": "A cheqdRevokeCredentialWithStatusList2021Args object as any for extensibility"
738
+ }
739
+ },
740
+ "required": [
741
+ "args"
742
+ ]
743
+ },
744
+ "returnType": {
745
+ "type": "object"
746
+ }
747
+ },
748
+ "cheqdRevokeCredentials": {
749
+ "description": "Revoke multiple credentials against a Status List 2021 as credential status registry",
750
+ "arguments": {
751
+ "type": "object",
752
+ "properties": {
753
+ "args": {
754
+ "type": "object",
755
+ "description": "A cheqdRevokeBulkCredentialsWithStatusList2021Args object as any for extensibility"
756
+ }
757
+ },
758
+ "required": [
759
+ "args"
760
+ ]
761
+ },
762
+ "returnType": {
763
+ "type": "array"
764
+ }
765
+ },
766
+ "cheqdSuspendCredential": {
767
+ "description": "Suspend a credential against a Status List 2021 as credential status registry",
768
+ "arguments": {
769
+ "type": "object",
770
+ "properties": {
771
+ "args": {
772
+ "type": "object",
773
+ "description": "A cheqdSuspendCredentialWithStatusList2021Args object as any for extensibility"
774
+ }
775
+ },
776
+ "required": [
777
+ "args"
778
+ ]
779
+ },
780
+ "returnType": {
781
+ "type": "object"
782
+ }
783
+ },
784
+ "cheqdSuspendCredentials": {
785
+ "description": "Suspend multiple credentials against a Status List 2021 as credential status registry",
786
+ "arguments": {
787
+ "type": "object",
788
+ "properties": {
789
+ "args": {
790
+ "type": "object",
791
+ "description": "A cheqdSuspendBulkCredentialsWithStatusList2021Args object as any for extensibility"
792
+ }
793
+ },
794
+ "required": [
795
+ "args"
796
+ ]
797
+ },
798
+ "returnType": {
799
+ "type": "array"
800
+ }
801
+ },
802
+ "cheqdUnsuspendCredential": {
803
+ "description": "Unsuspend a credential against a Status List 2021 as credential status registry",
804
+ "arguments": {
805
+ "type": "object",
806
+ "properties": {
807
+ "args": {
808
+ "type": "object",
809
+ "description": "cheqdUnsuspendCredentialWithStatusList2021Args object as any for extensibility"
810
+ }
811
+ },
812
+ "required": [
813
+ "args"
814
+ ]
815
+ },
816
+ "returnType": {
817
+ "type": "object"
818
+ }
819
+ },
820
+ "cheqdUnsuspendCredentials": {
821
+ "description": "Unsuspend multiple credentials against a Status List 2021 as credential status registry",
822
+ "arguments": {
823
+ "type": "object",
824
+ "properties": {
825
+ "args": {
826
+ "type": "object",
827
+ "description": "A cheqdUnsuspendBulkCredentialsWithStatusList2021Args object as any for extensibility"
828
+ }
829
+ },
830
+ "required": [
831
+ "args"
832
+ ]
833
+ },
834
+ "returnType": {
835
+ "type": "array"
836
+ }
837
+ },
838
+ "cheqdTransactVerifierPaysIssuer": {
839
+ "description": "Initiate a transaction where the verifier pays the issuer for a credential status check",
840
+ "arguments": {
841
+ "type": "object",
842
+ "properties": {
843
+ "args": {
844
+ "type": "object",
845
+ "description": "A cheqdTransactVerifierPaysIssuerArgs object as any for extensibility"
846
+ }
847
+ },
848
+ "required": [
849
+ "args"
850
+ ]
851
+ },
852
+ "returnType": {
853
+ "type": "object"
854
+ }
855
+ },
856
+ "cheqdObserveVerifierPaysIssuer": {
857
+ "description": "Observe a transaction where the verifier pays the issuer for a credential status check",
858
+ "arguments": {
859
+ "type": "object",
860
+ "properties": {
861
+ "args": {
862
+ "type": "object",
863
+ "description": "cheqdObserveVerifierPaysIssuerArgs object as any for extensibility"
864
+ }
865
+ },
866
+ "required": [
867
+ "args"
868
+ ]
869
+ },
870
+ "returnType": {
871
+ "type": "object"
872
+ }
873
+ }
874
+ }
875
+ }
876
+ }
877
+ private readonly supportedDidProviders: CheqdDIDProvider[]
878
+ private didProvider: CheqdDIDProvider;
879
+ private providerId: string;
880
+ static readonly defaultStatusList2021Length: number = 16 * 1024 * 8 // 16KB in bits or 131072 bits / entries
881
+ static readonly defaultContextV1 = 'https://www.w3.org/2018/credentials/v1'
882
+ static readonly statusList2021Context = 'https://w3id.org/vc-status-list-2021/v1'
883
+
884
+
885
+ constructor(args: { providers: CheqdDIDProvider[] }) {
886
+ if (typeof args.providers !== 'object') {
887
+ throw new Error('[did-provider-cheqd]: at least one did provider is required')
888
+ }
889
+
890
+ this.supportedDidProviders = args.providers
891
+ this.didProvider = args.providers[0]
892
+ this.providerId = Cheqd.generateProviderId(this.didProvider.network)
893
+
894
+ this.methods = {
895
+ [CreateIdentifierMethodName]: this.CreateIdentifier.bind(this),
896
+ [UpdateIdentifierMethodName]: this.UpdateIdentifier.bind(this),
897
+ [DeactivateIdentifierMethodName]: this.DeactivateIdentifier.bind(this),
898
+ [CreateResourceMethodName]: this.CreateResource.bind(this),
899
+ [CreateStatusList2021MethodName]: this.CreateStatusList2021.bind(this),
900
+ [CreateEncryptedStatusList2021MethodName]: this.CreateEncryptedStatusList2021.bind(this),
901
+ [GenerateDidDocMethodName]: this.GenerateDidDoc.bind(this),
902
+ [GenerateDidDocWithLinkedResourceMethodName]: this.GenerateDidDocWithLinkedResource.bind(this),
903
+ [GenerateKeyPairMethodName]: this.GenerateIdentityKeys.bind(this),
904
+ [GenerateVersionIdMethodName]: this.GenerateVersionId.bind(this),
905
+ [GenerateStatusList2021MethodName]: this.GenerateStatusList2021.bind(this),
906
+ [GenerateEncryptedStatusList2021MethodName]: this.GenerateEncryptedStatusList2021.bind(this),
907
+ [IssueRevocableCredentialWithStatusList2021MethodName]: this.IssueRevocableCredentialWithStatusList2021.bind(this),
908
+ [IssueSuspendableCredentialWithStatusList2021MethodName]: this.IssueSuspendableCredentialWithStatusList2021.bind(this),
909
+ [VerifyCredentialMethodName]: this.VerifyCredentialWithStatusList2021.bind(this),
910
+ [VerifyPresentationMethodName]: this.VerifyPresentationWithStatusList2021.bind(this),
911
+ [CheckCredentialStatusMethodName]: this.CheckCredentialStatusWithStatusList2021.bind(this),
912
+ [RevokeCredentialMethodName]: this.RevokeCredentialWithStatusList2021.bind(this),
913
+ [RevokeCredentialsMethodName]: this.RevokeBulkCredentialsWithStatusList2021.bind(this),
914
+ [SuspendCredentialMethodName]: this.SuspendCredentialWithStatusList2021.bind(this),
915
+ [SuspendCredentialsMethodName]: this.SuspendBulkCredentialsWithStatusList2021.bind(this),
916
+ [UnsuspendCredentialMethodName]: this.UnsuspendCredentialWithStatusList2021.bind(this),
917
+ [UnsuspendCredentialsMethodName]: this.UnsuspendBulkCredentialsWithStatusList2021.bind(this),
918
+ [TransactVerifierPaysIssuerMethodName]: this.TransactVerifierPaysIssuer.bind(this),
919
+ [ObserveVerifierPaysIssuerMethodName]: this.ObserveVerifierPaysIssuer.bind(this),
920
+ }
921
+ }
922
+
923
+ private async CreateIdentifier(args: ICheqdCreateIdentifierArgs, context: IContext): Promise<Omit<IIdentifier, 'provider'>> {
924
+ if (typeof args.kms !== 'string') {
925
+ throw new Error('[did-provider-cheqd]: kms is required')
926
+ }
927
+
928
+ if (typeof args.alias !== 'string') {
929
+ throw new Error('[did-provider-cheqd]: alias is required')
930
+ }
931
+
932
+ if (typeof args.document !== 'object') {
933
+ throw new Error('[did-provider-cheqd]: document object is required')
934
+ }
935
+
936
+ const provider = await Cheqd.loadProvider(<DIDDocument>args.document, this.supportedDidProviders)
937
+
938
+ this.didProvider = provider
939
+ this.providerId = Cheqd.generateProviderId(this.didProvider.network)
940
+
941
+ return await context.agent.didManagerCreate({
942
+ kms: args.kms,
943
+ alias: args.alias,
944
+ provider: this.providerId,
945
+ options: {
946
+ document: args.document,
947
+ keys: args.keys,
948
+ versionId: args?.versionId,
949
+ fee: args?.fee
950
+ }
951
+ })
952
+ }
953
+
954
+ private async UpdateIdentifier(args: ICheqdUpdateIdentifierArgs, context: IContext): Promise<Omit<IIdentifier, 'provider'>> {
955
+ if (typeof args.kms !== 'string') {
956
+ throw new Error('[did-provider-cheqd]: kms is required')
957
+ }
958
+
959
+ if (typeof args.document !== 'object') {
960
+ throw new Error('[did-provider-cheqd]: document object is required')
961
+ }
962
+
963
+ const provider = await Cheqd.loadProvider(<DIDDocument>args.document, this.supportedDidProviders)
964
+
965
+ this.didProvider = provider
966
+ this.providerId = Cheqd.generateProviderId(this.didProvider.network)
967
+
968
+ return await context.agent.didManagerUpdate({
969
+ did: args.document.id,
970
+ document: args.document,
971
+ options: {
972
+ kms: args.kms,
973
+ keys: args.keys,
974
+ versionId: args?.versionId,
975
+ fee: args?.fee
976
+ }
977
+ })
978
+ }
979
+
980
+ private async DeactivateIdentifier(args: ICheqdDeactivateIdentifierArgs, context: IContext) {
981
+ if (typeof args.kms !== 'string') {
982
+ throw new Error('[did-provider-cheqd]: kms is required')
983
+ }
984
+
985
+ if (typeof args.document !== 'object') {
986
+ throw new Error('[did-provider-cheqd]: document object is required')
987
+ }
988
+
989
+ const provider = await Cheqd.loadProvider(<DIDDocument>args.document, this.supportedDidProviders)
990
+
991
+ this.didProvider = provider
992
+ this.providerId = Cheqd.generateProviderId(this.didProvider.network)
993
+
994
+ return await this.didProvider.deactivateIdentifier({
995
+ did: args.document.id,
996
+ document: args.document,
997
+ options: {
998
+ keys: args.keys,
999
+ fee: args?.fee
1000
+ }
1001
+ }, context)
1002
+ }
1003
+
1004
+ private async CreateResource(args: ICheqdCreateLinkedResourceArgs, context: IContext) {
1005
+ if (typeof args.kms !== 'string') {
1006
+ throw new Error('[did-provider-cheqd]: kms is required')
1007
+ }
1008
+
1009
+ if (typeof args.payload !== 'object') {
1010
+ throw new Error('[did-provider-cheqd]: payload object is required')
1011
+ }
1012
+
1013
+ if (typeof args.network !== 'string') {
1014
+ throw new Error('[did-provider-cheqd]: network is required')
1015
+ }
1016
+
1017
+ if (args?.file) {
1018
+ args.payload.data = await Cheqd.getFile(args.file)
1019
+ }
1020
+
1021
+ if (typeof args?.payload?.data === 'string') {
1022
+ args.payload.data = fromString(args.payload.data, 'base64')
1023
+ }
1024
+
1025
+ this.providerId = Cheqd.generateProviderId(args.network)
1026
+ this.didProvider = await Cheqd.loadProvider({ id: this.providerId } as DIDDocument, this.supportedDidProviders)
1027
+
1028
+ return await this.didProvider.createResource({
1029
+ options: {
1030
+ kms: args.kms,
1031
+ payload: args.payload,
1032
+ signInputs: args.signInputs,
1033
+ fee: args?.fee
1034
+ }
1035
+ }, context)
1036
+ }
1037
+
1038
+ private async CreateStatusList2021(args: ICheqdCreateStatusList2021Args, context: IContext) {
1039
+ if (typeof args.kms !== 'string') {
1040
+ throw new Error('[did-provider-cheqd]: kms is required')
1041
+ }
1042
+
1043
+ if (typeof args.payload !== 'object') {
1044
+ throw new Error('[did-provider-cheqd]: payload object is required')
1045
+ }
1046
+
1047
+ if (typeof args.network !== 'string') {
1048
+ throw new Error('[did-provider-cheqd]: network is required')
1049
+ }
1050
+
1051
+ if (args?.file) {
1052
+ args.payload.data = await Cheqd.getFile(args.file)
1053
+ }
1054
+
1055
+ if (typeof args?.payload?.data === 'string') {
1056
+ args.payload.data = fromString(args.payload.data, 'base64')
1057
+ }
1058
+
1059
+ // TODO: validate data as per bitstring
1060
+
1061
+ // set default resource type in runtime
1062
+ args.payload.resourceType = 'StatusList2021'
1063
+
1064
+ this.providerId = Cheqd.generateProviderId(args.network)
1065
+ this.didProvider = await Cheqd.loadProvider({ id: this.providerId } as DIDDocument, this.supportedDidProviders)
1066
+
1067
+ return await this.didProvider.createResource({
1068
+ options: {
1069
+ kms: args.kms,
1070
+ payload: args.payload,
1071
+ signInputs: args.signInputs,
1072
+ fee: args?.fee
1073
+ }
1074
+ }, context)
1075
+ }
1076
+
1077
+ private async CreateEncryptedStatusList2021(args: ICheqdCreateEncryptedStatusList2021Args, context: IContext): Promise<CreateEncryptedStatusList2021Result> {
1078
+ if (typeof args.kms !== 'string') {
1079
+ throw new Error('[did-provider-cheqd]: kms is required')
1080
+ }
1081
+
1082
+ if (typeof args.payload !== 'object') {
1083
+ throw new Error('[did-provider-cheqd]: payload object is required')
1084
+ }
1085
+
1086
+ if (typeof args.network !== 'string') {
1087
+ throw new Error('[did-provider-cheqd]: network is required')
1088
+ }
1089
+
1090
+ if (args?.file) {
1091
+ args.payload.data = await Cheqd.getFile(args.file)
1092
+ }
1093
+
1094
+ if (typeof args?.payload?.data === 'string') {
1095
+ args.payload.data = fromString(args.payload.data, 'base64')
1096
+ }
1097
+
1098
+ // TODO: validate data as per bitstring
1099
+
1100
+ if (!args?.encryptionOptions) {
1101
+ throw new Error('[did-provider-cheqd]: encryptionOptions is required')
1102
+ }
1103
+
1104
+ if (!args?.bootstrapOptions) {
1105
+ throw new Error('[did-provider-cheqd]: bootstrapOptions is required')
1106
+ }
1107
+
1108
+ if (!args?.encryptionOptions?.accessControlConditions) {
1109
+ throw new Error('[did-provider-cheqd]: accessControlConditions is required')
1110
+ }
1111
+
1112
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1113
+ const lit = await LitProtocol.create({
1114
+ chain: args.bootstrapOptions?.chain,
1115
+ litNetwork: args.bootstrapOptions?.litNetwork
1116
+ })
1117
+
1118
+ // construct access control conditions
1119
+ const unifiedAccessControlConditions = await Promise.all(args.encryptionOptions.accessControlConditions.map(async (condition) => {
1120
+ switch (condition.type) {
1121
+ case AccessControlConditionTypes.memoNonce:
1122
+ return await LitProtocol.generateCosmosAccessControlConditionTransactionMemo({
1123
+ key: '$.txs.*.body.memo',
1124
+ comparator: 'contains',
1125
+ value: condition?.specificNonce || await LitProtocol.generateTxNonce(condition?.nonceFormat)
1126
+ },
1127
+ condition.amountObserved,
1128
+ condition.senderAddressObserved,
1129
+ condition.recipientAddressObserved,
1130
+ args.bootstrapOptions.chain
1131
+ )
1132
+ case AccessControlConditionTypes.balance:
1133
+ return await LitProtocol.generateCosmosAccessControlConditionBalance({
1134
+ key: '$.balances[0].amount',
1135
+ comparator: condition.comparator,
1136
+ value: condition.amountObserved
1137
+ },
1138
+ args.bootstrapOptions.chain,
1139
+ condition.addressObserved
1140
+ )
1141
+ default:
1142
+ throw new Error(`[did-provider-cheqd]: accessControlCondition type is not supported`)
1143
+ }
1144
+ }))
1145
+
1146
+ // encrypt data
1147
+ const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(toString(args.payload.data!, 'base64url'), unifiedAccessControlConditions, true)
1148
+
1149
+ // set encrypted data
1150
+ args.payload.data = new Uint8Array(await encryptedString.arrayBuffer())
1151
+
1152
+ // set default resource type in runtime
1153
+ args.payload.resourceType = 'StatusList2021'
1154
+
1155
+ this.providerId = Cheqd.generateProviderId(args.network)
1156
+ this.didProvider = await Cheqd.loadProvider({ id: this.providerId } as DIDDocument, this.supportedDidProviders)
1157
+
1158
+ const created = await this.didProvider.createResource({
1159
+ options: {
1160
+ kms: args.kms,
1161
+ payload: args.payload,
1162
+ signInputs: args.signInputs,
1163
+ fee: args?.fee
1164
+ }
1165
+ }, context)
1166
+
1167
+ return {
1168
+ created,
1169
+ encryptedSymmetricKey,
1170
+ encryptedStatusList2021: await blobToHexString(encryptedString),
1171
+ symmetricKey: args?.encryptionOptions?.returnSymmetricKey ? toString(symmetricKey!, 'hex') : undefined,
1172
+ unifiedAccessControlConditions
1173
+ } satisfies CreateEncryptedStatusList2021Result
1174
+ }
1175
+
1176
+ private async GenerateDidDoc(
1177
+ args: ICheqdGenerateDidDocArgs,
1178
+ context: IContext
1179
+ ): Promise<TExportedDIDDocWithKeys> {
1180
+ if (typeof args.verificationMethod !== 'string') {
1181
+ throw new Error('[did-provider-cheqd]: verificationMethod is required')
1182
+ }
1183
+
1184
+ if (typeof args.methodSpecificIdAlgo !== 'string') {
1185
+ throw new Error('[did-provider-cheqd]: methodSpecificIdAlgo is required')
1186
+ }
1187
+
1188
+ if (typeof args.network !== 'string') {
1189
+ throw new Error('[did-provider-cheqd]: network is required')
1190
+ }
1191
+
1192
+ const keyPair = createKeyPairBase64()
1193
+ const keyPairHex: IKeyPair = { publicKey: toString(fromString(keyPair.publicKey, 'base64'), 'hex'), privateKey: toString(fromString(keyPair.privateKey, 'base64'), 'hex') }
1194
+ const verificationKeys = createVerificationKeys(keyPair.publicKey, args.methodSpecificIdAlgo, 'key-1', args.network)
1195
+ const verificationMethods = createDidVerificationMethod([args.verificationMethod], [verificationKeys])
1196
+
1197
+ return {
1198
+ didDoc: createDidPayload(verificationMethods, [verificationKeys]),
1199
+ versionId: v4(),
1200
+ keys: [
1201
+ {
1202
+ publicKeyHex: keyPairHex.publicKey,
1203
+ privateKeyHex: keyPairHex.privateKey,
1204
+ kid: keyPairHex.publicKey,
1205
+ type: 'Ed25519'
1206
+ }
1207
+ ]
1208
+ }
1209
+ }
1210
+
1211
+ private async GenerateDidDocWithLinkedResource(args: any, context: IContext): Promise<TExportedDIDDocWithLinkedResourceWithKeys> {
1212
+ if (typeof args.verificationMethod !== 'string') {
1213
+ throw new Error('[did-provider-cheqd]: verificationMethod is required')
1214
+ }
1215
+
1216
+ if (typeof args.methodSpecificIdAlgo !== 'string') {
1217
+ throw new Error('[did-provider-cheqd]: methodSpecificIdAlgo is required')
1218
+ }
1219
+
1220
+ if (typeof args.network !== 'string') {
1221
+ throw new Error('[did-provider-cheqd]: network is required')
1222
+ }
1223
+
1224
+ const keyPair = createKeyPairBase64()
1225
+ const keyPairHex: IKeyPair = { publicKey: toString(fromString(keyPair.publicKey, 'base64'), 'hex'), privateKey: toString(fromString(keyPair.privateKey, 'base64'), 'hex') }
1226
+ const verificationKeys = createVerificationKeys(keyPair.publicKey, args.methodSpecificIdAlgo, 'key-1', args.network)
1227
+ const verificationMethods = createDidVerificationMethod([args.verificationMethod], [verificationKeys])
1228
+ const payload = createDidPayload(verificationMethods, [verificationKeys])
1229
+
1230
+ return {
1231
+ didDoc: payload,
1232
+ versionId: v4(),
1233
+ keys: [
1234
+ {
1235
+ publicKeyHex: keyPairHex.publicKey,
1236
+ privateKeyHex: keyPairHex.privateKey,
1237
+ kid: keyPairHex.publicKey,
1238
+ type: 'Ed25519'
1239
+ }
1240
+ ],
1241
+ linkedResource: {
1242
+ id: v4(),
1243
+ collectionId: payload.id.split(':').reverse()[0],
1244
+ name: 'sample json resource',
1245
+ version: '1.0.0',
1246
+ resourceType: 'SampleResource',
1247
+ alsoKnownAs: [],
1248
+ data: toString(new TextEncoder().encode(
1249
+ JSON.stringify({ sample: 'json' })
1250
+ ), 'base64'),
1251
+ }
1252
+ }
1253
+ }
1254
+
1255
+ private async GenerateIdentityKeys(args: any, context: IContext): Promise<TImportableEd25519Key> {
1256
+ const keyPair = createKeyPairHex()
1257
+ return {
1258
+ publicKeyHex: keyPair.publicKey,
1259
+ privateKeyHex: keyPair.privateKey,
1260
+ kid: keyPair.publicKey,
1261
+ type: 'Ed25519'
1262
+ }
1263
+ }
1264
+
1265
+ private async GenerateVersionId(args: any, context: IContext): Promise<string> {
1266
+ return v4()
1267
+ }
1268
+
1269
+ private async GenerateStatusList2021(args: ICheqdGenerateStatusList2021Args, context: IContext): Promise<Bitstring> {
1270
+ const statusList = args?.buffer
1271
+ ? new StatusList({ buffer: args.buffer })
1272
+ : new StatusList({ length: args?.length || Cheqd.defaultStatusList2021Length })
1273
+
1274
+ const encoded = await statusList.encode() as Bitstring
1275
+
1276
+ switch (args?.bitstringEncoding) {
1277
+ case 'base64url':
1278
+ return encoded
1279
+ case 'base64':
1280
+ return toString(fromString(encoded, 'base64url'), 'base64')
1281
+ case 'hex':
1282
+ return toString(fromString(encoded, 'base64url'), 'hex')
1283
+ default:
1284
+ return encoded
1285
+ }
1286
+ }
1287
+
1288
+ private async GenerateEncryptedStatusList2021(args: ICheqdGenerateEncryptedStatusList2021Args, context: IContext): Promise<GenerateEncryptedStatusList2021Result> {
1289
+ // validate encryptionOptions
1290
+ if (!args.encryptionOptions) {
1291
+ throw new Error('[did-provider-cheqd]: encryptionOptions is required')
1292
+ }
1293
+
1294
+ // validate encryptionOptions.accessControlConditions
1295
+ if (!args.encryptionOptions.accessControlConditions) {
1296
+ throw new Error('[did-provider-cheqd]: encryptionOptions.accessControlConditions is required')
1297
+ }
1298
+
1299
+ // generate status list
1300
+ const statusList = args?.buffer
1301
+ ? new StatusList({ buffer: args.buffer })
1302
+ : new StatusList({ length: args?.length || Cheqd.defaultStatusList2021Length })
1303
+
1304
+ // encode status list
1305
+ const encoded = await statusList.encode() as Bitstring
1306
+
1307
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1308
+ const lit = await LitProtocol.create({
1309
+ chain: args.bootstrapOptions.chain,
1310
+ litNetwork: args.bootstrapOptions.litNetwork,
1311
+ })
1312
+
1313
+ // construct access control conditions
1314
+ const unifiedAccessControlConditions = await Promise.all(args.encryptionOptions.accessControlConditions.map(async (condition) => {
1315
+ switch (condition.type) {
1316
+ case AccessControlConditionTypes.memoNonce:
1317
+ return await LitProtocol.generateCosmosAccessControlConditionTransactionMemo({
1318
+ key: '$.txs.*.body.memo',
1319
+ comparator: 'contains',
1320
+ value: condition?.specificNonce || await LitProtocol.generateTxNonce(condition?.nonceFormat)
1321
+ },
1322
+ condition.amountObserved,
1323
+ condition.senderAddressObserved,
1324
+ condition.recipientAddressObserved,
1325
+ args.bootstrapOptions.chain
1326
+ )
1327
+ case AccessControlConditionTypes.balance:
1328
+ return await LitProtocol.generateCosmosAccessControlConditionBalance({
1329
+ key: '$.balances[0].amount',
1330
+ comparator: condition.comparator,
1331
+ value: condition.amountObserved
1332
+ },
1333
+ args.bootstrapOptions.chain,
1334
+ condition.addressObserved
1335
+ )
1336
+ default:
1337
+ throw new Error(`[did-provider-cheqd]: accessControlCondition type is not supported`)
1338
+ }
1339
+ }))
1340
+
1341
+ // encrypt data
1342
+ const { encryptedString, encryptedSymmetricKey } = await lit.encrypt(encoded, unifiedAccessControlConditions)
1343
+
1344
+ // return result
1345
+ return {
1346
+ encryptedStatusList2021: await blobToHexString(encryptedString),
1347
+ encryptedSymmetricKey,
1348
+ unifiedAccessControlConditions
1349
+ } satisfies GenerateEncryptedStatusList2021Result
1350
+ }
1351
+
1352
+ private async IssueRevocableCredentialWithStatusList2021(args: ICheqdIssueRevocableCredentialWithStatusList2021Args, context: IContext): Promise<VerifiableCredential> {
1353
+ // generate index
1354
+ const statusListIndex = args.statusOptions.statusListIndex || await randomFromRange(args.statusOptions.statusListRangeStart || 0, (args.statusOptions.statusListRangeEnd || Cheqd.defaultStatusList2021Length) - 1, args.statusOptions.indexNotIn || [])
1355
+
1356
+ // construct issuer
1357
+ const issuer = ((args.issuanceOptions.credential.issuer as { id: string }).id)
1358
+ ? (args.issuanceOptions.credential.issuer as { id: string }).id
1359
+ : args.issuanceOptions.credential.issuer as string
1360
+
1361
+ // generate status list credential
1362
+ const statusListCredential = `${resolverUrl}${issuer}?resourceName=${args.statusOptions.statusListName}`
1363
+
1364
+ // construct credential status
1365
+ const credentialStatus = {
1366
+ id: `${statusListCredential}#${statusListIndex}`,
1367
+ type: 'StatusList2021Entry',
1368
+ statusPurpose: 'revocation',
1369
+ statusListIndex: `${statusListIndex}`,
1370
+ statusListCredential,
1371
+ }
1372
+
1373
+ // add credential status to credential
1374
+ args.issuanceOptions.credential.credentialStatus = credentialStatus
1375
+
1376
+ // add relevant context
1377
+ args.issuanceOptions.credential['@context'] = function() {
1378
+ // if no context is provided, add default context
1379
+ if (!args.issuanceOptions.credential['@context']) {
1380
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context]
1381
+ }
1382
+
1383
+ // if context is provided as an array, add default context if it is not already present
1384
+ if (Array.isArray(args.issuanceOptions.credential['@context'])) {
1385
+ if (args.issuanceOptions.credential['@context'].length === 0) {
1386
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context]
1387
+ }
1388
+
1389
+ if (!args.issuanceOptions.credential['@context'].includes(Cheqd.statusList2021Context)) {
1390
+ return [...args.issuanceOptions.credential['@context'], Cheqd.statusList2021Context]
1391
+ }
1392
+ }
1393
+
1394
+ // if context is provided as a string, add default context if it is not already present
1395
+ if (typeof args.issuanceOptions.credential['@context'] === 'string') return [Cheqd.defaultContextV1, Cheqd.statusList2021Context]
1396
+ }()
1397
+
1398
+ // create a credential
1399
+ const credential = await context.agent.createVerifiableCredential(args.issuanceOptions)
1400
+
1401
+ return credential
1402
+ }
1403
+
1404
+ private async IssueSuspendableCredentialWithStatusList2021(args: ICheqdIssueSuspendableCredentialWithStatusList2021Args, context: IContext): Promise<VerifiableCredential> {
1405
+ // generate index
1406
+ const statusListIndex = args.statusOptions.statusListIndex || await randomFromRange(args.statusOptions.statusListRangeStart || 0, (args.statusOptions.statusListRangeEnd || Cheqd.defaultStatusList2021Length) - 1, args.statusOptions.indexNotIn || [])
1407
+
1408
+ // construct issuer
1409
+ const issuer = ((args.issuanceOptions.credential.issuer as { id: string }).id)
1410
+ ? (args.issuanceOptions.credential.issuer as { id: string }).id
1411
+ : args.issuanceOptions.credential.issuer as string
1412
+
1413
+ // generate status list credential
1414
+ const statusListCredential = `${resolverUrl}${issuer}?resourceName=${args.statusOptions.statusListName}`
1415
+
1416
+ // construct credential status
1417
+ const credentialStatus = {
1418
+ id: `${statusListCredential}#${statusListIndex}`,
1419
+ type: 'StatusList2021Entry',
1420
+ statusPurpose: 'suspension',
1421
+ statusListIndex: `${statusListIndex}`,
1422
+ statusListCredential,
1423
+ }
1424
+
1425
+ // add credential status to credential
1426
+ args.issuanceOptions.credential.credentialStatus = credentialStatus
1427
+
1428
+ // add relevant context
1429
+ args.issuanceOptions.credential['@context'] = function() {
1430
+ // if no context is provided, add default context
1431
+ if (!args.issuanceOptions.credential['@context']) {
1432
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context]
1433
+ }
1434
+
1435
+ // if context is provided as an array, add default context if it is not already present
1436
+ if (Array.isArray(args.issuanceOptions.credential['@context'])) {
1437
+ if (args.issuanceOptions.credential['@context'].length === 0) {
1438
+ return [Cheqd.defaultContextV1, Cheqd.statusList2021Context]
1439
+ }
1440
+
1441
+ if (!args.issuanceOptions.credential['@context'].includes(Cheqd.statusList2021Context)) {
1442
+ return [...args.issuanceOptions.credential['@context'], Cheqd.statusList2021Context]
1443
+ }
1444
+ }
1445
+
1446
+ // if context is provided as a string, add default context if it is not already present
1447
+ if (typeof args.issuanceOptions.credential['@context'] === 'string') return [Cheqd.defaultContextV1, Cheqd.statusList2021Context]
1448
+ }()
1449
+
1450
+ // create a credential
1451
+ const credential = await context.agent.createVerifiableCredential(args.issuanceOptions)
1452
+
1453
+ return credential
1454
+ }
1455
+
1456
+ private async VerifyCredentialWithStatusList2021(args: ICheqdVerifyCredentialWithStatusList2021Args, context: IContext): Promise<VerificationResult> {
1457
+ // verify default policies
1458
+ const verificationResult = await context.agent.verifyCredential({
1459
+ credential: args.credential,
1460
+ policies: {
1461
+ credentialStatus: false
1462
+ }
1463
+ } satisfies IVerifyCredentialArgs)
1464
+
1465
+ // early return if verification failed
1466
+ if (!verificationResult.verified) {
1467
+ return { verified: false, error: verificationResult.error }
1468
+ }
1469
+
1470
+ // verify credential status
1471
+ switch (args.credential.credentialStatus?.statusPurpose) {
1472
+ case 'revocation':
1473
+ if (await Cheqd.checkRevoked(args.credential, { ...args.options, topArgs: args })) return { verified: false, revoked: true }
1474
+ return { verified: true, revoked: false }
1475
+ case 'suspension':
1476
+ if (await Cheqd.checkSuspended(args.credential, { ...args.options, topArgs: args })) return { verified: false, suspended: true }
1477
+ return { verified: true, suspended: false }
1478
+ default:
1479
+ throw new Error(`[did-provider-cheqd]: verify credential: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`)
1480
+ }
1481
+ }
1482
+
1483
+ private async VerifyPresentationWithStatusList2021(args: ICheqdVerifyPresentationWithStatusList2021Args, context: IContext): Promise<VerificationResult> {
1484
+ // verify default policies
1485
+ const verificationResult = await context.agent.verifyPresentation({
1486
+ presentation: args.presentation,
1487
+ policies: {
1488
+ credentialStatus: false
1489
+ }
1490
+ } satisfies IVerifyPresentationArgs)
1491
+
1492
+ // early return if verification failed
1493
+ if (!verificationResult.verified) {
1494
+ return { verified: false, error: verificationResult.error }
1495
+ }
1496
+
1497
+ if (!args.presentation.verifiableCredential) throw new Error('[did-provider-cheqd]: verify presentation: presentation.verifiableCredential is required')
1498
+
1499
+ // verify credential(s) status(es)
1500
+ for (let credential of args.presentation.verifiableCredential) {
1501
+ // if jwt credential, decode it
1502
+ if (typeof credential === 'string') {
1503
+ const decodedCredential = decodeJWT(credential)
1504
+
1505
+ // validate credential payload
1506
+ if (!decodedCredential.payload) throw new Error('[did-provider-cheqd]: verify presentation: decodedCredential.payload is required')
1507
+
1508
+ // validate credential payload ref as VerifiableCredential
1509
+ if (!decodedCredential.payload.vc) throw new Error('[did-provider-cheqd]: verify presentation: decodedCredential.payload.vc is required')
1510
+
1511
+ credential = decodedCredential.payload.vc as VerifiableCredential
1512
+ }
1513
+
1514
+ switch (credential.credentialStatus?.statusPurpose) {
1515
+ case 'revocation':
1516
+ if (await Cheqd.checkRevoked(credential, { ...args.options, topArgs: args })) return { verified: false, revoked: true }
1517
+ break
1518
+ case 'suspension':
1519
+ if (await Cheqd.checkSuspended(credential, { ...args.options, topArgs: args })) return { verified: false, suspended: true }
1520
+ break
1521
+ default:
1522
+ throw new Error(`[did-provider-cheqd]: verify presentation: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`)
1523
+ }
1524
+ }
1525
+
1526
+ return { verified: true }
1527
+ }
1528
+
1529
+ private async CheckCredentialStatusWithStatusList2021(args: ICheqdCheckCredentialStatusWithStatusList2021Args, context: IContext): Promise<StatusCheckResult> {
1530
+ switch (args.credential.credentialStatus?.statusPurpose) {
1531
+ case 'revocation':
1532
+ if (await Cheqd.checkRevoked(args.credential, { ...args.options, topArgs: args })) return { revoked: true }
1533
+ return { revoked: false }
1534
+ case 'suspension':
1535
+ if (await Cheqd.checkSuspended(args.credential, { ...args.options, topArgs: args })) return { suspended: true }
1536
+ return { suspended: false }
1537
+ default:
1538
+ throw new Error(`[did-provider-cheqd]: check status: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`)
1539
+ }
1540
+ }
1541
+
1542
+ private async RevokeCredentialWithStatusList2021(args: ICheqdRevokeCredentialWithStatusList2021Args, context: IContext): Promise<RevocationResult> {
1543
+ // validate status purpose
1544
+ if (args.credential.credentialStatus?.statusPurpose !== 'revocation') {
1545
+ throw new Error(`[did-provider-cheqd]: revocation: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`)
1546
+ }
1547
+
1548
+ // validate args in pairs - case: statusListFile and statusList
1549
+ if (args.options?.statusListFile && args.options?.statusList) {
1550
+ throw new Error('[did-provider-cheqd]: revocation: statusListFile and statusList are mutually exclusive')
1551
+ }
1552
+
1553
+ // validate args in pairs - case: statusListFile and fetchList
1554
+ if (args.options?.statusListFile && args.options?.fetchList) {
1555
+ throw new Error('[did-provider-cheqd]: revocation: statusListFile and fetchList are mutually exclusive')
1556
+ }
1557
+
1558
+ // validate args in pairs - case: statusList and fetchList
1559
+ if (args.options?.statusList && args.options?.fetchList) {
1560
+ throw new Error('[did-provider-cheqd]: revocation: statusList and fetchList are mutually exclusive')
1561
+ }
1562
+
1563
+ // validate args in pairs - case: publish
1564
+ if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
1565
+ throw new Error('[did-provider-cheqd]: revocation: publish requires statusListFile or statusList, if fetchList is disabled')
1566
+ }
1567
+
1568
+ // revoke credential
1569
+ return await Cheqd.revokeCredential(args.credential, {
1570
+ ...args.options,
1571
+ topArgs: args,
1572
+ publishOptions: {
1573
+ context,
1574
+ resourceId: args?.options?.resourceId,
1575
+ resourceVersion: args?.options?.resourceVersion,
1576
+ signInputs: args?.options?.signInputs,
1577
+ fee: args?.options?.fee
1578
+ }
1579
+ })
1580
+ }
376
1581
 
377
- return {
378
- didDoc: createDidPayload(verificationMethods, [verificationKeys]),
379
- versionId: v4(),
380
- keys: [
381
- {
382
- publicKeyHex: keyPairHex.publicKey,
383
- privateKeyHex: keyPairHex.privateKey,
384
- kid: keyPairHex.publicKey,
385
- type: 'Ed25519'
386
- }
387
- ]
1582
+ private async RevokeBulkCredentialsWithStatusList2021(args: ICheqdRevokeBulkCredentialsWithStatusList2021Args, context: IContext): Promise<RevocationResult[]> {
1583
+ // TODO: implement
1584
+ throw new Error('[did-provider-cheqd]: revocation: bulk revocation is not implemented yet')
1585
+ }
1586
+
1587
+ private async SuspendCredentialWithStatusList2021(args: ICheqdSuspendCredentialWithStatusList2021Args, context: IContext): Promise<SuspensionResult> {
1588
+ // validate status purpose
1589
+ if (args.credential.credentialStatus?.statusPurpose !== 'suspension') {
1590
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`)
1591
+ }
1592
+
1593
+ // validate args in pairs - case: statusListFile and statusList
1594
+ if (args.options?.statusListFile && args.options?.statusList) {
1595
+ throw new Error('[did-provider-cheqd]: suspension: statusListFile and statusList are mutually exclusive')
388
1596
  }
1597
+
1598
+ // validate args in pairs - case: statusListFile and fetchList
1599
+ if (args.options?.statusListFile && args.options?.fetchList) {
1600
+ throw new Error('[did-provider-cheqd]: suspension: statusListFile and fetchList are mutually exclusive')
1601
+ }
1602
+
1603
+ // validate args in pairs - case: statusList and fetchList
1604
+ if (args.options?.statusList && args.options?.fetchList) {
1605
+ throw new Error('[did-provider-cheqd]: suspension: statusList and fetchList are mutually exclusive')
1606
+ }
1607
+
1608
+ // validate args in pairs - case: publish
1609
+ if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
1610
+ throw new Error('[did-provider-cheqd]: suspension: publish requires statusListFile or statusList, if fetchList is disabled')
1611
+ }
1612
+
1613
+ // suspend credential
1614
+ return await Cheqd.suspendCredential(args.credential, {
1615
+ ...args.options,
1616
+ topArgs: args,
1617
+ publishOptions: {
1618
+ context,
1619
+ resourceId: args?.options?.resourceId,
1620
+ resourceVersion: args?.options?.resourceVersion,
1621
+ signInputs: args?.options?.signInputs,
1622
+ fee: args?.options?.fee
1623
+ }
1624
+ })
389
1625
  }
390
1626
 
391
- private async GenerateDidDocWithLinkedResource(args: any, context: IContext): Promise<TExportedDIDDocWithLinkedResourceWithKeys> {
392
- if (typeof args.verificationMethod !== 'string') {
393
- throw new Error('[did-provider-cheqd]: verificationMethod is required')
1627
+ private async SuspendBulkCredentialsWithStatusList2021(args: ICheqdSuspendBulkCredentialsWithStatusList2021Args, context: IContext): Promise<SuspensionResult[]> {
1628
+ // TODO: implement
1629
+ throw new Error('[did-provider-cheqd]: suspension: bulk suspension is not implemented yet')
1630
+ }
1631
+
1632
+ private async UnsuspendCredentialWithStatusList2021(args: ICheqdUnsuspendCredentialWithStatusList2021Args, context: IContext): Promise<UnsuspensionResult> {
1633
+ // validate status purpose
1634
+ if (args.credential.credentialStatus?.statusPurpose !== 'suspension') {
1635
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${args.credential.credentialStatus?.statusPurpose}`)
394
1636
  }
395
1637
 
396
- if (typeof args.methodSpecificIdAlgo !== 'string') {
397
- throw new Error('[did-provider-cheqd]: methodSpecificIdAlgo is required')
1638
+ // validate args in pairs - case: statusListFile and statusList
1639
+ if (args.options?.statusListFile && args.options?.statusList) {
1640
+ throw new Error('[did-provider-cheqd]: suspension: statusListFile and statusList are mutually exclusive')
398
1641
  }
399
1642
 
400
- if (typeof args.network !== 'string') {
401
- throw new Error('[did-provider-cheqd]: network is required')
1643
+ // validate args in pairs - case: statusListFile and fetchList
1644
+ if (args.options?.statusListFile && args.options?.fetchList) {
1645
+ throw new Error('[did-provider-cheqd]: suspension: statusListFile and fetchList are mutually exclusive')
402
1646
  }
403
1647
 
404
- const keyPair = createKeyPairBase64()
405
- const keyPairHex: IKeyPair = { publicKey: toString(fromString(keyPair.publicKey, 'base64'), 'hex'), privateKey: toString(fromString(keyPair.privateKey, 'base64'), 'hex') }
406
- const verificationKeys = createVerificationKeys(keyPair.publicKey, args.methodSpecificIdAlgo, 'key-1', args.network)
407
- const verificationMethods = createDidVerificationMethod([args.verificationMethod], [verificationKeys])
408
- const payload = createDidPayload(verificationMethods, [verificationKeys])
1648
+ // validate args in pairs - case: statusList and fetchList
1649
+ if (args.options?.statusList && args.options?.fetchList) {
1650
+ throw new Error('[did-provider-cheqd]: suspension: statusList and fetchList are mutually exclusive')
1651
+ }
409
1652
 
410
- return {
411
- didDoc: payload,
412
- versionId: v4(),
413
- keys: [
414
- {
415
- publicKeyHex: keyPairHex.publicKey,
416
- privateKeyHex: keyPairHex.privateKey,
417
- kid: keyPairHex.publicKey,
418
- type: 'Ed25519'
1653
+ // validate args in pairs - case: publish
1654
+ if (args.options?.publish && !args.fetchList && !(args.options?.statusListFile || args.options?.statusList)) {
1655
+ throw new Error('[did-provider-cheqd]: suspension: publish requires statusListFile or statusList, if fetchList is disabled')
1656
+ }
1657
+
1658
+ // suspend credential
1659
+ return await Cheqd.unsuspendCredential(args.credential, {
1660
+ ...args.options,
1661
+ topArgs: args,
1662
+ publishOptions: {
1663
+ context,
1664
+ resourceId: args?.options?.resourceId,
1665
+ resourceVersion: args?.options?.resourceVersion,
1666
+ signInputs: args?.options?.signInputs,
1667
+ fee: args?.options?.fee
1668
+ }
1669
+ })
1670
+ }
1671
+
1672
+ private async UnsuspendBulkCredentialsWithStatusList2021(args: ICheqdUnsuspendBulkCredentialsWithStatusList2021Args, context: IContext): Promise<UnsuspensionResult[]> {
1673
+ // TODO: implement
1674
+ throw new Error('[did-provider-cheqd]: suspension: bulk unsuspension is not implemented yet')
1675
+ }
1676
+
1677
+ private async TransactVerifierPaysIssuer(args: ICheqdTransactVerifierPaysIssuerArgs, context: IContext): Promise<TransactionResult> {
1678
+ try {
1679
+ // delegate to provider
1680
+ const transactionResult = await this.didProvider.transactSendTokens({
1681
+ recipientAddress: args.recipientAddress,
1682
+ amount: args.amount,
1683
+ memoNonce: args.memoNonce,
1684
+ txBytes: args.txBytes,
1685
+ })
1686
+
1687
+ // return transaction result
1688
+ return {
1689
+ successful: !transactionResult.code,
1690
+ transactionHash: transactionResult.transactionHash,
1691
+ events: transactionResult.events,
1692
+ rawLog: transactionResult.rawLog,
1693
+ txResponse: args?.returnTxResponse ? transactionResult : undefined
1694
+ } satisfies TransactionResult
1695
+ } catch (error) {
1696
+ // return error
1697
+ return {
1698
+ successful: false,
1699
+ error: error as IError
1700
+ } satisfies TransactionResult
1701
+ }
1702
+ }
1703
+
1704
+ private async ObserveVerifierPaysIssuer(args: ICheqdObserveVerifierPaysIssuerArgs, context: IContext): Promise<ObservationResult> {
1705
+ // verify with raw unified access control conditions, if any
1706
+ if (args?.unifiedAccessControlCondition) {
1707
+ try {
1708
+ // define network
1709
+ const network = (function() {
1710
+ switch (args.unifiedAccessControlCondition.chain) {
1711
+ case LitCompatibleCosmosChains.cheqdMainnet:
1712
+ return CheqdNetwork.Mainnet
1713
+ case LitCompatibleCosmosChains.cheqdTestnet:
1714
+ return CheqdNetwork.Testnet
1715
+ default:
1716
+ throw new Error(`[did-provider-cheqd]: observe: Unsupported chain: ${args.unifiedAccessControlCondition.chain}`)
1717
+ }
1718
+ }())
1719
+
1720
+ // construct url
1721
+ const url = `${DefaultRESTUrls[network]}${args.unifiedAccessControlCondition.path}`
1722
+
1723
+ // fetch relevant txs
1724
+ const txs = await (await fetch(url)).json() as ShallowTypedTxsResponse
1725
+
1726
+ // skim through txs for relevant events, in which case memoNonce is present and strict equals to the one provided
1727
+ const meetsConditionTxIndex = txs?.txs?.findIndex(tx => unescapeUnicode(tx.body.memo) === unescapeUnicode(args.unifiedAccessControlCondition!.returnValueTest.value))
1728
+
1729
+ // define meetsCondition
1730
+ const meetsCondition = (typeof meetsConditionTxIndex !== 'undefined' && meetsConditionTxIndex !== -1)
1731
+
1732
+ // return observation result
1733
+ return {
1734
+ subscribed: true,
1735
+ meetsCondition: meetsCondition,
1736
+ transactionHash: meetsCondition ? txs!.tx_responses[meetsConditionTxIndex].txhash : undefined,
1737
+ events: meetsCondition ? txs!.tx_responses[meetsConditionTxIndex].events : undefined,
1738
+ rawLog: meetsCondition ? txs!.tx_responses[meetsConditionTxIndex].raw_log : undefined,
1739
+ txResponse: meetsCondition ? (args?.returnTxResponse ? txs!.tx_responses[meetsConditionTxIndex] : undefined) : undefined
1740
+ } satisfies ObservationResult
1741
+ } catch (error) {
1742
+ // return error
1743
+ return {
1744
+ subscribed: false,
1745
+ meetsCondition: false,
1746
+ error: error as IError
1747
+ } satisfies ObservationResult
1748
+ }
1749
+ }
1750
+
1751
+ // validate access control conditions components - case: senderAddress
1752
+ if (!args.senderAddress) {
1753
+ throw new Error('[did-provider-cheqd]: observation: senderAddress is required')
1754
+ }
1755
+
1756
+ // validate access control conditions components - case: recipientAddress
1757
+ if (!args.recipientAddress) {
1758
+ throw new Error('[did-provider-cheqd]: observation: recipientAddress is required')
1759
+ }
1760
+
1761
+ // validate access control conditions components - case: amount
1762
+ if (!args.amount || !args.amount.amount || !args.amount.denom || args.amount.denom !== 'ncheq') {
1763
+ 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`')
1764
+ }
1765
+
1766
+ // validate access control conditions components - case: memoNonce
1767
+ if (!args.memoNonce) {
1768
+ throw new Error('[did-provider-cheqd]: observation: memoNonce is required')
1769
+ }
1770
+
1771
+ // validate access control conditions components - case: network
1772
+ if (!args.network) {
1773
+ throw new Error('[did-provider-cheqd]: observation: network is required')
1774
+ }
1775
+
1776
+ try {
1777
+ // otherwise, construct url, as per components
1778
+ 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}'`
1779
+
1780
+ // fetch relevant txs
1781
+ const txs = await (await fetch(url)).json() as ShallowTypedTxsResponse
1782
+
1783
+ // skim through txs for relevant events, in which case memoNonce is present and strict equals to the one provided
1784
+ const meetsConditionTxIndex = txs?.txs?.findIndex(tx => unescapeUnicode(tx.body.memo) === unescapeUnicode(args.memoNonce))
1785
+
1786
+ // define meetsCondition
1787
+ const meetsCondition = (typeof meetsConditionTxIndex !== 'undefined' && meetsConditionTxIndex !== -1)
1788
+
1789
+ // return observation result
1790
+ return {
1791
+ subscribed: true,
1792
+ meetsCondition: meetsCondition,
1793
+ transactionHash: meetsCondition ? txs!.tx_responses[meetsConditionTxIndex].txhash : undefined,
1794
+ events: meetsCondition ? txs!.tx_responses[meetsConditionTxIndex].events : undefined,
1795
+ rawLog: meetsCondition ? txs!.tx_responses[meetsConditionTxIndex].raw_log : undefined,
1796
+ txResponse: meetsCondition ? (args?.returnTxResponse ? txs!.tx_responses[meetsConditionTxIndex] : undefined) : undefined
1797
+ } satisfies ObservationResult
1798
+ } catch (error) {
1799
+ // return error
1800
+ return {
1801
+ subscribed: false,
1802
+ meetsCondition: false,
1803
+ error: error as IError
1804
+ } satisfies ObservationResult
1805
+ }
1806
+ }
1807
+
1808
+ static async revokeCredential(credential: VerifiableCredential, options?: ICheqdStatusList2021Options): Promise<RevocationResult> {
1809
+ try {
1810
+ // validate status purpose
1811
+ if (credential?.credentialStatus?.statusPurpose !== 'revocation') throw new Error('[did-provider-cheqd]: revocation: Invalid status purpose')
1812
+
1813
+ // fetch status list 2021 metadata
1814
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential))
1815
+
1816
+ // detect if encrypted
1817
+ const isEncrypted = function() {
1818
+ switch (metadata.mediaType) {
1819
+ case 'application/octet-stream':
1820
+ return true
1821
+ case 'application/gzip':
1822
+ return false
1823
+ default:
1824
+ throw new Error(`[did-provider-cheqd]: revocation: Unsupported media type: ${metadata.mediaType}`)
419
1825
  }
420
- ],
421
- linkedResource: {
422
- id: v4(),
423
- collectionId: payload.id.split(':').reverse()[0],
424
- name: 'sample json resource',
425
- version: '1.0.0',
426
- resourceType: 'SampleResource',
427
- alsoKnownAs: [],
428
- data: toString(new TextEncoder().encode(
429
- JSON.stringify({ sample: 'json' })
430
- ), 'base64'),
1826
+ }()
1827
+
1828
+ // early return, if encrypted and no decryption key provided
1829
+ if (isEncrypted && !options?.topArgs?.symmetricKey) throw new Error('[did-provider-cheqd]: revocation: symmetricKey is required, if status list 2021 is encrypted')
1830
+
1831
+ // fetch status list 2021 inscribed in credential
1832
+ const statusList2021 = options?.topArgs?.fetchList
1833
+ ? (await async function () {
1834
+ // if not encrypted, return bitstring
1835
+ if (!isEncrypted) return await Cheqd.fetchStatusList2021(credential)
1836
+
1837
+ // otherwise, decrypt and return bitstring
1838
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true) as Uint8Array)
1839
+
1840
+ // decrypt
1841
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'))
1842
+ }())
1843
+ : (await async function () {
1844
+ // if status list 2021 is not fetched, read from file
1845
+ if (options?.statusListFile) {
1846
+ // if not encrypted, return bitstring
1847
+ if (!isEncrypted) return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode()
1848
+
1849
+ // otherwise, decrypt and return bitstring
1850
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile))
1851
+
1852
+ // decrypt
1853
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'))
1854
+ }
1855
+
1856
+ if (!options?.statusListInlineBitstring) throw new Error('[did-provider-cheqd]: revocation: statusListInlineBitstring is required, if statusListFile is not provided')
1857
+
1858
+ // otherwise, read from inline bitstring
1859
+ return options?.statusListInlineBitstring
1860
+ }())
1861
+
1862
+ // parse status list 2021
1863
+ const statusList = await StatusList.decode({ encodedList: statusList2021 })
1864
+
1865
+ // early exit, if credential is already revoked
1866
+ if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex))) return { revoked: false }
1867
+
1868
+ // update revocation status
1869
+ statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true)
1870
+
1871
+ // set in-memory status list ref
1872
+ const bitstring = await statusList.encode() as Bitstring
1873
+
1874
+ // cast top-level args
1875
+ const topArgs = options?.topArgs as ICheqdRevokeCredentialWithStatusList2021Args
1876
+
1877
+ // write status list 2021 to file, if provided
1878
+ if (topArgs?.writeToFile) {
1879
+ await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile)
431
1880
  }
1881
+
1882
+ // publish status list 2021, if provided
1883
+ const published = topArgs?.publish
1884
+ ? (await async function () {
1885
+ // fetch status list 2021 metadata
1886
+ const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential)
1887
+
1888
+ // publish status list 2021 as new version
1889
+ const scoped = topArgs.publishEncrypted
1890
+ ? (await async function () {
1891
+ // instantiate dkg-threshold client, in which case lit-protocol is used
1892
+ const lit = await LitProtocol.create({
1893
+ chain: options?.topArgs?.bootstrapOptions?.chain,
1894
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
1895
+ })
1896
+
1897
+ // encrypt
1898
+ const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true)
1899
+
1900
+ // return tuple of publish result and encryption relevant metadata
1901
+ return [
1902
+ await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
1903
+ { encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey!, 'hex') }
1904
+ ]
1905
+ }())
1906
+ : [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined]
1907
+
1908
+ // early exit, if publish failed
1909
+ if (!scoped[0]) throw new Error('[did-provider-cheqd]: revocation: Failed to publish status list 2021')
1910
+
1911
+ // return publish result
1912
+ return scoped
1913
+ }())
1914
+ : undefined
1915
+
1916
+ return {
1917
+ revoked: true,
1918
+ published: topArgs?.publish ? true : undefined,
1919
+ statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
1920
+ encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString((published?.[1] as { encryptedString: Blob })?.encryptedString) : undefined,
1921
+ encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? (published?.[1] as { encryptedSymmetricKey: string })?.encryptedSymmetricKey : undefined,
1922
+ symmetricKey: topArgs?.returnSymmetricKey ? (published?.[1] as { symmetricKey: string })?.symmetricKey : undefined,
1923
+ resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
1924
+ } satisfies RevocationResult
1925
+ } catch (error) {
1926
+ // silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
1927
+ console.error(error)
1928
+
1929
+ return { revoked: false, error: error as IError } satisfies RevocationResult
432
1930
  }
433
1931
  }
434
1932
 
435
- private async GenerateIdentityKeys(args: any, context: IContext): Promise<TImportableEd25519Key> {
436
- const keyPair = createKeyPairHex()
437
- return {
438
- publicKeyHex: keyPair.publicKey,
439
- privateKeyHex: keyPair.privateKey,
440
- kid: keyPair.publicKey,
441
- type: 'Ed25519'
1933
+ static async suspendCredential(credential: VerifiableCredential, options?: ICheqdStatusList2021Options): Promise<SuspensionResult> {
1934
+ try {
1935
+ // validate status purpose
1936
+ if (credential?.credentialStatus?.statusPurpose !== 'suspension') throw new Error('[did-provider-cheqd]: suspension: Invalid status purpose')
1937
+
1938
+ // fetch status list 2021 metadata
1939
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential))
1940
+
1941
+ // detect if encrypted
1942
+ const isEncrypted = function() {
1943
+ switch (metadata.mediaType) {
1944
+ case 'application/octet-stream':
1945
+ return true
1946
+ case 'application/gzip':
1947
+ return false
1948
+ default:
1949
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported media type: ${metadata.mediaType}`)
1950
+ }
1951
+ }()
1952
+
1953
+ // early return, if encrypted and no decryption key provided
1954
+ if (isEncrypted && !options?.topArgs?.symmetricKey) throw new Error('[did-provider-cheqd]: suspension: symmetricKey is required, if status list 2021 is encrypted')
1955
+
1956
+ // fetch status list 2021 inscribed in credential
1957
+ const statusList2021 = options?.topArgs?.fetchList
1958
+ ? (await async function () {
1959
+ // if not encrypted, return bitstring
1960
+ if (!isEncrypted) return await Cheqd.fetchStatusList2021(credential)
1961
+
1962
+ // otherwise, decrypt and return bitstring
1963
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true) as Uint8Array)
1964
+
1965
+ // decrypt
1966
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'))
1967
+ }())
1968
+ : (await async function () {
1969
+ // if status list 2021 is not fetched, read from file
1970
+ if (options?.statusListFile) {
1971
+ // if not encrypted, return bitstring
1972
+ if (!isEncrypted) return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode()
1973
+
1974
+ // otherwise, decrypt and return bitstring
1975
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile))
1976
+
1977
+ // decrypt
1978
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'))
1979
+ }
1980
+
1981
+ if (!options?.statusListInlineBitstring) throw new Error('[did-provider-cheqd]: suspension: statusListInlineBitstring is required, if statusListFile is not provided')
1982
+
1983
+ // otherwise, read from inline bitstring
1984
+ return options?.statusListInlineBitstring
1985
+ }())
1986
+
1987
+ // parse status list 2021
1988
+ const statusList = await StatusList.decode({ encodedList: statusList2021 })
1989
+
1990
+ // early exit, if already suspended
1991
+ if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex))) return { suspended: false } satisfies SuspensionResult
1992
+
1993
+ // update suspension status
1994
+ statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true)
1995
+
1996
+ // set in-memory status list ref
1997
+ const bitstring = await statusList.encode() as Bitstring
1998
+
1999
+ // cast top-level args
2000
+ const topArgs = options?.topArgs as ICheqdSuspendCredentialWithStatusList2021Args
2001
+
2002
+ // write status list 2021 to file, if provided
2003
+ if (topArgs?.writeToFile) {
2004
+ await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile)
2005
+ }
2006
+
2007
+ // publish status list 2021, if provided
2008
+ const published = topArgs?.publish
2009
+ ? (await async function () {
2010
+ // fetch status list 2021 metadata
2011
+ const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential)
2012
+
2013
+ // publish status list 2021 as new version
2014
+ const scoped = topArgs.publishEncrypted
2015
+ ? (await async function () {
2016
+ // instantiate dkg-threshold client, in which case lit-protocol is used
2017
+ const lit = await LitProtocol.create({
2018
+ chain: options?.topArgs?.bootstrapOptions?.chain,
2019
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
2020
+ })
2021
+
2022
+ // encrypt
2023
+ const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true)
2024
+
2025
+ // return tuple of publish result and encryption relevant metadata
2026
+ return [
2027
+ await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
2028
+ { encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey!, 'hex') }
2029
+ ]
2030
+ }())
2031
+ : [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined]
2032
+
2033
+ // early exit, if publish failed
2034
+ if (!scoped[0]) throw new Error('[did-provider-cheqd]: suspension: Failed to publish status list 2021')
2035
+
2036
+ // return publish result
2037
+ return scoped
2038
+ }())
2039
+ : undefined
2040
+
2041
+ return {
2042
+ suspended: true,
2043
+ published: topArgs?.publish ? true : undefined,
2044
+ statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
2045
+ encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString((published?.[1] as { encryptedString: Blob })?.encryptedString) : undefined,
2046
+ encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? (published?.[1] as { encryptedSymmetricKey: string })?.encryptedSymmetricKey : undefined,
2047
+ symmetricKey: topArgs?.returnSymmetricKey ? (published?.[1] as { symmetricKey: string })?.symmetricKey : undefined,
2048
+ resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
2049
+ } satisfies SuspensionResult
2050
+ } catch (error) {
2051
+ // silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
2052
+ console.error(error)
2053
+
2054
+ return { suspended: false, error: error as IError } satisfies SuspensionResult
442
2055
  }
443
2056
  }
444
2057
 
445
- private async GenerateVersionId(args: any, context: IContext): Promise<string> {
446
- return v4()
2058
+ static async unsuspendCredential(credential: VerifiableCredential, options?: ICheqdStatusList2021Options): Promise<UnsuspensionResult> {
2059
+ try {
2060
+ // validate status purpose
2061
+ if (credential?.credentialStatus?.statusPurpose !== 'suspension') throw new Error('[did-provider-cheqd]: unsuspension: Invalid status purpose')
2062
+
2063
+ // fetch status list 2021 metadata
2064
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential))
2065
+
2066
+ // detect if encrypted
2067
+ const isEncrypted = function() {
2068
+ switch (metadata.mediaType) {
2069
+ case 'application/octet-stream':
2070
+ return true
2071
+ case 'application/gzip':
2072
+ return false
2073
+ default:
2074
+ throw new Error(`[did-provider-cheqd]: unsuspension: Unsupported media type: ${metadata.mediaType}`)
2075
+ }
2076
+ }()
2077
+
2078
+ // early return, if encrypted and no decryption key provided
2079
+ if (isEncrypted && !options?.topArgs?.symmetricKey) throw new Error('[did-provider-cheqd]: unsuspension: symmetricKey is required, if status list 2021 is encrypted')
2080
+
2081
+ // fetch status list 2021 inscribed in credential
2082
+ const statusList2021 = options?.topArgs?.fetchList
2083
+ ? (await async function () {
2084
+ // if not encrypted, return bitstring
2085
+ if (!isEncrypted) return await Cheqd.fetchStatusList2021(credential)
2086
+
2087
+ // otherwise, decrypt and return bitstring
2088
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true) as Uint8Array)
2089
+
2090
+ // decrypt
2091
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'))
2092
+ }())
2093
+ : (await async function () {
2094
+ // if status list 2021 is not fetched, read from file
2095
+ if (options?.statusListFile) {
2096
+ // if not encrypted, return bitstring
2097
+ if (!isEncrypted) return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode()
2098
+
2099
+ // otherwise, decrypt and return bitstring
2100
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile))
2101
+
2102
+ // decrypt
2103
+ return await LitProtocol.decryptDirect(scopedRawBlob, fromString(options?.topArgs?.symmetricKey, 'hex'))
2104
+ }
2105
+
2106
+ if (!options?.statusListInlineBitstring) throw new Error('[did-provider-cheqd]: unsuspension: statusListInlineBitstring is required, if statusListFile is not provided')
2107
+
2108
+ // otherwise, read from inline bitstring
2109
+ return options?.statusListInlineBitstring
2110
+ }())
2111
+
2112
+ // parse status list 2021
2113
+ const statusList = await StatusList.decode({ encodedList: statusList2021 })
2114
+
2115
+ // early exit, if already suspended
2116
+ if (statusList.getStatus(Number(credential.credentialStatus.statusListIndex))) return { unsuspended: false } satisfies UnsuspensionResult
2117
+
2118
+ // update suspension status
2119
+ statusList.setStatus(Number(credential.credentialStatus.statusListIndex), true)
2120
+
2121
+ // set in-memory status list ref
2122
+ const bitstring = await statusList.encode() as Bitstring
2123
+
2124
+ // cast top-level args
2125
+ const topArgs = options?.topArgs as ICheqdSuspendCredentialWithStatusList2021Args
2126
+
2127
+ // write status list 2021 to file, if provided
2128
+ if (topArgs?.writeToFile) {
2129
+ await Cheqd.writeFile(fromString(bitstring, 'base64url'), options?.statusListFile)
2130
+ }
2131
+
2132
+ // publish status list 2021, if provided
2133
+ const published = topArgs?.publish
2134
+ ? (await async function () {
2135
+ // fetch status list 2021 metadata
2136
+ const statusListMetadata = await Cheqd.fetchStatusList2021Metadata(credential)
2137
+
2138
+ // publish status list 2021 as new version
2139
+ const scoped = topArgs.publishEncrypted
2140
+ ? (await async function () {
2141
+ // instantiate dkg-threshold client, in which case lit-protocol is used
2142
+ const lit = await LitProtocol.create({
2143
+ chain: options?.topArgs?.bootstrapOptions?.chain,
2144
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
2145
+ })
2146
+
2147
+ // encrypt
2148
+ const { encryptedString, encryptedSymmetricKey, symmetricKey } = await lit.encrypt(bitstring, options?.topArgs?.encryptionOptions?.unifiedAccessControlConditions, true)
2149
+
2150
+ // return tuple of publish result and encryption relevant metadata
2151
+ return [
2152
+ await Cheqd.publishStatusList2021(new Uint8Array(await encryptedString.arrayBuffer()), statusListMetadata, options?.publishOptions),
2153
+ { encryptedString, encryptedSymmetricKey, symmetricKey: toString(symmetricKey!, 'hex') }
2154
+ ]
2155
+ }())
2156
+ : [await Cheqd.publishStatusList2021(fromString(bitstring, 'base64url'), statusListMetadata, options?.publishOptions), undefined]
2157
+
2158
+ // early exit, if publish failed
2159
+ if (!scoped[0]) throw new Error('[did-provider-cheqd]: unsuspension: Failed to publish status list 2021')
2160
+
2161
+ // return publish result
2162
+ return scoped
2163
+ }())
2164
+ : undefined
2165
+
2166
+ return {
2167
+ unsuspended: true,
2168
+ published: topArgs?.publish ? true : undefined,
2169
+ statusList: topArgs?.returnUpdatedStatusList ? bitstring : undefined,
2170
+ encryptedStatusList: topArgs?.returnUpdatedEncryptedStatusList ? await blobToHexString((published?.[1] as { encryptedString: Blob })?.encryptedString) : undefined,
2171
+ encryptedSymmetricKey: topArgs?.returnEncryptedSymmetricKey ? (published?.[1] as { encryptedSymmetricKey: string })?.encryptedSymmetricKey : undefined,
2172
+ symmetricKey: topArgs?.returnSymmetricKey ? (published?.[1] as { symmetricKey: string })?.symmetricKey : undefined,
2173
+ resourceMetadata: topArgs?.returnStatusListMetadata ? await Cheqd.fetchStatusList2021Metadata(credential) : undefined
2174
+ } satisfies UnsuspensionResult
2175
+ } catch (error) {
2176
+ // silent fail + early exit, optimised for parallelisation, use with Promise.allSettled
2177
+ console.error(error)
2178
+
2179
+ return { unsuspended: false, error: error as IError } satisfies UnsuspensionResult
2180
+ }
2181
+ }
2182
+
2183
+ static async checkRevoked(credential: VerifiableCredential, options: ICheqdStatusList2021Options = { fetchList: true }): Promise<boolean> {
2184
+ // validate status purpose
2185
+ if (credential.credentialStatus?.statusPurpose !== 'revocation') {
2186
+ throw new Error(`[did-provider-cheqd]: revocation: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`)
2187
+ }
2188
+
2189
+ // fetch status list 2021 metadata
2190
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential))
2191
+
2192
+ // detect if encrypted
2193
+ const isEncrypted = function() {
2194
+ switch (metadata.mediaType) {
2195
+ case 'application/octet-stream':
2196
+ return true
2197
+ case 'application/gzip':
2198
+ return false
2199
+ default:
2200
+ throw new Error(`[did-provider-cheqd]: revocation: Unsupported media type: ${metadata.mediaType}`)
2201
+ }
2202
+ }()
2203
+
2204
+ // early return, if encrypted and decryption key is not provided
2205
+ if (isEncrypted && !options?.topArgs?.encryptedSymmetricKey) throw new Error('[did-provider-cheqd]: revocation: encryptedSymmetricKey is required, if status list 2021 is encrypted')
2206
+
2207
+ // fetch status list 2021 inscribed in credential
2208
+ const statusList2021 = options?.topArgs?.fetchList
2209
+ ? (await async function () {
2210
+ // if not encrypted, return bitstring
2211
+ if (!isEncrypted) return await Cheqd.fetchStatusList2021(credential)
2212
+
2213
+ // otherwise, decrypt and return bitstring
2214
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true) as Uint8Array)
2215
+
2216
+ // instantiate dkg-threshold client, in which case lit-protocol is used
2217
+ const lit = await LitProtocol.create({
2218
+ chain: options?.topArgs?.bootstrapOptions?.chain,
2219
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
2220
+ })
2221
+
2222
+ // decrypt
2223
+ return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions)
2224
+ }())
2225
+ : (await async function () {
2226
+ // if status list 2021 is not fetched, read from file
2227
+ if (options?.statusListFile) {
2228
+ // if not encrypted, return bitstring
2229
+ if (!isEncrypted) return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode()
2230
+
2231
+ // otherwise, decrypt and return bitstring
2232
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile))
2233
+
2234
+ // instantiate dkg-threshold client, in which case lit-protocol is used
2235
+ const lit = await LitProtocol.create({
2236
+ chain: options?.topArgs?.bootstrapOptions?.chain,
2237
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
2238
+ })
2239
+
2240
+ // decrypt
2241
+ return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions)
2242
+ }
2243
+
2244
+ if (!options?.statusListInlineBitstring) throw new Error(' [did-provider-cheqd]: revocation: statusListInlineBitstring is required, if statusListFile is not provided')
2245
+
2246
+ // otherwise, read from inline bitstring
2247
+ return options?.statusListInlineBitstring
2248
+ }())
2249
+
2250
+ // parse status list 2021
2251
+ const statusList = await StatusList.decode({ encodedList: statusList2021 })
2252
+
2253
+ // get status by index
2254
+ return !!statusList.getStatus(Number(credential.credentialStatus.statusListIndex))
2255
+ }
2256
+
2257
+ static async checkSuspended(credential: VerifiableCredential, options: ICheqdStatusList2021Options = { fetchList: true }): Promise<boolean> {
2258
+ // validate status purpose
2259
+ if (credential.credentialStatus?.statusPurpose !== 'suspension') {
2260
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported status purpose: ${credential.credentialStatus?.statusPurpose}`)
2261
+ }
2262
+
2263
+ // fetch status list 2021 metadata
2264
+ const metadata = (await Cheqd.fetchStatusList2021Metadata(credential))
2265
+
2266
+ // detect if encrypted
2267
+ const isEncrypted = function() {
2268
+ switch (metadata.mediaType) {
2269
+ case 'application/octet-stream':
2270
+ return true
2271
+ case 'application/gzip':
2272
+ return false
2273
+ default:
2274
+ throw new Error(`[did-provider-cheqd]: suspension: Unsupported media type: ${metadata.mediaType}`)
2275
+ }
2276
+ }()
2277
+
2278
+ // early return, if encrypted and decryption key is not provided
2279
+ if (isEncrypted && !options?.topArgs?.encryptedSymmetricKey) throw new Error('[did-provider-cheqd]: suspension: encryptedSymmetricKey is required, if status list 2021 is encrypted')
2280
+
2281
+ // fetch status list 2021 inscribed in credential
2282
+ const statusList2021 = options?.topArgs?.fetchList
2283
+ ? (await async function () {
2284
+ // if not encrypted, return bitstring
2285
+ if (!isEncrypted) return await Cheqd.fetchStatusList2021(credential)
2286
+
2287
+ // otherwise, decrypt and return bitstring
2288
+ const scopedRawBlob = await toBlob(await Cheqd.fetchStatusList2021(credential, true) as Uint8Array)
2289
+
2290
+ // instantiate dkg-threshold client, in which case lit-protocol is used
2291
+ const lit = await LitProtocol.create({
2292
+ chain: options?.topArgs?.bootstrapOptions?.chain,
2293
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
2294
+ })
2295
+
2296
+ // decrypt
2297
+ return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions)
2298
+ }())
2299
+ : (await async function () {
2300
+ // if status list 2021 is not fetched, read from file
2301
+ if (options?.statusListFile) {
2302
+ // if not encrypted, return bitstring
2303
+ if (!isEncrypted) return new StatusList({ buffer: await Cheqd.getFile(options.statusListFile) }).encode()
2304
+
2305
+ // otherwise, decrypt and return bitstring
2306
+ const scopedRawBlob = await toBlob(await Cheqd.getFile(options.statusListFile))
2307
+
2308
+ // instantiate dkg-threshold client, in which case lit-protocol is used
2309
+ const lit = await LitProtocol.create({
2310
+ chain: options?.topArgs?.bootstrapOptions?.chain,
2311
+ litNetwork: options?.topArgs?.bootstrapOptions?.litNetwork
2312
+ })
2313
+
2314
+ // decrypt
2315
+ return await lit.decrypt(scopedRawBlob, options?.topArgs?.encryptedSymmetricKey, options?.topArgs?.decryptionOptions?.unifiedAccessControlConditions)
2316
+ }
2317
+
2318
+ if (!options?.statusListInlineBitstring) throw new Error(' [did-provider-cheqd]: suspension: statusListInlineBitstring is required, if statusListFile is not provided')
2319
+
2320
+ // otherwise, read from inline bitstring
2321
+ return options?.statusListInlineBitstring
2322
+ }())
2323
+
2324
+ // parse status list 2021
2325
+ const statusList = await StatusList.decode({ encodedList: statusList2021 })
2326
+
2327
+ // get status by index
2328
+ return !!statusList.getStatus(Number(credential.credentialStatus.statusListIndex))
2329
+ }
2330
+
2331
+ static async publishStatusList2021(statusList2021Raw: Uint8Array, statusList2021Metadata: LinkedResourceMetadataResolutionResult, options: { context: IContext, resourceId?: string, resourceVersion?: string, signInputs?: ISignInputs[], fee?: DidStdFee }): Promise<boolean> {
2332
+ // construct status list 2021 payload from previous version + new version
2333
+ const payload = {
2334
+ collectionId: statusList2021Metadata.resourceCollectionId,
2335
+ id: options?.resourceId || v4(),
2336
+ name: statusList2021Metadata.resourceName,
2337
+ version: options?.resourceVersion || new Date().toISOString(),
2338
+ resourceType: 'StatusList2021',
2339
+ data: statusList2021Raw
2340
+ } satisfies StatusList2021ResourcePayload
2341
+
2342
+ return await options.context.agent[CreateStatusList2021MethodName]({
2343
+ kms: (await options.context.agent.keyManagerGetKeyManagementSystems())[0],
2344
+ payload,
2345
+ network: statusList2021Metadata.resourceURI.split(':')[2] as CheqdNetwork,
2346
+ signInputs: options?.signInputs,
2347
+ fee: options?.fee
2348
+ })
2349
+ }
2350
+
2351
+ static async fetchStatusList2021(credential: VerifiableCredential, returnRaw = false): Promise<Bitstring | Uint8Array> {
2352
+ // validate credential status
2353
+ if (!credential.credentialStatus) throw new Error('[did-provider-cheqd]: fetch status list: Credential status is not present')
2354
+
2355
+ // validate credential status type
2356
+ if (credential.credentialStatus.type !== 'StatusList2021Entry') throw new Error('[did-provider-cheqd]: fetch status list: Credential status type is not valid')
2357
+
2358
+ // validate credential status list status purpose
2359
+ if (credential.credentialStatus.statusPurpose !== 'revocation' && credential.credentialStatus.statusPurpose !== 'suspension') throw new Error('[did-provider-cheqd]: fetch status list: Credential status purpose is not valid')
2360
+
2361
+ // validate credential status list status list credential
2362
+ if (!credential.credentialStatus.statusListCredential) throw new Error('[did-provider-cheqd]: fetch status list: Credential status list credential is not present')
2363
+
2364
+ // fetch status list 2021
2365
+ const raw = await (await fetch(credential.credentialStatus.statusListCredential)).arrayBuffer()
2366
+
2367
+ // return raw if requested
2368
+ if (returnRaw) return new Uint8Array(raw)
2369
+
2370
+ // otherwise, parse to bitstring and return
2371
+ const bitstring = toString(new Uint8Array(raw), 'base64url')
2372
+
2373
+ return bitstring
2374
+ }
2375
+
2376
+ static async fetchStatusList2021Metadata(credential: VerifiableCredential): Promise<LinkedResourceMetadataResolutionResult> {
2377
+ // get base url
2378
+ const baseUrl = new URL(credential.credentialStatus?.statusListCredential)
2379
+
2380
+ // get resource name
2381
+ const resourceName = baseUrl.searchParams.get('resourceName')
2382
+
2383
+ // unset resource name
2384
+ baseUrl.searchParams.delete('resourceName')
2385
+
2386
+ // construct metadata url
2387
+ const metadataUrl = `${baseUrl.toString()}/metadata`
2388
+
2389
+ // fetch collection metadata
2390
+ const collectionMetadata = await (await fetch(metadataUrl)).json() as DIDMetadataDereferencingResult
2391
+
2392
+ // early exit if no linked resources
2393
+ if (!collectionMetadata?.contentStream?.linkedResourceMetadata) throw new Error('[did-provider-cheqd]: fetch status list metadata: No linked resources found')
2394
+
2395
+ // find relevant resources by resource name
2396
+ const resourceVersioning = collectionMetadata.contentStream.linkedResourceMetadata.filter((resource) => resource.resourceName === resourceName)
2397
+
2398
+ // early exit if no relevant resources
2399
+ if (!resourceVersioning.length || resourceVersioning.length === 0) throw new Error(`[did-provider-cheqd]: fetch status list metadata: No relevant resources found by resource name ${resourceName}`)
2400
+
2401
+ // get latest resource version by nextVersionId null pointer, or by latest created date as fallback
2402
+ return resourceVersioning.find((resource) => !resource.nextVersionId) || resourceVersioning.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime())[0]
447
2403
  }
448
2404
 
449
2405
  static async loadProvider(document: DIDDocument, providers: CheqdDIDProvider[]): Promise<CheqdDIDProvider> {
@@ -476,4 +2432,25 @@ export class Cheqd implements IAgentPlugin {
476
2432
  resolve(new Uint8Array(content))
477
2433
  })
478
2434
  }
2435
+
2436
+ static async writeFile(content: Uint8Array, filename?: string): Promise<void> {
2437
+ if (!filename) {
2438
+ filename = `statusList2021-${v4()}`
2439
+ }
2440
+
2441
+ // alert if file exists
2442
+ if (fs.existsSync(filename)) {
2443
+ debug(`[did-provider-cheqd]: File ${filename} already exists`)
2444
+ console.warn(`[did-provider-cheqd]: File ${filename} already exists. Overwriting...`)
2445
+ }
2446
+
2447
+ return new Promise((resolve, reject) => {
2448
+ fs.writeFile(filename!, content, (err) => {
2449
+ if (err) {
2450
+ reject(new Error(`[did-provider-cheqd]: Error writing file ${filename}: reason: ${err}`))
2451
+ }
2452
+ resolve()
2453
+ })
2454
+ })
2455
+ }
479
2456
  }