@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,754 +0,0 @@
1
- import type { RecordsWriteMessage, RecordsWriteOptions } from '@dwn-protocol/id';
2
-
3
- import * as cryptoUtils from '../crypto/utils.js';
4
- import { Convert, removeEmptyObjects, removeUndefinedProperties } from '../common/index.js';
5
-
6
- import type { ManagedKey, ManagedKeyPair, ManagedKeyStore, ManagedPrivateKey } from './types/managed-key.js';
7
-
8
- import { DwnResponse, IDManagedAgent } from './types/agent.js';
9
- import { isManagedKeyPair } from './utils.js';
10
-
11
- type EncodedPrivateKey = Omit<ManagedPrivateKey, 'material'> & {
12
- // Key material, encoded as Base64Url.
13
- material: string;
14
- }
15
-
16
- type EncodedKey = Omit<ManagedKey, 'material'> & {
17
- // Key material, encoded as Base64Url.
18
- material?: string;
19
- }
20
-
21
- type EncodedKeyPair = {
22
- privateKey: EncodedKey;
23
- publicKey: EncodedKey;
24
- }
25
-
26
- /**
27
- * An implementation of `ManagedKeyStore` that stores key metadata and
28
- * public key material in a DWN.
29
- *
30
- * An instance of this class can be used by `KeyManager` or
31
- * an implementation of `KeyManagementSystem`.
32
- */
33
- export class KeyStoreDwn implements ManagedKeyStore<string, ManagedKey | ManagedKeyPair> {
34
- private _keyRecordProperties = {
35
- dataFormat : 'application/json',
36
- schema : 'https://abaxx.tech/schemas/dwn/managed-key'
37
- };
38
-
39
- constructor(options?: { schema: string }) {
40
- const { schema } = options ?? {};
41
- if (schema) {
42
- this._keyRecordProperties.schema = schema;
43
- }
44
- }
45
-
46
- async deleteKey(options: {
47
- agent: IDManagedAgent,
48
- context?: string,
49
- id: string
50
- }): Promise<boolean> {
51
- const { agent, context, id } = options;
52
-
53
- // Determine which DID to use to author DWN messages.
54
- const authorDid = await this.getAuthor({ agent, context });
55
-
56
- // Query the DWN for all stored key objects.
57
- const { reply: queryReply} = await this.getKeyRecords(agent, context);
58
-
59
- // Loop through all of the entries and try to find a match.
60
- let matchingRecordId: string | undefined;
61
- for (const record of queryReply.entries ?? []) {
62
- // @ts-ignore
63
- if (record.encodedData) {
64
- // @ts-ignore
65
- const storedKey = this.decodeKey(record.encodedData);
66
- const storedKeyId = isManagedKeyPair(storedKey) ? storedKey.publicKey.id : storedKey.id;
67
- if (storedKey && storedKeyId === id) {
68
- matchingRecordId = (record as RecordsWriteMessage).recordId ;
69
- break;
70
- }
71
- }
72
- }
73
-
74
- // Return undefined if the specified key was not found in the store.
75
- if (!matchingRecordId) return false;
76
-
77
- // If a record for the specified key was found, attempt to delete it.
78
- const { reply: { status } } = await agent.dwnManager.processRequest({
79
- author : authorDid,
80
- target : authorDid,
81
- messageType : 'RecordsDelete',
82
- messageOptions : {
83
- recordId: matchingRecordId
84
- }
85
- });
86
-
87
- // If the key was successfully deleted, return true;
88
- if (status.code === 202) return true;
89
-
90
- // If the key could not be deleted, return false;
91
- return false;
92
- }
93
-
94
- async findKey(options: { id: string, agent: IDManagedAgent, context?: string }): Promise<ManagedKey | ManagedKeyPair | undefined>;
95
- async findKey(options: { alias: string, agent: IDManagedAgent, context?: string }): Promise<ManagedKey | ManagedKeyPair | undefined>;
96
- async findKey(options: { agent: IDManagedAgent, alias?: string, context?: string, id?: string }): Promise<ManagedKey | ManagedKeyPair | undefined> {
97
- const { agent, alias, context, id } = options;
98
-
99
- // Query the DWN for all stored managed key objects.
100
- const { reply: queryReply} = await this.getKeyRecords(agent, context);
101
-
102
- // Loop through all of the entries and return a match, if found.
103
- for (const record of queryReply.entries ?? []) {
104
- // @ts-ignore
105
- if (record.encodedData) {
106
- // @ts-ignore
107
- const storedKey = this.decodeKey(record.encodedData);
108
- if (isManagedKeyPair(storedKey)) {
109
- if (storedKey.publicKey.id === id) return storedKey;
110
- if (storedKey.publicKey.alias === alias) return storedKey;
111
- } else {
112
- if (storedKey.id === id) return storedKey;
113
- if (storedKey.alias === alias) return storedKey;
114
- }
115
- }
116
- }
117
-
118
- // Return undefined if no matches were found.
119
- return undefined;
120
- }
121
-
122
- async getKey(options: {
123
- agent: IDManagedAgent,
124
- context?: string,
125
- id: string
126
- }): Promise<ManagedKey | ManagedKeyPair | undefined> {
127
- const { agent, context, id } = options;
128
-
129
- // Query the DWN for all stored managed key objects.
130
- const { reply: queryReply} = await this.getKeyRecords(agent, context);
131
-
132
- // Loop through all of the entries and return a match, if found.
133
- for (const record of queryReply.entries ?? []) {
134
- // @ts-ignore
135
- if (record.encodedData) {
136
- // @ts-ignore
137
- const storedKey = this.decodeKey(record.encodedData);
138
- const storedKeyId = isManagedKeyPair(storedKey) ? storedKey.publicKey.id : storedKey.id;
139
- if (storedKeyId === id) return storedKey;
140
- }
141
- }
142
-
143
- // Return undefined if no matches were found.
144
- return undefined;
145
- }
146
-
147
- async importKey(options: {
148
- agent: IDManagedAgent,
149
- context?: string,
150
- key: ManagedKey | ManagedKeyPair
151
- }): Promise<string> {
152
- const { agent, context, key } = options;
153
-
154
- let keyId: string;
155
- if (isManagedKeyPair(key)) {
156
- keyId = key.publicKey.id;
157
- } else {
158
- // If an ID wasn't specified, generate one.
159
- if (!key.id) {
160
- key.id = cryptoUtils.randomUuid();
161
- }
162
- keyId = key.id;
163
- }
164
-
165
- // Determine which DID to use to author DWN messages.
166
- const authorDid = await this.getAuthor({ agent, context });
167
-
168
- // Check if the key being imported is already present in the store.
169
- const duplicateFound = await this.getKey({ agent, context, id: keyId });
170
- if (duplicateFound) {
171
- throw new Error(`KeyStoreDwn: Key with ID already exists: '${keyId}'`);
172
- }
173
-
174
- // Encode the managed key or key pair as bytes.
175
- const encodedKey = this.encodeKey(key);
176
-
177
- const { reply: { status } } = await agent.dwnManager.processRequest({
178
- author : authorDid,
179
- target : authorDid,
180
- messageType : 'RecordsWrite',
181
- messageOptions : { ...this._keyRecordProperties },
182
- // @ts-ignore
183
- dataStream : new Blob([encodedKey])
184
- });
185
-
186
- // If the write fails, throw an error.
187
- if (status.code !== 202) {
188
- throw new Error('DidStoreDwn: Failed to write imported DID to store.');
189
- }
190
-
191
- return keyId;
192
- }
193
-
194
- async listKeys(options: {
195
- agent: IDManagedAgent,
196
- context?: string
197
- }): Promise<(ManagedKey | ManagedKeyPair)[]> {
198
- const { agent, context } = options;
199
-
200
- // Query the DWN for all stored managed key objects.
201
- const { reply: queryReply} = await this.getKeyRecords(agent, context);
202
-
203
- // Loop through all of the entries and accumulate the key objects.
204
- let storedKeys: (ManagedKey | ManagedKeyPair)[] = [];
205
- for (const record of queryReply.entries ?? []) {
206
- // @ts-ignore
207
- if (record.encodedData) {
208
- // @ts-ignore
209
- const storedKey = this.decodeKey(record.encodedData);
210
- storedKeys.push(storedKey);
211
- }
212
- }
213
-
214
- return storedKeys;
215
- }
216
-
217
- async updateKey(options: {
218
- agent: IDManagedAgent,
219
- context?: string
220
- } & Pick<ManagedKey, 'id' | 'alias' | 'metadata'>): Promise<boolean> {
221
- const { agent, context, id } = options;
222
- const propertyUpdates = { alias: options.alias, metadata: options.metadata };
223
-
224
- // Determine which DID to use to author DWN messages.
225
- const authorDid = await this.getAuthor({ agent, context });
226
-
227
- // Query the DWN for all stored managed key objects.
228
- const { reply: queryReply} = await this.getKeyRecords(agent, context);
229
-
230
- // Confirm the key being updated is already present in the store.
231
- let keyToUpdate: ManagedKey | ManagedKeyPair | undefined;
232
- let recordToUpdate: RecordsWriteMessage | undefined;
233
- for (const entry of queryReply.entries ?? []) {
234
- // @ts-ignore
235
- const { encodedData, ...record } = entry;
236
- if (encodedData) {
237
- const storedKey = this.decodeKey(encodedData);
238
- const storedKeyId = isManagedKeyPair(storedKey) ? storedKey.publicKey.id : storedKey.id;
239
- if (storedKey && storedKeyId === id) {
240
- keyToUpdate = storedKey;
241
- recordToUpdate = record as RecordsWriteMessage ;
242
- break;
243
- }
244
- }
245
- }
246
-
247
- // Key with given ID not present so update operation cannot proceed.
248
- if (!recordToUpdate || !keyToUpdate) return false;
249
-
250
- // Make a deep copy of the update properties to ensure all nested objects do not share references.
251
- removeUndefinedProperties(propertyUpdates);
252
- removeEmptyObjects(propertyUpdates);
253
- const clonedUpdates = structuredClone(propertyUpdates);
254
-
255
- // Update the given properties of the key.
256
- if (isManagedKeyPair(keyToUpdate)) {
257
- keyToUpdate.privateKey = { ...keyToUpdate.privateKey, ...clonedUpdates };
258
- keyToUpdate.publicKey = { ...keyToUpdate.publicKey, ...clonedUpdates };
259
- } else {
260
- keyToUpdate = { ...keyToUpdate, ...clonedUpdates };
261
- }
262
-
263
- // Encode the updated key or key pair as bytes.
264
- const updatedKeyBytes: any = this.encodeKey(keyToUpdate);
265
-
266
- // Assemble the update messsage, including record ID and context ID, if any.
267
- let messageOptions = { ...recordToUpdate.descriptor } as Partial<RecordsWriteOptions>;
268
- messageOptions.contextId = recordToUpdate.contextId;
269
- messageOptions.recordId = recordToUpdate.recordId;
270
-
271
- /** Remove properties from the update messageOptions to let the DWN SDK
272
- * auto-fill. Otherwisse, you will get 409 Conflict errors. */
273
- delete messageOptions.dataCid;
274
- delete messageOptions.dataSize;
275
- delete messageOptions.data;
276
- delete messageOptions.messageTimestamp;
277
-
278
- // Overwrite the entry in the store with the updated object.
279
- const { reply: { status } } = await agent.dwnManager.processRequest({
280
- author : authorDid,
281
- target : authorDid,
282
- messageType : 'RecordsWrite',
283
- messageOptions,
284
- dataStream : new Blob([updatedKeyBytes])
285
- });
286
-
287
- // If the write fails, throw an error.
288
- if (status.code !== 202) {
289
- throw new Error('DidStoreDwn: Failed to write updated key to store.');
290
- }
291
-
292
- return true;
293
- }
294
-
295
- private decodeKey(keyEncodedData: string): ManagedKey | ManagedKeyPair {
296
- const encodedKey = Convert.base64Url(keyEncodedData).toObject() as EncodedKey | EncodedKeyPair;
297
-
298
- if ('publicKey' in encodedKey) {
299
- const privateKeyMaterial = encodedKey.privateKey.material
300
- ? Convert.base64Url(encodedKey.privateKey.material).toUint8Array()
301
- : undefined;
302
-
303
- const publicKeyMaterial = encodedKey.publicKey.material
304
- ? Convert.base64Url(encodedKey.publicKey.material).toUint8Array()
305
- : undefined;
306
-
307
- const managedKeyPair = {
308
- privateKey : { ...encodedKey.privateKey, material: privateKeyMaterial },
309
- publicKey : { ...encodedKey.publicKey, material: publicKeyMaterial}
310
- } as ManagedKeyPair;
311
-
312
- return managedKeyPair;
313
-
314
- } else {
315
- const material = encodedKey.material
316
- ? Convert.base64Url(encodedKey.material).toUint8Array()
317
- : undefined;
318
-
319
- const managedKey = { ...encodedKey, material } as ManagedKey;
320
-
321
- return managedKey;
322
- }
323
- }
324
-
325
- private encodeKey(managedKey: ManagedKey | ManagedKeyPair): Uint8Array {
326
- let encodedKey: EncodedKey | EncodedKeyPair;
327
-
328
- if (isManagedKeyPair(managedKey)) {
329
- const privateKeyMaterial = managedKey.privateKey.material
330
- ? Convert.uint8Array(managedKey.privateKey.material).toBase64Url()
331
- : undefined;
332
-
333
- const publicKeyMaterial = managedKey.publicKey.material
334
- ? Convert.uint8Array(managedKey.publicKey.material).toBase64Url()
335
- : undefined;
336
-
337
- encodedKey = {
338
- privateKey : { ...managedKey.privateKey, material: privateKeyMaterial },
339
- publicKey : { ...managedKey.publicKey, material: publicKeyMaterial }
340
- };
341
-
342
- } else {
343
- const material = managedKey.material
344
- ? Convert.uint8Array(managedKey.material).toBase64Url()
345
- : undefined;
346
-
347
- encodedKey = { ...managedKey, material };
348
- }
349
-
350
- const keyBytes = Convert.object(encodedKey).toUint8Array();
351
-
352
- return keyBytes;
353
- }
354
-
355
- private async getAuthor(options: {
356
- agent: IDManagedAgent,
357
- context?: string
358
- }): Promise<string> {
359
- const { agent, context } = options;
360
-
361
- // If `context` is specified, DWN messages will be signed by this DID.
362
- if (context) return context;
363
-
364
- // If Agent has an agentDid, use it to sign DWN messages.
365
- if (agent.agentDid) return agent.agentDid;
366
-
367
- // If `context` and `agent.agentDid`are undefined, throw error.
368
- throw new Error(`KeyStoreDwn: Agent property 'agentDid' is undefined and no context was specified.`);
369
- }
370
-
371
- private async getKeyRecords(agent: IDManagedAgent, context?: string): Promise<DwnResponse> {
372
- // Determine which DID to use to author DWN messages.
373
- const authorDid = await this.getAuthor({ agent, context });
374
-
375
- const dwnResponse = await agent.dwnManager.processRequest({
376
- author : authorDid,
377
- target : authorDid,
378
- messageType : 'RecordsQuery',
379
- messageOptions : {
380
- filter: { ...this._keyRecordProperties }
381
- }
382
- });
383
-
384
- return dwnResponse;
385
- }
386
- }
387
-
388
- /**
389
- * An implementation of `ManagedKeyStore` that stores key metadata and
390
- * public key material in memory.
391
- *
392
- * An instance of this class can be used by `KeyManager` or
393
- * an implementation of `KeyManagementSystem`.
394
- */
395
- export class KeyStoreMemory implements ManagedKeyStore<string, ManagedKey | ManagedKeyPair> {
396
- /**
397
- * A private field that contains the Map used as the in-memory key-value store.
398
- */
399
- private store: Map<string, ManagedKey | ManagedKeyPair> = new Map();
400
-
401
- async deleteKey({ id }: { id: string }): Promise<boolean> {
402
- if (this.store.has(id)) {
403
- // Key with given ID exists so proceed with delete.
404
- this.store.delete(id);
405
- return true;
406
- }
407
-
408
- // Key with given ID not present so delete operation not possible.
409
- return false;
410
- }
411
-
412
- async findKey(options: { id: string }): Promise<ManagedKey | ManagedKeyPair | undefined>;
413
- async findKey(options: { alias: string }): Promise<ManagedKey | ManagedKeyPair | undefined>;
414
- async findKey(options: { alias?: string, id?: string }): Promise<ManagedKey | ManagedKeyPair | undefined> {
415
- let { alias, id } = options;
416
-
417
- // Get key by ID.
418
- if (id) return this.store.get(id);
419
-
420
- if (alias) {
421
- // Search through the store to find a matching entry.
422
- for (const key of await this.listKeys()) {
423
- if ('alias' in key && key.alias === alias) return key;
424
- if ('publicKey' in key && key.publicKey.alias === alias) return key;
425
- }
426
- }
427
-
428
- return undefined;
429
- }
430
-
431
- async getKey({ id }: { id: string }): Promise<ManagedKey | ManagedKeyPair | undefined> {
432
- return this.store.get(id);
433
- }
434
-
435
- async importKey({ key }: { key: ManagedKey | ManagedKeyPair }): Promise<string> {
436
- let id: string;
437
- if (isManagedKeyPair(key)) {
438
- id = key.publicKey.id;
439
- } else {
440
- // If an ID wasn't specified, generate one.
441
- if (!key.id) {
442
- key.id = cryptoUtils.randomUuid();
443
- }
444
- id = key.id;
445
- }
446
-
447
- if (this.store.has(id)) {
448
- // Key with given ID already exists so import operation cannot proceed.
449
- throw new Error(`KeyStoreMemory: Key with ID already exists: '${id}'`);
450
- }
451
-
452
- // Make a deep copy of the key so that the object stored does not share the same references as the input key.
453
- const clonedKey = structuredClone(key);
454
- this.store.set(id, clonedKey);
455
-
456
- return id;
457
- }
458
-
459
- async listKeys(): Promise<(ManagedKey | ManagedKeyPair)[]> {
460
- return Array.from(this.store.values());
461
- }
462
-
463
- async updateKey(options:
464
- Pick<ManagedKey, 'id' | 'alias' | 'metadata'>
465
- ): Promise<boolean> {
466
- const id = options.id;
467
- const propertyUpdates = { alias: options.alias, metadata: options.metadata };
468
-
469
- const keyExists = this.store.has(id);
470
- if (!keyExists) {
471
- // Key with given ID not present so update operation cannot proceed.
472
- return false;
473
- }
474
-
475
- // Retrieve the current value of the key from the store.
476
- let key = await this.getKey({ id }) as ManagedKey | ManagedKeyPair;
477
-
478
- // Make a deep copy of the update properties to ensure all nested objects do not share references.
479
- removeUndefinedProperties(propertyUpdates);
480
- removeEmptyObjects(propertyUpdates);
481
- const clonedUpdates = structuredClone(propertyUpdates);
482
-
483
- // Update the given properties of the key.
484
- if (isManagedKeyPair(key)) {
485
- key.privateKey = { ...key.privateKey, ...clonedUpdates };
486
- key.publicKey = { ...key.publicKey, ...clonedUpdates };
487
- } else {
488
- key = { ...key, ...clonedUpdates, id: key.id };
489
- }
490
-
491
- // Overwrite the entry in the store with the updated object.
492
- this.store.set(id, key);
493
-
494
- return true;
495
- }
496
- }
497
-
498
- /**
499
- * An implementation of `ManagedKeyStore` that stores private key
500
- * material in a DWN.
501
- *
502
- * An instance of this class can be used by an implementation of
503
- * `KeyManagementSystem`.
504
- */
505
- export class PrivateKeyStoreDwn implements ManagedKeyStore<string, ManagedPrivateKey> {
506
- private _keyRecordProperties = {
507
- dataFormat : 'application/json',
508
- schema : 'https://abaxx.tech/schemas/dwn/kms-private-key'
509
- };
510
-
511
- async deleteKey(options: {
512
- agent: IDManagedAgent,
513
- context?: string,
514
- id: string
515
- }): Promise<boolean> {
516
- const { agent, context, id } = options;
517
-
518
- // Determine which DID to use to author DWN messages.
519
- const authorDid = await this.getAuthor({ agent, context });
520
-
521
- // Query the DWN for all stored key objects.
522
- const { reply: queryReply} = await this.getKeyRecords(agent, context);
523
-
524
- // Loop through all of the entries and try to find a match.
525
- let matchingRecordId: string | undefined;
526
- for (const record of queryReply.entries ?? []) {
527
- // @ts-ignore
528
- if (record.encodedData) {
529
- // @ts-ignore
530
- const storedKey = this.decodeKey(record.encodedData);
531
- if (storedKey && storedKey.id === id) {
532
- matchingRecordId = (record as RecordsWriteMessage).recordId ;
533
- break;
534
- }
535
- }
536
- }
537
-
538
- // Return undefined if the specified key was not found in the store.
539
- if (!matchingRecordId) return false;
540
-
541
- // If a record for the specified key was found, attempt to delete it.
542
- const { reply: { status } } = await agent.dwnManager.processRequest({
543
- author : authorDid,
544
- target : authorDid,
545
- messageType : 'RecordsDelete',
546
- messageOptions : {
547
- recordId: matchingRecordId
548
- }
549
- });
550
-
551
- // If the key was successfully deleted, return true;
552
- if (status.code === 202) return true;
553
-
554
- // If the key could not be deleted, return false;
555
- return false;
556
- }
557
-
558
- async findKey(): Promise<ManagedPrivateKey | undefined> {
559
- throw new Error(`PrivateKeyStoreDwn: Method not implemented: 'findKey'`);
560
- }
561
-
562
- async getKey(options: {
563
- agent: IDManagedAgent,
564
- context?: string,
565
- id: string
566
- }): Promise<ManagedPrivateKey | undefined> {
567
- const { agent, context, id } = options;
568
-
569
- // Query the DWN for all stored key objects.
570
- const { reply: queryReply} = await this.getKeyRecords(agent, context);
571
-
572
- // Loop through all of the entries and return a match, if found.
573
- for (const record of queryReply.entries ?? []) {
574
- // @ts-ignore
575
- if (record.encodedData) {
576
- // @ts-ignore
577
- const storedKey = this.decodeKey(record.encodedData);
578
- if (storedKey.id === id) return storedKey;
579
- }
580
- }
581
-
582
- // Return undefined if no matches were found.
583
- return undefined;
584
- }
585
-
586
- async importKey(options: {
587
- agent: IDManagedAgent,
588
- context?: string,
589
- key: Omit<ManagedPrivateKey, 'id'>
590
- }): Promise<string> {
591
- const { agent, context, key } = options;
592
-
593
- if (!key.material) throw new TypeError(`Required parameter missing: 'material'`);
594
- if (!key.type) throw new TypeError(`Required parameter missing: 'type'`);
595
-
596
- // Determine which DID to use to author DWN messages.
597
- const authorDid = await this.getAuthor({ agent, context });
598
-
599
- // Encode the managed key or key pair as bytes.
600
- const id = cryptoUtils.randomUuid(); // Generate a random ID.
601
- const encodedPrivateKey: any = this.encodeKey({...key, id });
602
-
603
- const { reply: { status } } = await agent.dwnManager.processRequest({
604
- author : authorDid,
605
- target : authorDid,
606
- messageType : 'RecordsWrite',
607
- messageOptions : { ...this._keyRecordProperties },
608
- dataStream : new Blob([encodedPrivateKey])
609
- });
610
-
611
- // If the write fails, throw an error.
612
- if (status.code !== 202) {
613
- throw new Error('PrivateKeyStoreDwn: Failed to write imported DID to store.');
614
- }
615
-
616
- return id;
617
- }
618
-
619
- async listKeys(options: {
620
- agent: IDManagedAgent,
621
- context?: string
622
- }): Promise<ManagedPrivateKey[]> {
623
- const { agent, context } = options;
624
-
625
- // Query the DWN for all stored key objects.
626
- const { reply: queryReply} = await this.getKeyRecords(agent, context);
627
-
628
- // Loop through all of the entries and accumulate the key objects.
629
- let storedKeys: ManagedPrivateKey[] = [];
630
- for (const record of queryReply.entries ?? []) {
631
- // @ts-ignore
632
- if (record.encodedData) {
633
- // @ts-ignore
634
- const storedKey = this.decodeKey(record.encodedData);
635
- storedKeys.push(storedKey);
636
- }
637
- }
638
-
639
- return storedKeys;
640
- }
641
-
642
- async updateKey(): Promise<boolean> {
643
- throw new Error(`PrivateKeyStoreMemory: Method not implemented: 'updateKey'`);
644
- }
645
-
646
- private decodeKey(keyEncodedData: string): ManagedPrivateKey {
647
- const encodedKey = Convert.base64Url(keyEncodedData).toObject() as EncodedPrivateKey;
648
-
649
- const privateKey = {
650
- ...encodedKey,
651
- material: Convert.base64Url(encodedKey.material).toUint8Array()
652
- } as ManagedPrivateKey;
653
-
654
- return privateKey;
655
- }
656
-
657
- private encodeKey(privateKey: ManagedPrivateKey): Uint8Array {
658
- const encodedKey = {
659
- ...privateKey,
660
- material: Convert.uint8Array(privateKey.material).toBase64Url()
661
- } as EncodedPrivateKey;
662
-
663
- const keyBytes = Convert.object(encodedKey).toUint8Array();
664
-
665
- return keyBytes;
666
- }
667
-
668
- private async getAuthor(options: {
669
- agent: IDManagedAgent,
670
- context?: string
671
- }): Promise<string> {
672
- const { agent, context } = options;
673
-
674
- // If `context` is specified, DWN messages will be signed by this DID.
675
- if (context) return context;
676
-
677
- // If Agent has an agentDid, use it to sign DWN messages.
678
- if (agent.agentDid) return agent.agentDid;
679
-
680
- // If `context` and `agent.agentDid`are undefined, throw error.
681
- throw new Error(`PrivateKeyStoreDwn: Agent property 'agentDid' is undefined and no context was specified.`);
682
- }
683
-
684
- private async getKeyRecords(agent: IDManagedAgent, context?: string): Promise<DwnResponse> {
685
- // Determine which DID to use to author DWN messages.
686
- const authorDid = await this.getAuthor({ agent, context });
687
-
688
- const dwnResponse = await agent.dwnManager.processRequest({
689
- author : authorDid,
690
- target : authorDid,
691
- messageType : 'RecordsQuery',
692
- messageOptions : {
693
- filter: { ...this._keyRecordProperties }
694
- }
695
- });
696
-
697
- return dwnResponse;
698
- }
699
- }
700
-
701
- /**
702
- * An implementation of `ManagedKeyStore` that stores private key
703
- * material in memory.
704
- *
705
- * An instance of this class can be used by an implementation of
706
- * `KeyManagementSystem`.
707
- */
708
- export class PrivateKeyStoreMemory implements ManagedKeyStore<string, ManagedPrivateKey> {
709
- /**
710
- * A private field that contains the Map used as the in-memory key-value store.
711
- */
712
- private store: Map<string, ManagedPrivateKey> = new Map();
713
-
714
- async deleteKey({ id }: { id: string }): Promise<boolean> {
715
- if (this.store.has(id)) {
716
- // Key with given ID exists so proceed with delete.
717
- this.store.delete(id);
718
- return true;
719
- }
720
-
721
- // Key with given ID not present so delete operation not possible.
722
- return false;
723
- }
724
-
725
- async findKey(): Promise<ManagedPrivateKey | undefined> {
726
- throw new Error(`PrivateKeyStoreMemory: Method not implemented: 'findKey'`);
727
- }
728
-
729
- async getKey({ id }: { id: string }): Promise<ManagedPrivateKey | undefined> {
730
- return this.store.get(id);
731
- }
732
-
733
- async importKey({ key }: { key: Omit<ManagedPrivateKey, 'id'> }): Promise<string> {
734
- if (!key.material) throw new TypeError(`Required parameter missing: 'material'`);
735
- if (!key.type) throw new TypeError(`Required parameter missing: 'type'`);
736
-
737
- // Make a deep copy of the key so that the object stored does not share the same references as the input key.
738
- // The private key material is transferred to the new object, making the original obj.material unusable.
739
- const clonedKey = structuredClone(key, { transfer: [key.material.buffer] }) as ManagedPrivateKey;
740
-
741
- clonedKey.id = cryptoUtils.randomUuid();
742
- this.store.set(clonedKey.id, clonedKey);
743
-
744
- return clonedKey.id;
745
- }
746
-
747
- async listKeys(): Promise<ManagedPrivateKey[]> {
748
- return Array.from(this.store.values());
749
- }
750
-
751
- async updateKey(): Promise<boolean> {
752
- throw new Error(`PrivateKeyStoreMemory: Method not implemented: 'updateKey'`);
753
- }
754
- }