@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
package/src/agent/dwn-manager.ts
DELETED
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
GenericMessage,
|
|
3
|
-
MessagesGetReply,
|
|
4
|
-
PrivateKeySigner,
|
|
5
|
-
RecordsWriteMessage,
|
|
6
|
-
RecordsWriteOptions,
|
|
7
|
-
Signer,
|
|
8
|
-
UnionMessageReply,
|
|
9
|
-
} from '@dwn-protocol/id';
|
|
10
|
-
|
|
11
|
-
import { Convert } from '../common/index.js';
|
|
12
|
-
import { Jose } from '../crypto/index.js';
|
|
13
|
-
import { DidResolver } from '../dids/index.js';
|
|
14
|
-
import { Readable } from 'readable-stream';
|
|
15
|
-
import * as didUtils from '../dids/utils.js';
|
|
16
|
-
|
|
17
|
-
import {
|
|
18
|
-
Cid,
|
|
19
|
-
Dwn,
|
|
20
|
-
Message,
|
|
21
|
-
EventsGet,
|
|
22
|
-
DataStream,
|
|
23
|
-
RecordsRead,
|
|
24
|
-
MessagesGet,
|
|
25
|
-
RecordsWrite,
|
|
26
|
-
RecordsQuery,
|
|
27
|
-
DwnMethodName,
|
|
28
|
-
RecordsDelete,
|
|
29
|
-
ProtocolsQuery,
|
|
30
|
-
DwnInterfaceName,
|
|
31
|
-
ProtocolsConfigure,
|
|
32
|
-
EventLogLevel,
|
|
33
|
-
DataStoreLevel,
|
|
34
|
-
MessageStoreLevel,
|
|
35
|
-
} from '@dwn-protocol/id';
|
|
36
|
-
|
|
37
|
-
import type { DwnRpcRequest } from './rpc-client.js';
|
|
38
|
-
import type { DwnResponse, ProcessDwnRequest, SendDwnRequest, IDManagedAgent } from './types/agent.js';
|
|
39
|
-
|
|
40
|
-
import { isManagedKeyPair } from './utils.js';
|
|
41
|
-
import type { OutboxEntryPayload } from './outbox.js';
|
|
42
|
-
import { blobToIsomorphicNodeReadable, webReadableToIsomorphicNodeReadable } from './utils.js';
|
|
43
|
-
|
|
44
|
-
export type GeneralJws = {
|
|
45
|
-
payload: string
|
|
46
|
-
signatures: SignatureEntry[]
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export type SignatureEntry = {
|
|
50
|
-
protected: string
|
|
51
|
-
signature: string
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export type RecordsWriteAuthorizationPayload = {
|
|
55
|
-
recordId: string;
|
|
56
|
-
contextId?: string;
|
|
57
|
-
descriptorCid: string;
|
|
58
|
-
attestationCid?: string;
|
|
59
|
-
encryptionCid?: string;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
type DwnMessage = {
|
|
63
|
-
message: any;
|
|
64
|
-
data?: Blob;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const dwnMessageCreators = {
|
|
68
|
-
[DwnInterfaceName.Events + DwnMethodName.Get] : EventsGet,
|
|
69
|
-
[DwnInterfaceName.Messages + DwnMethodName.Get] : MessagesGet,
|
|
70
|
-
[DwnInterfaceName.Records + DwnMethodName.Read] : RecordsRead,
|
|
71
|
-
[DwnInterfaceName.Records + DwnMethodName.Query] : RecordsQuery,
|
|
72
|
-
[DwnInterfaceName.Records + DwnMethodName.Write] : RecordsWrite,
|
|
73
|
-
[DwnInterfaceName.Records + DwnMethodName.Delete] : RecordsDelete,
|
|
74
|
-
[DwnInterfaceName.Protocols + DwnMethodName.Query] : ProtocolsQuery,
|
|
75
|
-
[DwnInterfaceName.Protocols + DwnMethodName.Configure] : ProtocolsConfigure,
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
export type DwnManagerOptions = {
|
|
79
|
-
agent?: IDManagedAgent;
|
|
80
|
-
dwn: Dwn;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export type DwnManagerCreateOptions = {
|
|
84
|
-
agent?: IDManagedAgent;
|
|
85
|
-
dataPath?: string;
|
|
86
|
-
didResolver?: DidResolver;
|
|
87
|
-
dwn?: Dwn;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export class DwnManager {
|
|
91
|
-
/**
|
|
92
|
-
* Holds the instance of a `IDManagedAgent` that represents the current
|
|
93
|
-
* execution context for the `KeyManager`. This agent is utilized
|
|
94
|
-
* to interact with other agent components. It's vital
|
|
95
|
-
* to ensure this instance is set to correctly contextualize
|
|
96
|
-
* operations within the broader agent framework.
|
|
97
|
-
*/
|
|
98
|
-
private _agent?: IDManagedAgent;
|
|
99
|
-
private _dwn: Dwn;
|
|
100
|
-
|
|
101
|
-
constructor(options: DwnManagerOptions) {
|
|
102
|
-
this._agent = options.agent;
|
|
103
|
-
this._dwn = options.dwn;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Constructs a Signer for the connected did.
|
|
108
|
-
*
|
|
109
|
-
* @param author - The DID.
|
|
110
|
-
* @returns A promise that resolves to the result.
|
|
111
|
-
*/
|
|
112
|
-
async getSigner(author: string): Promise<Signer> {
|
|
113
|
-
const signingKeyId = await this.getAuthorSigningKeyId({ did: author });
|
|
114
|
-
const parsedDid = didUtils.parseDid({ didUrl: signingKeyId });
|
|
115
|
-
if (!parsedDid) throw new Error(`DidIonMethod: Unable to parse DID: ${signingKeyId}`);
|
|
116
|
-
const normalizedDid = parsedDid.did.split(':', 3).join(':');
|
|
117
|
-
const normalizedSigningKeyId = `${normalizedDid}#${parsedDid.fragment}`;
|
|
118
|
-
|
|
119
|
-
const signingKey = await this.agent.keyManager.getKey({ keyRef: normalizedSigningKeyId });
|
|
120
|
-
if (!isManagedKeyPair(signingKey)) {
|
|
121
|
-
throw new Error(`DwnManager: Signing key not found for author: '${author}'`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const { alg } = Jose.webCryptoToJose(signingKey.privateKey.algorithm);
|
|
125
|
-
if (alg === undefined) {
|
|
126
|
-
throw Error(`No algorithm provided to sign with key ID ${signingKeyId}`);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
keyId : signingKeyId,
|
|
131
|
-
algorithm : alg,
|
|
132
|
-
sign : async (content: Uint8Array): Promise<Uint8Array> => {
|
|
133
|
-
return await this.agent.keyManager.sign({
|
|
134
|
-
algorithm : signingKey.privateKey.algorithm,
|
|
135
|
-
data : content,
|
|
136
|
-
keyRef : normalizedSigningKeyId
|
|
137
|
-
});
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Constructs a Private Key Signer for a did.
|
|
144
|
-
*
|
|
145
|
-
* @param author - The DID Object.
|
|
146
|
-
* @returns A promise that resolves to the result.
|
|
147
|
-
*/
|
|
148
|
-
async getPrivateKeySigner(author: any) {
|
|
149
|
-
const signingKeyId = await this.agent.didManager.getDefaultSigningKey({ did: author.did });
|
|
150
|
-
const signingKeyPair = author.keySet.verificationMethodKeys[0];
|
|
151
|
-
// const signingKeyPair = ionDid.keySet.verificationMethodKeys.find(keyPair => keyPair.publicKeyJwk.kid === "#dwn-sig");
|
|
152
|
-
const signingPrivateKeyJwk = signingKeyPair.privateKeyJwk;
|
|
153
|
-
return [new PrivateKeySigner({
|
|
154
|
-
privateJwk : signingPrivateKeyJwk,
|
|
155
|
-
algorithm : signingPrivateKeyJwk.alg,
|
|
156
|
-
keyId : signingKeyId,
|
|
157
|
-
})];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Retrieves the `IDManagedAgent` execution context.
|
|
162
|
-
* If the `agent` instance proprety is undefined, it will throw an error.
|
|
163
|
-
*
|
|
164
|
-
* @returns The `IDManagedAgent` instance that represents the current execution
|
|
165
|
-
* context.
|
|
166
|
-
*
|
|
167
|
-
* @throws Will throw an error if the `agent` instance property is undefined.
|
|
168
|
-
*/
|
|
169
|
-
get agent(): IDManagedAgent {
|
|
170
|
-
if (this._agent === undefined) {
|
|
171
|
-
throw new Error('DidManager: Unable to determine agent execution context.');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return this._agent;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
set agent(agent: IDManagedAgent) {
|
|
178
|
-
this._agent = agent;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
get dwn(): Dwn {
|
|
182
|
-
return this._dwn;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
public static async create(options?: DwnManagerCreateOptions) {
|
|
186
|
-
let { agent, dataPath, didResolver, dwn } = options ?? { };
|
|
187
|
-
|
|
188
|
-
dataPath ??= 'DATA/AGENT';
|
|
189
|
-
|
|
190
|
-
if (dwn === undefined) {
|
|
191
|
-
// Use LevelDB stores (browser-compatible)
|
|
192
|
-
const dataStore = new DataStoreLevel({
|
|
193
|
-
blockstoreLocation: `${dataPath}/DWN_DATASTORE`
|
|
194
|
-
});
|
|
195
|
-
const eventLog = new EventLogLevel({
|
|
196
|
-
location: `${dataPath}/DWN_EVENTLOG`
|
|
197
|
-
});
|
|
198
|
-
const messageStore = new MessageStoreLevel(({
|
|
199
|
-
blockstoreLocation : `${dataPath}/DWN_MESSAGESTORE`,
|
|
200
|
-
indexLocation : `${dataPath}/DWN_MESSAGEINDEX`
|
|
201
|
-
}));
|
|
202
|
-
|
|
203
|
-
// Note: PostgreSQL stores commented out - use environment variable or config to enable
|
|
204
|
-
// const messageStore = new MessageStoreSql(postgresDialect);
|
|
205
|
-
// const dataStore = new DataStoreSql(postgresDialect);
|
|
206
|
-
// const eventLog = new EventLogSql(postgresDialect);
|
|
207
|
-
|
|
208
|
-
dwn = await Dwn.create({
|
|
209
|
-
dataStore,
|
|
210
|
-
//@ts-ignore
|
|
211
|
-
didResolver,
|
|
212
|
-
eventLog,
|
|
213
|
-
messageStore,
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return new DwnManager({ agent, dwn });
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
public async processRequest(request: ProcessDwnRequest): Promise<DwnResponse> {
|
|
221
|
-
const { message, dataStream } = await this.constructDwnMessage({ request });
|
|
222
|
-
|
|
223
|
-
let reply: UnionMessageReply;
|
|
224
|
-
if (request.store !== false) {
|
|
225
|
-
// @ts-ignore
|
|
226
|
-
reply = await this._dwn.processMessage(request.target, message, dataStream);
|
|
227
|
-
} else {
|
|
228
|
-
reply = { status: { code: 202, detail: 'Accepted' }};
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
reply,
|
|
233
|
-
message : message,
|
|
234
|
-
messageCid : await Message.getCid(message)
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
public async sendRequest(request: SendDwnRequest): Promise<DwnResponse> {
|
|
239
|
-
const dwnRpcRequest: Partial<DwnRpcRequest> = { targetDid: request.target };
|
|
240
|
-
let messageData: Blob | Readable | ReadableStream | undefined;
|
|
241
|
-
|
|
242
|
-
if ('messageCid' in request) {
|
|
243
|
-
const { message, data } = await this.getDwnMessage({
|
|
244
|
-
author : request.author,
|
|
245
|
-
messageCid : request.messageCid,
|
|
246
|
-
messageType : request.messageType
|
|
247
|
-
});
|
|
248
|
-
dwnRpcRequest.message = message;
|
|
249
|
-
messageData = data;
|
|
250
|
-
|
|
251
|
-
} else {
|
|
252
|
-
const { message } = await this.constructDwnMessage({ request });
|
|
253
|
-
dwnRpcRequest.message = message;
|
|
254
|
-
messageData = request.dataStream;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (messageData) {
|
|
258
|
-
dwnRpcRequest.data = messageData;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const { didDocument, didResolutionMetadata } = await this.agent.didResolver.resolve(request.target);
|
|
262
|
-
if (!didDocument) {
|
|
263
|
-
const errorCode = `${didResolutionMetadata?.error}: ` || '';
|
|
264
|
-
const defaultMessage = `Unable to resolve target DID: ${request.target}`;
|
|
265
|
-
const errorMessage = didResolutionMetadata?.errorMessage ?? defaultMessage;
|
|
266
|
-
throw new Error(`DwnManager: ${errorCode}${errorMessage}`);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const [ service ] = didUtils.getServices({ didDocument, id: '#dwn' });
|
|
270
|
-
if (!service) {
|
|
271
|
-
throw new Error(`DwnManager: DID Document of '${request.target}' has no service endpoints with ID '#dwn'`);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (!didUtils.isDwnServiceEndpoint(service.serviceEndpoint)) {
|
|
275
|
-
throw new Error(`DwnManager: Malformed '#dwn' service endpoint. Expected array of node addresses.`);
|
|
276
|
-
}
|
|
277
|
-
const dwnEndpointUrls = service.serviceEndpoint.nodes;
|
|
278
|
-
|
|
279
|
-
let dwnReply;
|
|
280
|
-
let errorMessages = [];
|
|
281
|
-
|
|
282
|
-
// try sending to author's publicly addressable dwn's until first request succeeds.
|
|
283
|
-
for (let dwnUrl of dwnEndpointUrls) {
|
|
284
|
-
dwnRpcRequest.dwnUrl = dwnUrl;
|
|
285
|
-
|
|
286
|
-
try {
|
|
287
|
-
dwnReply = await this.agent.rpcClient.sendDwnRequest(dwnRpcRequest as DwnRpcRequest);
|
|
288
|
-
break;
|
|
289
|
-
} catch(error: unknown) {
|
|
290
|
-
const message = (error instanceof Error) ? error.message : 'Unknown error';
|
|
291
|
-
errorMessages.push({ url: dwnUrl, message });
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (!dwnReply) {
|
|
296
|
-
if (this.agent.outbox) {
|
|
297
|
-
const dataBase64 = messageData
|
|
298
|
-
? await this.messageDataToBase64(messageData)
|
|
299
|
-
: undefined;
|
|
300
|
-
await this.agent.outbox.enqueue({
|
|
301
|
-
targetDid: request.target,
|
|
302
|
-
dwnUrls: dwnEndpointUrls,
|
|
303
|
-
message: dwnRpcRequest.message as Record<string, unknown>,
|
|
304
|
-
...(dataBase64 !== undefined && { dataBase64 }),
|
|
305
|
-
} as OutboxEntryPayload);
|
|
306
|
-
return {
|
|
307
|
-
message: dwnRpcRequest.message,
|
|
308
|
-
messageCid: await Message.getCid(dwnRpcRequest.message),
|
|
309
|
-
reply: { status: { code: 202, detail: 'Queued for delivery when online' } },
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
throw new Error(JSON.stringify(errorMessages));
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return {
|
|
316
|
-
message : dwnRpcRequest.message,
|
|
317
|
-
messageCid : await Message.getCid(dwnRpcRequest.message),
|
|
318
|
-
reply : dwnReply,
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
private async messageDataToBase64(
|
|
323
|
-
data: Blob | Readable | ReadableStream
|
|
324
|
-
): Promise<string> {
|
|
325
|
-
if (data instanceof Blob) {
|
|
326
|
-
const u8a = new Uint8Array(await data.arrayBuffer());
|
|
327
|
-
return Convert.uint8Array(u8a).toBase64Url();
|
|
328
|
-
}
|
|
329
|
-
const u8a = await Convert.asyncIterable(data as AsyncIterable<Uint8Array>).toUint8ArrayAsync();
|
|
330
|
-
return Convert.uint8Array(u8a).toBase64Url();
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
private async constructDwnMessage(options: {
|
|
334
|
-
request: ProcessDwnRequest
|
|
335
|
-
}) {
|
|
336
|
-
const { request } = options;
|
|
337
|
-
|
|
338
|
-
let readableStream: Readable | undefined;
|
|
339
|
-
|
|
340
|
-
if (request.messageType === 'RecordsWrite') {
|
|
341
|
-
const messageOptions = request.messageOptions as RecordsWriteOptions;
|
|
342
|
-
|
|
343
|
-
if (request.dataStream && !messageOptions.data) {
|
|
344
|
-
const { dataStream } = request;
|
|
345
|
-
let isomorphicNodeReadable: Readable;
|
|
346
|
-
|
|
347
|
-
if (dataStream instanceof Blob) {
|
|
348
|
-
isomorphicNodeReadable = blobToIsomorphicNodeReadable(dataStream);
|
|
349
|
-
readableStream = blobToIsomorphicNodeReadable(dataStream);
|
|
350
|
-
|
|
351
|
-
} else if (dataStream instanceof ReadableStream) {
|
|
352
|
-
const [ forCid, forProcessMessage ] = dataStream.tee();
|
|
353
|
-
isomorphicNodeReadable = webReadableToIsomorphicNodeReadable(forCid);
|
|
354
|
-
readableStream = webReadableToIsomorphicNodeReadable(forProcessMessage);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// @ts-ignore
|
|
358
|
-
messageOptions.dataCid = await Cid.computeDagPbCidFromStream(isomorphicNodeReadable);
|
|
359
|
-
// @ts-ignore
|
|
360
|
-
messageOptions.dataSize ??= isomorphicNodeReadable['bytesRead'];
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const dwnSigner = await this.constructDwnSigner(request.author);
|
|
365
|
-
|
|
366
|
-
const messageCreator = dwnMessageCreators[request.messageType];
|
|
367
|
-
const dwnMessage = await messageCreator.create({
|
|
368
|
-
...<any>request.messageOptions,
|
|
369
|
-
signer: dwnSigner
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
// return { message: dwnMessage.toJSON(), dataStream: readableStream };
|
|
373
|
-
return { message: dwnMessage.message, dataStream: readableStream };
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
private async getAuthorSigningKeyId(options: {
|
|
377
|
-
did: string
|
|
378
|
-
}): Promise<string> {
|
|
379
|
-
const { did } = options;
|
|
380
|
-
|
|
381
|
-
// Get the method-specific default signing key.
|
|
382
|
-
const signingKeyId = await this.agent.didManager.getDefaultSigningKey({ did });
|
|
383
|
-
|
|
384
|
-
if (!signingKeyId) {
|
|
385
|
-
throw new Error (`DwnManager: Unable to determine signing key for author: '${did}'`);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
return signingKeyId;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
private async constructDwnSigner(author: string): Promise<Signer> {
|
|
392
|
-
const signingKeyId = await this.getAuthorSigningKeyId({ did: author });
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* DID keys stored in KeyManager use the canonicalId as an alias, so
|
|
396
|
-
* normalize the signing key ID before attempting to retrieve the key.
|
|
397
|
-
*/
|
|
398
|
-
const parsedDid = didUtils.parseDid({ didUrl: signingKeyId });
|
|
399
|
-
if (!parsedDid) throw new Error(`DidIonMethod: Unable to parse DID: ${signingKeyId}`);
|
|
400
|
-
const normalizedDid = parsedDid.did.split(':', 3).join(':');
|
|
401
|
-
const normalizedSigningKeyId = `${normalizedDid}#${parsedDid.fragment}`;
|
|
402
|
-
|
|
403
|
-
const signingKey = await this.agent.keyManager.getKey({ keyRef: normalizedSigningKeyId });
|
|
404
|
-
if (!isManagedKeyPair(signingKey)) {
|
|
405
|
-
throw new Error(`DwnManager: Signing key not found for author: '${author}'`);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
const { alg } = Jose.webCryptoToJose(signingKey.privateKey.algorithm);
|
|
409
|
-
if (alg === undefined) {
|
|
410
|
-
throw Error(`No algorithm provided to sign with key ID ${signingKeyId}`);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return {
|
|
414
|
-
keyId : signingKeyId,
|
|
415
|
-
algorithm : alg,
|
|
416
|
-
sign : async (content: Uint8Array): Promise<Uint8Array> => {
|
|
417
|
-
return await this.agent.keyManager.sign({
|
|
418
|
-
algorithm : signingKey.privateKey.algorithm,
|
|
419
|
-
data : content,
|
|
420
|
-
keyRef : normalizedSigningKeyId
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
private async getDwnMessage(options: {
|
|
427
|
-
author: string,
|
|
428
|
-
messageType: string,
|
|
429
|
-
messageCid: string
|
|
430
|
-
}): Promise<DwnMessage> {
|
|
431
|
-
const { author, messageType, messageCid } = options;
|
|
432
|
-
|
|
433
|
-
const dwnSigner = await this.constructDwnSigner(author);
|
|
434
|
-
|
|
435
|
-
const messagesGet = await MessagesGet.create({
|
|
436
|
-
messageCids : [messageCid],
|
|
437
|
-
signer : dwnSigner
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
const result: MessagesGetReply = await this._dwn.processMessage(author, messagesGet.message);
|
|
441
|
-
// @ts-ignore
|
|
442
|
-
if (!(result.messages && result.messages.length === 1)) {
|
|
443
|
-
throw new Error('TODO: message not found');
|
|
444
|
-
}
|
|
445
|
-
// @ts-ignore
|
|
446
|
-
const [ messageEntry ] = result.messages;
|
|
447
|
-
|
|
448
|
-
let { message } = messageEntry;
|
|
449
|
-
if (!message) {
|
|
450
|
-
throw new Error('TODO: message not found');
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
let dwnMessage: DwnMessage = { message };
|
|
454
|
-
|
|
455
|
-
/** If the message is a RecordsWrite, either data will be present, OR
|
|
456
|
-
* we have to fetch it using a RecordsRead. */
|
|
457
|
-
if (messageType === 'RecordsWrite') {
|
|
458
|
-
const { encodedData } = messageEntry;
|
|
459
|
-
const writeMessage = message as RecordsWriteMessage;
|
|
460
|
-
|
|
461
|
-
if (encodedData) {
|
|
462
|
-
const dataBytes: any = Convert.base64Url(encodedData).toUint8Array();
|
|
463
|
-
dwnMessage.data = new Blob([dataBytes]);
|
|
464
|
-
} else {
|
|
465
|
-
const recordsRead = await RecordsRead.create({
|
|
466
|
-
filter: {
|
|
467
|
-
recordId: writeMessage.recordId
|
|
468
|
-
},
|
|
469
|
-
signer: dwnSigner
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
const reply = await this._dwn.processMessage(author, recordsRead.message);
|
|
473
|
-
|
|
474
|
-
if (reply.status.code >= 400) {
|
|
475
|
-
const { status: { code, detail } } = reply;
|
|
476
|
-
throw new Error(`(${code}) Failed to read data associated with record ${writeMessage.recordId}. ${detail}}`);
|
|
477
|
-
} else if (reply.record) {
|
|
478
|
-
const dataBytes: any = await DataStream.toBytes(reply.record.data);
|
|
479
|
-
dwnMessage.data = new Blob([dataBytes]);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
return dwnMessage;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
/**
|
|
488
|
-
* ADDED TO GET SYNC WORKING
|
|
489
|
-
* - createMessage()
|
|
490
|
-
* - processMessage()
|
|
491
|
-
* - writePrunedRecord()
|
|
492
|
-
*/
|
|
493
|
-
|
|
494
|
-
public async createMessage(options: {
|
|
495
|
-
author: string,
|
|
496
|
-
messageOptions: unknown,
|
|
497
|
-
messageType: string
|
|
498
|
-
}): Promise<EventsGet | MessagesGet | RecordsRead | RecordsQuery | RecordsWrite | RecordsDelete | ProtocolsQuery | ProtocolsConfigure> {
|
|
499
|
-
const { author, messageOptions, messageType } = options;
|
|
500
|
-
|
|
501
|
-
const dwnSigner = await this.constructDwnSigner(author);
|
|
502
|
-
|
|
503
|
-
const messageCreator = dwnMessageCreators[messageType];
|
|
504
|
-
|
|
505
|
-
const dwnMessage = await messageCreator.create({
|
|
506
|
-
...<any>messageOptions,
|
|
507
|
-
signer: dwnSigner
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
return dwnMessage;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
/**
|
|
514
|
-
* Writes a pruned initial `RecordsWrite` to a DWN without needing to supply associated data.
|
|
515
|
-
* Note: This method should ONLY be used by a {@link SyncManager} implementation.
|
|
516
|
-
*
|
|
517
|
-
* @param options.targetDid - DID of the DWN tenant to write the pruned RecordsWrite to.
|
|
518
|
-
* @returns DWN reply containing the status of processing request.
|
|
519
|
-
*/
|
|
520
|
-
public async writePrunedRecord(options: {
|
|
521
|
-
targetDid: string,
|
|
522
|
-
message: RecordsWriteMessage
|
|
523
|
-
}): Promise<GenericMessageReply> {
|
|
524
|
-
const { targetDid, message } = options;
|
|
525
|
-
// @ts-ignore
|
|
526
|
-
return await this._dwn.synchronizePrunedInitialRecordsWrite(targetDid, message);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
public async processMessage(options: {
|
|
530
|
-
targetDid: string,
|
|
531
|
-
message: GenericMessage,
|
|
532
|
-
dataStream?: Readable
|
|
533
|
-
}): Promise<UnionMessageReply> {
|
|
534
|
-
const { dataStream, message, targetDid } = options;
|
|
535
|
-
|
|
536
|
-
// @ts-ignore
|
|
537
|
-
return await this._dwn.processMessage(targetDid, message, dataStream);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
type GenericMessageReply = {
|
|
542
|
-
status: Status;
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
type Status = {
|
|
546
|
-
code: number
|
|
547
|
-
detail: string
|
|
548
|
-
};
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import type { PortableDid } from '../dids/index.js';
|
|
2
|
-
import type { IDManagedAgent } from './types/agent.js';
|
|
3
|
-
import type { CreateDidMethodOptions, ManagedDid } from './did-manager.js';
|
|
4
|
-
import type { ManagedIdentityStore } from './store-managed-identity.js';
|
|
5
|
-
|
|
6
|
-
import { IdentityStoreMemory } from './store-managed-identity.js';
|
|
7
|
-
|
|
8
|
-
type CreateWithDid = Required<Pick<CreateIdentityOptions, 'did'>>
|
|
9
|
-
& Pick<CreateIdentityOptions, 'context' | 'name' | 'kms'>
|
|
10
|
-
|
|
11
|
-
type CreateWithDidMethod<M extends DidMethod> = Pick<CreateIdentityOptions, 'context' | 'kms' | 'name'> & {
|
|
12
|
-
didMethod: M;
|
|
13
|
-
didOptions?: CreateDidMethodOptions[M];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type DidMethod = keyof CreateDidMethodOptions;
|
|
17
|
-
|
|
18
|
-
export type CreateIdentityOptions = {
|
|
19
|
-
did?: PortableDid;
|
|
20
|
-
didMethod?: any;
|
|
21
|
-
didOptions?: any;
|
|
22
|
-
context?: string;
|
|
23
|
-
kms?: string;
|
|
24
|
-
name: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type IdentityManagerOptions = {
|
|
28
|
-
agent?: IDManagedAgent;
|
|
29
|
-
store?: ManagedIdentityStore;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export type ImportIdentityOptions = {
|
|
33
|
-
context?: string;
|
|
34
|
-
did?: PortableDid;
|
|
35
|
-
identity: ManagedIdentity;
|
|
36
|
-
kms?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface ManagedIdentity {
|
|
40
|
-
did: string;
|
|
41
|
-
name: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export class IdentityManager {
|
|
45
|
-
/**
|
|
46
|
-
* Holds the instance of a `IDManagedAgent` that represents the current
|
|
47
|
-
* execution context for the `KeyManager`. This agent is utilized
|
|
48
|
-
* to interact with other agent components. It's vital
|
|
49
|
-
* to ensure this instance is set to correctly contextualize
|
|
50
|
-
* operations within the broader agent framework.
|
|
51
|
-
*/
|
|
52
|
-
private _agent?: IDManagedAgent;
|
|
53
|
-
private _store: ManagedIdentityStore;
|
|
54
|
-
|
|
55
|
-
constructor(options?: IdentityManagerOptions) {
|
|
56
|
-
const { agent, store } = options ?? {};
|
|
57
|
-
this._agent = agent;
|
|
58
|
-
this._store = store ?? new IdentityStoreMemory();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Retrieves the `IDManagedAgent` execution context.
|
|
63
|
-
* If the `agent` instance proprety is undefined, it will throw an error.
|
|
64
|
-
*
|
|
65
|
-
* @returns The `IDManagedAgent` instance that represents the current execution
|
|
66
|
-
* context.
|
|
67
|
-
*
|
|
68
|
-
* @throws Will throw an error if the `agent` instance property is undefined.
|
|
69
|
-
*/
|
|
70
|
-
get agent(): IDManagedAgent {
|
|
71
|
-
if (this._agent === undefined) {
|
|
72
|
-
throw new Error('IdentityManager: Unable to determine agent execution context.');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return this._agent;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
set agent(agent: IDManagedAgent) {
|
|
79
|
-
this._agent = agent;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async create<M extends DidMethod>(options: CreateWithDidMethod<M>): Promise<ManagedIdentity>;
|
|
83
|
-
async create(options: CreateWithDid): Promise<ManagedIdentity>;
|
|
84
|
-
async create(options: CreateIdentityOptions): Promise<ManagedIdentity> {
|
|
85
|
-
let { context, did, didMethod, didOptions, kms, name } = options;
|
|
86
|
-
|
|
87
|
-
if (!(didMethod ? !did : did)) {
|
|
88
|
-
throw new Error(`Either 'did' or 'didMethod' must be defined, but not both.`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
let managedDid: ManagedDid | undefined;
|
|
92
|
-
|
|
93
|
-
// Get the agent instance.
|
|
94
|
-
const agent = this.agent;
|
|
95
|
-
|
|
96
|
-
if (didMethod) {
|
|
97
|
-
// Create new DID and generate key set.
|
|
98
|
-
managedDid = await agent.didManager.create({ method: didMethod, context, kms, ...didOptions });
|
|
99
|
-
|
|
100
|
-
} else if (did) {
|
|
101
|
-
// Import given DID and key set.
|
|
102
|
-
managedDid = await agent.didManager.import({ did, context, kms });
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (managedDid === undefined) {
|
|
106
|
-
throw new Error('IdentityManager: Unable to generate or import DID.');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Create a ManagedIdentity.
|
|
110
|
-
const identity: ManagedIdentity = {
|
|
111
|
-
did : managedDid.did,
|
|
112
|
-
name : name
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
/** If context is undefined, then the Identity will be stored under the
|
|
116
|
-
* tenant of the created DID. Otherwise, the Identity records will
|
|
117
|
-
* be stored under the tenant of the specified context. */
|
|
118
|
-
context ??= identity.did;
|
|
119
|
-
|
|
120
|
-
// Store the ManagedIdentity in the store.
|
|
121
|
-
await this._store.importIdentity({ identity, agent, context });
|
|
122
|
-
|
|
123
|
-
return identity;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async get(options: {
|
|
127
|
-
did: string,
|
|
128
|
-
context?: string
|
|
129
|
-
}): Promise<ManagedIdentity | undefined> {
|
|
130
|
-
const { context, did } = options;
|
|
131
|
-
|
|
132
|
-
const identity = this._store.getIdentity({ did, agent: this.agent, context });
|
|
133
|
-
|
|
134
|
-
return identity;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async import(options: ImportIdentityOptions): Promise<ManagedIdentity> {
|
|
138
|
-
let { context, did, identity, kms } = options;
|
|
139
|
-
|
|
140
|
-
// Get the agent instance.
|
|
141
|
-
const agent = this.agent;
|
|
142
|
-
|
|
143
|
-
// If provided, import the given DID and key set.
|
|
144
|
-
if (did) {
|
|
145
|
-
await agent.didManager.import({ did, context, kms });
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** If context is undefined, then the Identity will be stored under the
|
|
149
|
-
* tenant of the imported DID. Otherwise, the Identity record will
|
|
150
|
-
* be stored under the tenant of the specified context. */
|
|
151
|
-
context ??= identity.did;
|
|
152
|
-
|
|
153
|
-
// Store the ManagedIdentity in the store.
|
|
154
|
-
await this._store.importIdentity({ identity, agent, context });
|
|
155
|
-
|
|
156
|
-
return identity;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async list(options?: { context?: string }): Promise<ManagedIdentity[]> {
|
|
160
|
-
const { context } = options ?? {};
|
|
161
|
-
const identities = this._store.listIdentities({ agent: this.agent, context });
|
|
162
|
-
|
|
163
|
-
return identities;
|
|
164
|
-
}
|
|
165
|
-
}
|