@dwn-protocol/id-sdk 0.2.5 → 0.2.6

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 (99) hide show
  1. package/package.json +2 -3
  2. package/src/agent/app-data-store.ts +0 -365
  3. package/src/agent/did-manager.ts +0 -393
  4. package/src/agent/dwn-manager.ts +0 -548
  5. package/src/agent/identity-manager.ts +0 -165
  6. package/src/agent/index.ts +0 -19
  7. package/src/agent/json-rpc.ts +0 -107
  8. package/src/agent/key-manager.ts +0 -302
  9. package/src/agent/kms-local.ts +0 -412
  10. package/src/agent/outbox.ts +0 -128
  11. package/src/agent/rpc-client.ts +0 -223
  12. package/src/agent/store-managed-did.ts +0 -295
  13. package/src/agent/store-managed-identity.ts +0 -243
  14. package/src/agent/store-managed-key.ts +0 -754
  15. package/src/agent/sync-manager.ts +0 -631
  16. package/src/agent/test-managed-agent.ts +0 -299
  17. package/src/agent/types/agent.ts +0 -145
  18. package/src/agent/types/managed-key.ts +0 -442
  19. package/src/agent/utils.ts +0 -190
  20. package/src/common/convert.ts +0 -424
  21. package/src/common/index.ts +0 -9
  22. package/src/common/multicodec.ts +0 -176
  23. package/src/common/object.ts +0 -43
  24. package/src/common/stores.ts +0 -125
  25. package/src/common/stream-node.ts +0 -381
  26. package/src/common/stream.ts +0 -406
  27. package/src/common/type-utils.ts +0 -117
  28. package/src/common/types.ts +0 -48
  29. package/src/credentials/credential-bbs.ts +0 -419
  30. package/src/credentials/credential.ts +0 -324
  31. package/src/credentials/index.ts +0 -5
  32. package/src/credentials/presentation.ts +0 -182
  33. package/src/credentials/status-list.ts +0 -365
  34. package/src/credentials/utils.ts +0 -58
  35. package/src/credentials/validators.ts +0 -52
  36. package/src/crypto/algorithms-api/aes/base.ts +0 -49
  37. package/src/crypto/algorithms-api/aes/ctr.ts +0 -51
  38. package/src/crypto/algorithms-api/aes/index.ts +0 -2
  39. package/src/crypto/algorithms-api/crypto-algorithm.ts +0 -127
  40. package/src/crypto/algorithms-api/crypto-key.ts +0 -56
  41. package/src/crypto/algorithms-api/ec/base.ts +0 -39
  42. package/src/crypto/algorithms-api/ec/ecdh.ts +0 -53
  43. package/src/crypto/algorithms-api/ec/ecdsa.ts +0 -37
  44. package/src/crypto/algorithms-api/ec/eddsa.ts +0 -30
  45. package/src/crypto/algorithms-api/ec/index.ts +0 -4
  46. package/src/crypto/algorithms-api/errors.ts +0 -29
  47. package/src/crypto/algorithms-api/index.ts +0 -6
  48. package/src/crypto/algorithms-api/pbkdf/index.ts +0 -1
  49. package/src/crypto/algorithms-api/pbkdf/pbkdf2.ts +0 -91
  50. package/src/crypto/crypto-algorithms/aes-ctr.ts +0 -70
  51. package/src/crypto/crypto-algorithms/bbs.ts +0 -110
  52. package/src/crypto/crypto-algorithms/ecdh.ts +0 -115
  53. package/src/crypto/crypto-algorithms/ecdsa.ts +0 -111
  54. package/src/crypto/crypto-algorithms/eddsa.ts +0 -110
  55. package/src/crypto/crypto-algorithms/index.ts +0 -6
  56. package/src/crypto/crypto-algorithms/pbkdf2.ts +0 -54
  57. package/src/crypto/crypto-primitives/aes-ctr.ts +0 -131
  58. package/src/crypto/crypto-primitives/aes-gcm.ts +0 -138
  59. package/src/crypto/crypto-primitives/bbs.ts +0 -183
  60. package/src/crypto/crypto-primitives/concat-kdf.ts +0 -207
  61. package/src/crypto/crypto-primitives/ed25519.ts +0 -201
  62. package/src/crypto/crypto-primitives/index.ts +0 -10
  63. package/src/crypto/crypto-primitives/pbkdf2.ts +0 -78
  64. package/src/crypto/crypto-primitives/secp256k1.ts +0 -322
  65. package/src/crypto/crypto-primitives/x25519.ts +0 -101
  66. package/src/crypto/crypto-primitives/xchacha20-poly1305.ts +0 -46
  67. package/src/crypto/crypto-primitives/xchacha20.ts +0 -34
  68. package/src/crypto/index.ts +0 -8
  69. package/src/crypto/jose.ts +0 -948
  70. package/src/crypto/types/crypto-key.ts +0 -4
  71. package/src/crypto/types/iddwn-crypto.ts +0 -119
  72. package/src/crypto/utils.ts +0 -200
  73. package/src/did-api.ts +0 -72
  74. package/src/dids/dht.ts +0 -412
  75. package/src/dids/did-dht.ts +0 -436
  76. package/src/dids/did-ion.ts +0 -613
  77. package/src/dids/did-key.ts +0 -791
  78. package/src/dids/did-resolver.ts +0 -107
  79. package/src/dids/index.ts +0 -9
  80. package/src/dids/resolver-cache-level.ts +0 -82
  81. package/src/dids/resolver-cache-noop.ts +0 -25
  82. package/src/dids/types.ts +0 -278
  83. package/src/dids/utils.ts +0 -129
  84. package/src/dwn-api.ts +0 -584
  85. package/src/iddwn.ts +0 -241
  86. package/src/identity-agent/index.ts +0 -270
  87. package/src/index.ts +0 -26
  88. package/src/interfaces/metadata.ts +0 -163
  89. package/src/interfaces/queue.ts +0 -108
  90. package/src/interfaces/services.ts +0 -122
  91. package/src/interfaces/transactions.ts +0 -220
  92. package/src/protocol.ts +0 -68
  93. package/src/proxy-agent/index.ts +0 -255
  94. package/src/record.ts +0 -521
  95. package/src/service-options.ts +0 -62
  96. package/src/typings/decentralized-identity__ion-pow-sdk.d.ts +0 -7
  97. package/src/user-agent/index.ts +0 -295
  98. package/src/utils.ts +0 -29
  99. package/src/vc-api.ts +0 -505
