@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.
- package/package.json +2 -3
- package/src/agent/app-data-store.ts +0 -365
- package/src/agent/did-manager.ts +0 -393
- package/src/agent/dwn-manager.ts +0 -548
- package/src/agent/identity-manager.ts +0 -165
- package/src/agent/index.ts +0 -19
- package/src/agent/json-rpc.ts +0 -107
- package/src/agent/key-manager.ts +0 -302
- package/src/agent/kms-local.ts +0 -412
- package/src/agent/outbox.ts +0 -128
- package/src/agent/rpc-client.ts +0 -223
- package/src/agent/store-managed-did.ts +0 -295
- package/src/agent/store-managed-identity.ts +0 -243
- package/src/agent/store-managed-key.ts +0 -754
- package/src/agent/sync-manager.ts +0 -631
- package/src/agent/test-managed-agent.ts +0 -299
- package/src/agent/types/agent.ts +0 -145
- package/src/agent/types/managed-key.ts +0 -442
- package/src/agent/utils.ts +0 -190
- package/src/common/convert.ts +0 -424
- package/src/common/index.ts +0 -9
- package/src/common/multicodec.ts +0 -176
- package/src/common/object.ts +0 -43
- package/src/common/stores.ts +0 -125
- package/src/common/stream-node.ts +0 -381
- package/src/common/stream.ts +0 -406
- package/src/common/type-utils.ts +0 -117
- package/src/common/types.ts +0 -48
- package/src/credentials/credential-bbs.ts +0 -419
- package/src/credentials/credential.ts +0 -324
- package/src/credentials/index.ts +0 -5
- package/src/credentials/presentation.ts +0 -182
- package/src/credentials/status-list.ts +0 -365
- package/src/credentials/utils.ts +0 -58
- package/src/credentials/validators.ts +0 -52
- package/src/crypto/algorithms-api/aes/base.ts +0 -49
- package/src/crypto/algorithms-api/aes/ctr.ts +0 -51
- package/src/crypto/algorithms-api/aes/index.ts +0 -2
- package/src/crypto/algorithms-api/crypto-algorithm.ts +0 -127
- package/src/crypto/algorithms-api/crypto-key.ts +0 -56
- package/src/crypto/algorithms-api/ec/base.ts +0 -39
- package/src/crypto/algorithms-api/ec/ecdh.ts +0 -53
- package/src/crypto/algorithms-api/ec/ecdsa.ts +0 -37
- package/src/crypto/algorithms-api/ec/eddsa.ts +0 -30
- package/src/crypto/algorithms-api/ec/index.ts +0 -4
- package/src/crypto/algorithms-api/errors.ts +0 -29
- package/src/crypto/algorithms-api/index.ts +0 -6
- package/src/crypto/algorithms-api/pbkdf/index.ts +0 -1
- package/src/crypto/algorithms-api/pbkdf/pbkdf2.ts +0 -91
- package/src/crypto/crypto-algorithms/aes-ctr.ts +0 -70
- package/src/crypto/crypto-algorithms/bbs.ts +0 -110
- package/src/crypto/crypto-algorithms/ecdh.ts +0 -115
- package/src/crypto/crypto-algorithms/ecdsa.ts +0 -111
- package/src/crypto/crypto-algorithms/eddsa.ts +0 -110
- package/src/crypto/crypto-algorithms/index.ts +0 -6
- package/src/crypto/crypto-algorithms/pbkdf2.ts +0 -54
- package/src/crypto/crypto-primitives/aes-ctr.ts +0 -131
- package/src/crypto/crypto-primitives/aes-gcm.ts +0 -138
- package/src/crypto/crypto-primitives/bbs.ts +0 -183
- package/src/crypto/crypto-primitives/concat-kdf.ts +0 -207
- package/src/crypto/crypto-primitives/ed25519.ts +0 -201
- package/src/crypto/crypto-primitives/index.ts +0 -10
- package/src/crypto/crypto-primitives/pbkdf2.ts +0 -78
- package/src/crypto/crypto-primitives/secp256k1.ts +0 -322
- package/src/crypto/crypto-primitives/x25519.ts +0 -101
- package/src/crypto/crypto-primitives/xchacha20-poly1305.ts +0 -46
- package/src/crypto/crypto-primitives/xchacha20.ts +0 -34
- package/src/crypto/index.ts +0 -8
- package/src/crypto/jose.ts +0 -948
- package/src/crypto/types/crypto-key.ts +0 -4
- package/src/crypto/types/iddwn-crypto.ts +0 -119
- package/src/crypto/utils.ts +0 -200
- package/src/did-api.ts +0 -72
- package/src/dids/dht.ts +0 -412
- package/src/dids/did-dht.ts +0 -436
- package/src/dids/did-ion.ts +0 -613
- package/src/dids/did-key.ts +0 -791
- package/src/dids/did-resolver.ts +0 -107
- package/src/dids/index.ts +0 -9
- package/src/dids/resolver-cache-level.ts +0 -82
- package/src/dids/resolver-cache-noop.ts +0 -25
- package/src/dids/types.ts +0 -278
- package/src/dids/utils.ts +0 -129
- package/src/dwn-api.ts +0 -584
- package/src/iddwn.ts +0 -241
- package/src/identity-agent/index.ts +0 -270
- package/src/index.ts +0 -26
- package/src/interfaces/metadata.ts +0 -163
- package/src/interfaces/queue.ts +0 -108
- package/src/interfaces/services.ts +0 -122
- package/src/interfaces/transactions.ts +0 -220
- package/src/protocol.ts +0 -68
- package/src/proxy-agent/index.ts +0 -255
- package/src/record.ts +0 -521
- package/src/service-options.ts +0 -62
- package/src/typings/decentralized-identity__ion-pow-sdk.d.ts +0 -7
- package/src/user-agent/index.ts +0 -295
- package/src/utils.ts +0 -29
- 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
|
-
}
|