@@ -1,613 +0,0 @@
1
- import type { JwkKeyPair, PrivateKeyJwk, PublicKeyJwk, IDCrypto } from '../crypto/index.js';
2
- import type { IonDocumentModel, IonPublicKeyModel, JwkEd25519, JwkEs256k } from '@decentralized-identity/ion-sdk';
3
-
4
- import { Convert, universalTypeOf } from '../common/index.js';
5
- import IonProofOfWork from '@decentralized-identity/ion-pow-sdk';
6
- import { EcdsaAlgorithm, EdDsaAlgorithm, Jose } from '../crypto/index.js';
7
- import { IonDid, IonPublicKeyPurpose, IonRequest } from '@decentralized-identity/ion-sdk';
8
-
9
- import type { DidDocument, DidKeySetVerificationMethodKey, DidMethod, DidResolutionOptions, DidResolutionResult, DidService, DwnServiceEndpoint, PortableDid } from './types.js';
10
-
11
- import { getServices, isDwnServiceEndpoint, parseDid } from './utils.js';
12
-
13
- export type DidIonAnchorOptions = {
14
- challengeEnabled?: boolean;
15
- challengeEndpoint?: string;
16
- operationsEndpoint?: string;
17
- keySet: DidIonKeySet;
18
- services: DidService[];
19
- }
20
-
21
- export type DidIonCreateOptions = {
22
- anchor?: boolean;
23
- keyAlgorithm?: typeof SupportedCryptoAlgorithms[number];
24
- keySet?: DidIonKeySet;
25
- services?: DidService[];
26
- }
27
-
28
- export type DidIonKeySet = {
29
- recoveryKey?: JwkKeyPair;
30
- updateKey?: JwkKeyPair;
31
- verificationMethodKeys?: DidKeySetVerificationMethodKey[];
32
- }
33
-
34
- enum OperationType {
35
- Create = 'create',
36
- Update = 'update',
37
- Deactivate = 'deactivate',
38
- Recover = 'recover'
39
- }
40
-
41
- /**
42
- * Data model representing a public key in the DID Document.
43
- */
44
- export interface IonCreateRequestModel {
45
- type: OperationType;
46
- suffixData: {
47
- deltaHash: string;
48
- recoveryCommitment: string;
49
- };
50
- delta: {
51
- updateCommitment: string;
52
- patches: {
53
- action: string;
54
- document: IonDocumentModel;
55
- }[];
56
- }
57
- }
58
-
59
- const SupportedCryptoAlgorithms = [
60
- 'Ed25519',
61
- 'secp256k1'
62
- ] as const;
63
-
64
- const VerificationRelationshipToIonPublicKeyPurpose = {
65
- assertionMethod : IonPublicKeyPurpose.AssertionMethod,
66
- authentication : IonPublicKeyPurpose.Authentication,
67
- capabilityDelegation : IonPublicKeyPurpose.CapabilityDelegation,
68
- capabilityInvocation : IonPublicKeyPurpose.CapabilityInvocation,
69
- keyAgreement : IonPublicKeyPurpose.KeyAgreement
70
- };
71
-
72
- export class DidIonMethod implements DidMethod {
73
- /**
74
- * Name of the DID method
75
- */
76
- public static methodName = 'ion';
77
-
78
- public static async anchor(options: {
79
- services: DidService[],
80
- keySet: DidIonKeySet,
81
- challengeEnabled?: boolean,
82
- challengeEndpoint?: string,
83
- operationsEndpoint?: string
84
- }): Promise<DidResolutionResult | undefined> {
85
- const {
86
- challengeEnabled = true,
87
- challengeEndpoint = 'https://beta.ion.msidentity.com/api/v1.0/proof-of-work-challenge',
88
- keySet,
89
- services,
90
- operationsEndpoint = 'https://beta.ion.msidentity.com/api/v1.0/operations'
91
- } = options;
92
-
93
- // Create ION Document.
94
- const ionDocument = await DidIonMethod.createIonDocument({
95
- keySet: keySet,
96
- services
97
- });
98
-
99
- const createRequest = await DidIonMethod.getIonCreateRequest({
100
- ionDocument,
101
- recoveryPublicKeyJwk : keySet.recoveryKey.publicKeyJwk,
102
- updatePublicKeyJwk : keySet.updateKey.publicKeyJwk
103
- });
104
-
105
- let resolutionResult: DidResolutionResult;
106
-
107
- if (challengeEnabled) {
108
- const response = await IonProofOfWork.submitIonRequest(
109
- challengeEndpoint,
110
- operationsEndpoint,
111
- JSON.stringify(createRequest)
112
- );
113
-
114
- if (response !== undefined && universalTypeOf(response) === 'String') {
115
- resolutionResult = JSON.parse(response);
116
- }
117
-
118
- } else {
119
- const response = await fetch(operationsEndpoint, {
120
- method : 'POST',
121
- mode : 'cors',
122
- body : JSON.stringify(createRequest),
123
- headers : {
124
- 'Content-Type': 'application/json'
125
- }
126
- });
127
-
128
- if (response.ok) {
129
- resolutionResult = await response.json();
130
- }
131
- }
132
-
133
- return resolutionResult;
134
- }
135
-
136
- public static async create(options?: DidIonCreateOptions): Promise<PortableDid> {
137
- let { anchor, keyAlgorithm, keySet, services } = options ?? { };
138
-
139
- // Begin constructing a PortableDid.
140
- const did: Partial<PortableDid> = {};
141
-
142
- // If any member of the key set is missing, generate the keys.
143
- did.keySet = await DidIonMethod.generateKeySet({ keyAlgorithm, keySet });
144
-
145
- // Generate Long Form DID URI.
146
- did.did = await DidIonMethod.getLongFormDid({
147
- keySet: did.keySet,
148
- services
149
- });
150
-
151
- // Get short form DID.
152
- did.canonicalId = await DidIonMethod.getShortFormDid({ didUrl: did.did });
153
-
154
- let didResolutionResult: DidResolutionResult | undefined;
155
- if (anchor) {
156
- // Attempt to anchor the DID.
157
- didResolutionResult = await DidIonMethod.anchor({
158
- keySet: did.keySet,
159
- services
160
- });
161
-
162
- } else {
163
- // If anchoring was not requested, then resolve the long form DID.
164
- didResolutionResult = await DidIonMethod.resolve({ didUrl: did.did });
165
- }
166
-
167
- // Store the DID Document.
168
- did.document = didResolutionResult.didDocument;
169
-
170
- return did as PortableDid;
171
- }
172
-
173
- public static async decodeLongFormDid(options: {
174
- didUrl: string
175
- }): Promise<IonCreateRequestModel> {
176
- const { didUrl } = options;
177
-
178
- const parsedDid = parseDid({ didUrl });
179
-
180
- if (!parsedDid) {
181
- throw new Error(`DidIonMethod: Unable to parse DID: ${didUrl}`);
182
- }
183
-
184
- const decodedLongFormDid = Convert.base64Url(
185
- parsedDid.id.split(':').pop()
186
- ).toObject() as Pick<IonCreateRequestModel, 'delta' | 'suffixData'>;
187
-
188
- const createRequest: IonCreateRequestModel = {
189
- ...decodedLongFormDid,
190
- type: OperationType.Create
191
- };
192
-
193
- return createRequest;
194
- }
195
-
196
- /**
197
- * Generates two key pairs used for authorization and encryption purposes
198
- * when interfacing with DWNs. The IDs of these keys are referenced in the
199
- * service object that includes the dwnUrls provided.
200
- */
201
- public static async generateDwnOptions(options: {
202
- encryptionKeyId?: string,
203
- serviceEndpointNodes: string[],
204
- serviceId?: string,
205
- signingKeyAlgorithm?: typeof SupportedCryptoAlgorithms[number]
206
- signingKeyId?: string,
207
- }): Promise<DidIonCreateOptions> {
208
- const {
209
- signingKeyAlgorithm = 'Ed25519', // Generate Ed25519 key pairs, by default.
210
- serviceId = '#dwn', // Use default ID value, unless overridden.
211
- signingKeyId = '#dwn-sig', // Use default key ID value, unless overridden.
212
- encryptionKeyId = '#dwn-enc', // Use default key ID value, unless overridden.
213
- serviceEndpointNodes } = options;
214
-
215
- const signingKeyPair = await DidIonMethod.generateJwkKeyPair({
216
- keyAlgorithm : signingKeyAlgorithm,
217
- keyId : signingKeyId
218
- });
219
-
220
- /** Currently, `id` has only implemented support for record
221
- * encryption using the `ECIES-ES256K` crypto algorithm. Until the
222
- * DWN SDK supports ECIES with EdDSA, the encryption key pair must
223
- * use secp256k1. */
224
- const encryptionKeyPair = await DidIonMethod.generateJwkKeyPair({
225
- keyAlgorithm : 'secp256k1',
226
- keyId : encryptionKeyId
227
- });
228
-
229
- const keySet: DidIonKeySet = {
230
- verificationMethodKeys: [
231
- { ...signingKeyPair, relationships: ['authentication'] },
232
- { ...encryptionKeyPair, relationships: ['keyAgreement'] }
233
- ]
234
- };
235
-
236
- const serviceEndpoint: DwnServiceEndpoint = {
237
- encryptionKeys : [encryptionKeyId],
238
- nodes : serviceEndpointNodes,
239
- signingKeys : [signingKeyId]
240
- };
241
-
242
- const services: DidService[] = [{
243
- id : serviceId,
244
- serviceEndpoint,
245
- type : 'DecentralizedWebNode',
246
- }];
247
-
248
- return { keySet, services };
249
- }
250
-
251
- public static async generateJwkKeyPair(options: {
252
- keyAlgorithm: typeof SupportedCryptoAlgorithms[number],
253
- keyId?: string
254
- }): Promise<JwkKeyPair> {
255
- const { keyAlgorithm, keyId } = options;
256
-
257
- let cryptoKeyPair: IDCrypto.CryptoKeyPair;
258
-
259
- switch (keyAlgorithm) {
260
- case 'Ed25519': {
261
- cryptoKeyPair = await new EdDsaAlgorithm().generateKey({
262
- algorithm : { name: 'EdDSA', namedCurve: 'Ed25519' },
263
- extractable : true,
264
- keyUsages : ['sign', 'verify']
265
- });
266
- break;
267
- }
268
-
269
- case 'secp256k1': {
270
- cryptoKeyPair = await new EcdsaAlgorithm().generateKey({
271
- algorithm : { name: 'ECDSA', namedCurve: 'secp256k1' },
272
- extractable : true,
273
- keyUsages : ['sign', 'verify']
274
- });
275
- break;
276
- }
277
-
278
- default: {
279
- throw new Error(`Unsupported crypto algorithm: '${keyAlgorithm}'`);
280
- }
281
- }
282
-
283
- // Convert the CryptoKeyPair to JwkKeyPair.
284
- const jwkKeyPair = await Jose.cryptoKeyToJwkPair({ keyPair: cryptoKeyPair });
285
-
286
- // Set kid values.
287
- if (keyId) {
288
- jwkKeyPair.privateKeyJwk.kid = keyId;
289
- jwkKeyPair.publicKeyJwk.kid = keyId;
290
- } else {
291
- // If a key ID is not specified, generate RFC 7638 JWK thumbprint.
292
- const jwkThumbprint = await Jose.jwkThumbprint({ key: jwkKeyPair.publicKeyJwk });
293
- jwkKeyPair.privateKeyJwk.kid = jwkThumbprint;
294
- jwkKeyPair.publicKeyJwk.kid = jwkThumbprint;
295
- }
296
-
297
- return jwkKeyPair;
298
- }
299
-
300
- public static async generateKeySet(options?: {
301
- keyAlgorithm?: typeof SupportedCryptoAlgorithms[number],
302
- keySet?: DidIonKeySet
303
- }): Promise<DidIonKeySet> {
304
- // Generate Ed25519 authentication key pair, by default.
305
- let { keyAlgorithm = 'Ed25519', keySet = {} } = options ?? {};
306
-
307
- // If keySet lacks verification method keys, generate one.
308
- if (keySet.verificationMethodKeys === undefined) {
309
- const authenticationkeyPair = await DidIonMethod.generateJwkKeyPair({
310
- keyAlgorithm,
311
- keyId: 'dwn-sig'
312
- });
313
- keySet.verificationMethodKeys = [{
314
- ...authenticationkeyPair,
315
- relationships: ['authentication', 'assertionMethod']
316
- }];
317
- }
318
-
319
- // If keySet lacks recovery key, generate one.
320
- if (keySet.recoveryKey === undefined) {
321
- // Note: ION/Sidetree only supports secp256k1 recovery keys.
322
- keySet.recoveryKey = await DidIonMethod.generateJwkKeyPair({
323
- keyAlgorithm : 'secp256k1',
324
- keyId : 'ion-recovery-1'
325
- });
326
- }
327
-
328
- // If keySet lacks update key, generate one.
329
- if (keySet.updateKey === undefined) {
330
- // Note: ION/Sidetree only supports secp256k1 update keys.
331
- keySet.updateKey = await DidIonMethod.generateJwkKeyPair({
332
- keyAlgorithm : 'secp256k1',
333
- keyId : 'ion-update-1'
334
- });
335
- }
336
-
337
- // Generate RFC 7638 JWK thumbprints if `kid` is missing from any key.
338
- for (const key of [...keySet.verificationMethodKeys, keySet.recoveryKey, keySet.updateKey]) {
339
- if ('publicKeyJwk' in key) key.publicKeyJwk.kid ??= await Jose.jwkThumbprint({ key: key.publicKeyJwk });
340
- if ('privateKeyJwk' in key) key.privateKeyJwk.kid ??= await Jose.jwkThumbprint({ key: key.privateKeyJwk });
341
- }
342
-
343
- return keySet;
344
- }
345
-
346
- /**
347
- * Given the W3C DID Document of a `did:ion` DID, return the identifier of
348
- * the verification method key that will be used for signing messages and
349
- * credentials, by default.
350
- *
351
- * @param document = DID Document to get the default signing key from.
352
- * @returns Verification method identifier for the default signing key.
353
- */
354
- public static async getDefaultSigningKey(options: {
355
- didDocument: DidDocument
356
- }): Promise<string | undefined> {
357
- const { didDocument } = options;
358
-
359
- if (!didDocument.id) {
360
- throw new Error(`DidIonMethod: DID document is missing 'id' property`);
361
- }
362
-
363
- /** If the DID document contains a DWN service endpoint in the expected
364
- * format, return the first entry in the `signingKeys` array. */
365
- const [dwnService] = getServices({ didDocument, type: 'DecentralizedWebNode' });
366
- if (isDwnServiceEndpoint(dwnService?.serviceEndpoint)) {
367
- const [verificationMethodId] = dwnService.serviceEndpoint.signingKeys;
368
- const did = didDocument.id;
369
- const signingKeyId = `${did}${verificationMethodId}`;
370
- return signingKeyId;
371
- }
372
-
373
- /** Otherwise, fallback to a naive approach of returning the first key ID
374
- * in the `authentication` verification relationships array. */
375
- if (didDocument.authentication
376
- && Array.isArray(didDocument.authentication)
377
- && didDocument.authentication.length > 0
378
- && typeof didDocument.authentication[0] === 'string') {
379
- const [verificationMethodId] = didDocument.authentication;
380
- const did = didDocument.id;
381
- const signingKeyId = `${did}${verificationMethodId}`;
382
- return signingKeyId;
383
- }
384
- }
385
-
386
- public static async getLongFormDid(options: {
387
- services: DidService[],
388
- keySet: DidIonKeySet
389
- }): Promise<string> {
390
- const { services = [], keySet } = options;
391
-
392
- // Create ION Document.
393
- const ionDocument = await DidIonMethod.createIonDocument({
394
- keySet: keySet,
395
- services
396
- });
397
-
398
- // Filter JWK to only those properties expected by ION/Sidetree.
399
- const recoveryKey = DidIonMethod.jwkToIonJwk({ key: keySet.recoveryKey.publicKeyJwk }) as JwkEs256k;
400
- const updateKey = DidIonMethod.jwkToIonJwk({ key: keySet.updateKey.publicKeyJwk }) as JwkEs256k;
401
-
402
- // Create an ION DID create request operation.
403
- const did = await IonDid.createLongFormDid({
404
- document: ionDocument,
405
- recoveryKey,
406
- updateKey
407
- });
408
-
409
- return did;
410
- }
411
-
412
- public static async getShortFormDid(options: {
413
- didUrl: string
414
- }): Promise<string> {
415
- const { didUrl } = options;
416
-
417
- const parsedDid = parseDid({ didUrl });
418
-
419
- if (!parsedDid) {
420
- throw new Error(`DidIonMethod: Unable to parse DID: ${didUrl}`);
421
- }
422
-
423
- const shortFormDid = parsedDid.did.split(':', 3).join(':');
424
-
425
- return shortFormDid;
426
- }
427
-
428
- public static async resolve(options: {
429
- didUrl: string,
430
- resolutionOptions?: DidResolutionOptions
431
- }): Promise<DidResolutionResult> {
432
- // TODO: add resolutionOptions as defined in https://www.w3.org/TR/did-core/#did-resolution
433
- const { didUrl, resolutionOptions = {} } = options;
434
-
435
- const parsedDid = parseDid({ didUrl });
436
- if (!parsedDid) {
437
- return {
438
- '@context' : 'https://w3id.org/did-resolution/v1',
439
- didDocument : undefined,
440
- didDocumentMetadata : {},
441
- didResolutionMetadata : {
442
- contentType : 'application/did+json',
443
- error : 'invalidDid',
444
- errorMessage : `Cannot parse DID: ${didUrl}`
445
- }
446
- };
447
- }
448
-
449
- if (parsedDid.method !== 'ion') {
450
- return {
451
- '@context' : 'https://w3id.org/did-resolution/v1',
452
- didDocument : undefined,
453
- didDocumentMetadata : {},
454
- didResolutionMetadata : {
455
- contentType : 'application/did+json',
456
- error : 'methodNotSupported',
457
- errorMessage : `Method not supported: ${parsedDid.method}`
458
- }
459
- };
460
- }
461
-
462
- const { resolutionEndpoint = 'https://discover.did.msidentity.com/1.0/identifiers/' } = resolutionOptions;
463
- const normalizeUrl = (url: string): string => url.endsWith('/') ? url : url + '/';
464
- const resolutionUrl = `${normalizeUrl(resolutionEndpoint)}${parsedDid.did}`;
465
-
466
- const response = await fetch(resolutionUrl);
467
-
468
- let resolutionResult: DidResolutionResult | object;
469
- try {
470
- resolutionResult = await response.json();
471
- } catch (error) {
472
- resolutionResult = {};
473
- }
474
-
475
- if (response.ok) {
476
- return resolutionResult as DidResolutionResult;
477
- }
478
-
479
- // Response was not "OK" (HTTP 4xx-5xx status code)
480
-
481
- // Return result if it contains DID resolution metadata.
482
- if ('didResolutionMetadata' in resolutionResult) {
483
- return resolutionResult;
484
- }
485
-
486
- // Set default error code and message.
487
- let error = 'internalError';
488
- let errorMessage = `DID resolver responded with HTTP status code: ${response.status}`;
489
-
490
- /** The Microsoft resolution endpoint does not return a valid DidResolutionResult
491
- * when an ION DID is "not found" so normalization is needed. */
492
- if ('error' in resolutionResult &&
493
- typeof resolutionResult.error === 'object' &&
494
- 'code' in resolutionResult.error &&
495
- typeof resolutionResult.error.code === 'string' &&
496
- 'message' in resolutionResult.error &&
497
- typeof resolutionResult.error.message === 'string') {
498
- error = resolutionResult.error.code.includes('not_found') ? 'notFound' : error;
499
- errorMessage = resolutionResult.error.message ?? errorMessage;
500
- }
501
-
502
- return {
503
- '@context' : 'https://w3id.org/did-resolution/v1',
504
- didDocument : undefined,
505
- didDocumentMetadata : {},
506
- didResolutionMetadata : {
507
- contentType: 'application/did+json',
508
- error,
509
- errorMessage
510
- }
511
- };
512
- }
513
-
514
- public static async createIonDocument(options: {
515
- keySet: DidIonKeySet,
516
- services?: DidService[]
517
- }): Promise<IonDocumentModel> {
518
- const { services = [], keySet } = options;
519
-
520
- /**
521
- * STEP 1: Convert key set verification method keys to ION SDK format.
522
- */
523
-
524
- const ionPublicKeys: IonPublicKeyModel[] = [];
525
-
526
- for (const key of keySet.verificationMethodKeys) {
527
- // Map W3C DID verification relationship names to ION public key purposes.
528
- const ionPurposes: IonPublicKeyPurpose[] = [];
529
- for (const relationship of key.relationships) {
530
- ionPurposes.push(
531
- VerificationRelationshipToIonPublicKeyPurpose[relationship]
532
- );
533
- }
534
-
535
- /** During certain ION operations, JWK validation will throw an error
536
- * if key IDs provided as input are prefixed with `#`. ION operation
537
- * outputs and DID document resolution always include the `#` prefix
538
- * for key IDs resulting in a confusing mismatch between inputs and
539
- * outputs. To improve the developer experience, this inconsistency
540
- * is addressed by normalizing input key IDs before being passed
541
- * to ION SDK methods. */
542
- const publicKeyId = (key.publicKeyJwk.kid.startsWith('#'))
543
- ? key.publicKeyJwk.kid.substring(1)
544
- : key.publicKeyJwk.kid;
545
-
546
- // Convert public key JWK to ION format.
547
- const publicKey: IonPublicKeyModel = {
548
- id : publicKeyId,
549
- publicKeyJwk : DidIonMethod.jwkToIonJwk({ key: key.publicKeyJwk }),
550
- purposes : ionPurposes,
551
- type : 'JsonWebKey2020'
552
- };
553
-
554
- ionPublicKeys.push(publicKey);
555
- }
556
-
557
- /**
558
- * STEP 2: Convert service entries, if any, to ION SDK format.
559
- */
560
- const ionServices = services.map(service => ({
561
- ...service,
562
- id: service.id.startsWith('#') ? service.id.substring(1) : service.id
563
- }));
564
-
565
- /**
566
- * STEP 3: Format as ION document.
567
- */
568
-
569
- const ionDocumentModel: IonDocumentModel = {
570
- publicKeys : ionPublicKeys,
571
- services : ionServices
572
- };
573
-
574
- return ionDocumentModel;
575
- }
576
-
577
- public static async getIonCreateRequest(options: {
578
- ionDocument: IonDocumentModel,
579
- recoveryPublicKeyJwk: PublicKeyJwk,
580
- updatePublicKeyJwk: PublicKeyJwk
581
- }): Promise<IonCreateRequestModel> {
582
- const { ionDocument, recoveryPublicKeyJwk, updatePublicKeyJwk } = options;
583
-
584
- // Create an ION DID create request operation.
585
- const createRequest = await IonRequest.createCreateRequest({
586
- document : ionDocument,
587
- recoveryKey : DidIonMethod.jwkToIonJwk({ key: recoveryPublicKeyJwk }) as JwkEs256k,
588
- updateKey : DidIonMethod.jwkToIonJwk({ key: updatePublicKeyJwk }) as JwkEs256k
589
- });
590
-
591
- return createRequest;
592
- }
593
-
594
- private static jwkToIonJwk({ key }: { key: PrivateKeyJwk | PublicKeyJwk }): JwkEd25519 | JwkEs256k {
595
- let ionJwk: Partial<JwkEd25519 | JwkEs256k> = { };
596
-
597
- if ('crv' in key) {
598
- ionJwk.crv = key.crv;
599
- ionJwk.kty = key.kty;
600
- ionJwk.x = key.x;
601
- if ('d' in key) ionJwk.d = key.d;
602
-
603
- if ('y' in key && key.y) {
604
- // secp256k1 JWK.
605
- return { ...ionJwk, y: key.y} as JwkEs256k;
606
- }
607
- // Ed25519 JWK.
608
- return { ...ionJwk } as JwkEd25519;
609
- }
610
-
611
- throw new Error(`jwkToIonJwk: Unsupported key algorithm.`);
612
- }
613
- }