@enbox/agent 0.2.2 → 0.3.0
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/dist/browser.mjs +9 -9
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/agent-did-resolver-cache.js.map +1 -1
- package/dist/esm/anonymous-dwn-api.js +1 -1
- package/dist/esm/bearer-identity.js +1 -1
- package/dist/esm/connect.js +3 -3
- package/dist/esm/connect.js.map +1 -1
- package/dist/esm/did-api.js +3 -3
- package/dist/esm/did-api.js.map +1 -1
- package/dist/esm/dwn-api.js +39 -8
- package/dist/esm/dwn-api.js.map +1 -1
- package/dist/esm/dwn-discovery-file.js +244 -0
- package/dist/esm/dwn-discovery-file.js.map +1 -0
- package/dist/esm/dwn-discovery-payload.js +253 -0
- package/dist/esm/dwn-discovery-payload.js.map +1 -0
- package/dist/esm/dwn-encryption.js.map +1 -1
- package/dist/esm/dwn-key-delivery.js.map +1 -1
- package/dist/esm/dwn-record-upgrade.js.map +1 -1
- package/dist/esm/{web5-user-agent.js → enbox-user-agent.js} +12 -7
- package/dist/esm/enbox-user-agent.js.map +1 -0
- package/dist/esm/identity-api.js +3 -3
- package/dist/esm/identity-api.js.map +1 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/local-dwn.js +150 -26
- package/dist/esm/local-dwn.js.map +1 -1
- package/dist/esm/local-key-manager.js +2 -2
- package/dist/esm/local-key-manager.js.map +1 -1
- package/dist/esm/oidc.js +11 -11
- package/dist/esm/oidc.js.map +1 -1
- package/dist/esm/permissions-api.js.map +1 -1
- package/dist/esm/store-data.js.map +1 -1
- package/dist/esm/sync-api.js +2 -2
- package/dist/esm/sync-api.js.map +1 -1
- package/dist/esm/sync-engine-level.js +2 -2
- package/dist/esm/sync-engine-level.js.map +1 -1
- package/dist/esm/test-harness.js +3 -3
- package/dist/esm/test-harness.js.map +1 -1
- package/dist/esm/utils-internal.js +2 -2
- package/dist/types/agent-did-resolver-cache.d.ts +7 -7
- package/dist/types/agent-did-resolver-cache.d.ts.map +1 -1
- package/dist/types/anonymous-dwn-api.d.ts +3 -3
- package/dist/types/anonymous-dwn-api.d.ts.map +1 -1
- package/dist/types/bearer-identity.d.ts +1 -1
- package/dist/types/connect.d.ts +8 -8
- package/dist/types/connect.d.ts.map +1 -1
- package/dist/types/did-api.d.ts +12 -11
- package/dist/types/did-api.d.ts.map +1 -1
- package/dist/types/dwn-api.d.ts +27 -11
- package/dist/types/dwn-api.d.ts.map +1 -1
- package/dist/types/dwn-discovery-file.d.ts +122 -0
- package/dist/types/dwn-discovery-file.d.ts.map +1 -0
- package/dist/types/dwn-discovery-payload.d.ts +105 -0
- package/dist/types/dwn-discovery-payload.d.ts.map +1 -0
- package/dist/types/dwn-encryption.d.ts +8 -8
- package/dist/types/dwn-encryption.d.ts.map +1 -1
- package/dist/types/dwn-key-delivery.d.ts +5 -5
- package/dist/types/dwn-key-delivery.d.ts.map +1 -1
- package/dist/types/dwn-record-upgrade.d.ts +2 -2
- package/dist/types/dwn-record-upgrade.d.ts.map +1 -1
- package/dist/types/{web5-user-agent.d.ts → enbox-user-agent.d.ts} +17 -13
- package/dist/types/enbox-user-agent.d.ts.map +1 -0
- package/dist/types/identity-api.d.ts +10 -10
- package/dist/types/identity-api.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/local-dwn.d.ts +93 -15
- package/dist/types/local-dwn.d.ts.map +1 -1
- package/dist/types/local-key-manager.d.ts +9 -9
- package/dist/types/local-key-manager.d.ts.map +1 -1
- package/dist/types/oidc.d.ts +23 -19
- package/dist/types/oidc.d.ts.map +1 -1
- package/dist/types/permissions-api.d.ts +4 -4
- package/dist/types/permissions-api.d.ts.map +1 -1
- package/dist/types/store-data.d.ts +3 -3
- package/dist/types/store-data.d.ts.map +1 -1
- package/dist/types/store-did.d.ts +2 -2
- package/dist/types/store-did.d.ts.map +1 -1
- package/dist/types/store-identity.d.ts +2 -2
- package/dist/types/store-identity.d.ts.map +1 -1
- package/dist/types/store-key.d.ts +2 -2
- package/dist/types/store-key.d.ts.map +1 -1
- package/dist/types/sync-api.d.ts +9 -9
- package/dist/types/sync-api.d.ts.map +1 -1
- package/dist/types/sync-engine-level.d.ts +9 -9
- package/dist/types/sync-engine-level.d.ts.map +1 -1
- package/dist/types/sync-messages.d.ts +5 -5
- package/dist/types/sync-messages.d.ts.map +1 -1
- package/dist/types/test-harness.d.ts +4 -4
- package/dist/types/test-harness.d.ts.map +1 -1
- package/dist/types/types/agent.d.ts +24 -19
- package/dist/types/types/agent.d.ts.map +1 -1
- package/dist/types/types/identity.d.ts +1 -1
- package/dist/types/types/key-manager.d.ts +2 -2
- package/dist/types/types/key-manager.d.ts.map +1 -1
- package/dist/types/types/sync.d.ts +2 -2
- package/dist/types/types/sync.d.ts.map +1 -1
- package/dist/types/utils-internal.d.ts +4 -4
- package/dist/types/utils-internal.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/agent-did-resolver-cache.ts +8 -8
- package/src/anonymous-dwn-api.ts +4 -4
- package/src/bearer-identity.ts +1 -1
- package/src/connect.ts +12 -12
- package/src/did-api.ts +13 -11
- package/src/dwn-api.ts +61 -16
- package/src/dwn-discovery-file.ts +305 -0
- package/src/dwn-discovery-payload.ts +308 -0
- package/src/dwn-encryption.ts +8 -8
- package/src/dwn-key-delivery.ts +5 -5
- package/src/dwn-record-upgrade.ts +2 -2
- package/src/{web5-user-agent.ts → enbox-user-agent.ts} +26 -16
- package/src/identity-api.ts +11 -11
- package/src/index.ts +3 -1
- package/src/local-dwn.ts +154 -28
- package/src/local-key-manager.ts +10 -10
- package/src/oidc.ts +40 -30
- package/src/permissions-api.ts +5 -5
- package/src/store-data.ts +7 -7
- package/src/store-did.ts +2 -2
- package/src/store-identity.ts +2 -2
- package/src/store-key.ts +2 -2
- package/src/sync-api.ts +10 -10
- package/src/sync-engine-level.ts +12 -12
- package/src/sync-messages.ts +5 -5
- package/src/test-harness.ts +9 -9
- package/src/types/agent.ts +31 -20
- package/src/types/identity.ts +1 -1
- package/src/types/key-manager.ts +2 -2
- package/src/types/sync.ts +2 -2
- package/src/utils-internal.ts +4 -4
- package/dist/esm/web5-user-agent.js.map +0 -1
- package/dist/types/web5-user-agent.d.ts.map +0 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types and utilities for the `dwn://register` discovery protocol.
|
|
3
|
+
*
|
|
4
|
+
* The payload is the JSON data exchanged between the local DWN server
|
|
5
|
+
* (electrobun-dwn) and the requesting app during the `dwn://register`
|
|
6
|
+
* redirect flow. It is encoded as base64url and placed in the URL
|
|
7
|
+
* fragment (`#`) of the callback URL.
|
|
8
|
+
*
|
|
9
|
+
* This module intentionally avoids external dependencies so it can be
|
|
10
|
+
* consumed from any environment (Bun, browser, Electrobun) without
|
|
11
|
+
* triggering transitive dependency resolution issues.
|
|
12
|
+
*
|
|
13
|
+
* @see https://github.com/enboxorg/enbox/issues/586
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// ─── Types ────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The JSON payload delivered via the URL fragment in a `dwn://register`
|
|
21
|
+
* callback redirect.
|
|
22
|
+
*
|
|
23
|
+
* Intentionally minimal — everything beyond the endpoint (version,
|
|
24
|
+
* WebSocket support, etc.) is obtained from `GET {endpoint}/info`.
|
|
25
|
+
*/
|
|
26
|
+
export type DwnDiscoveryPayload = {
|
|
27
|
+
/** Base URL of the running DWN server (e.g. `"http://127.0.0.1:55557"`). */
|
|
28
|
+
endpoint: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parsed result from a `dwn://register` URL.
|
|
33
|
+
*/
|
|
34
|
+
export type DwnRegisterUrlParams = {
|
|
35
|
+
/** The callback URL to redirect to with the discovery payload. */
|
|
36
|
+
callback: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// ─── Constants ────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
/** The URL scheme for DWN discovery protocol handlers. */
|
|
42
|
+
export const DWN_PROTOCOL_SCHEME = 'dwn';
|
|
43
|
+
|
|
44
|
+
/** The `dwn://register` path that triggers the discovery handshake. */
|
|
45
|
+
export const DWN_REGISTER_PATH = 'register';
|
|
46
|
+
|
|
47
|
+
// ─── Register URL construction ───────────────────────────────────
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Build a `dwn://register?callback=<url>` URL that, when opened by the OS,
|
|
51
|
+
* triggers electrobun-dwn (or another `dwn://` scheme handler) to redirect
|
|
52
|
+
* back to `callbackUrl` with the local DWN endpoint in the URL fragment.
|
|
53
|
+
*
|
|
54
|
+
* This is the **trigger** side of the `dwn://register` browser flow.
|
|
55
|
+
* The web app opens this URL (e.g. via `window.open()` or `location.href`),
|
|
56
|
+
* the OS routes it to the registered handler, and the handler redirects
|
|
57
|
+
* back with the discovery payload.
|
|
58
|
+
*
|
|
59
|
+
* @param callbackUrl - The URL to redirect back to after discovery.
|
|
60
|
+
* This should be the current page (or a dedicated callback page) that
|
|
61
|
+
* will read the payload from `window.location.hash`.
|
|
62
|
+
* @returns The `dwn://register?callback=<encoded-url>` URL string.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const registerUrl = buildDwnRegisterUrl('https://myapp.com/callback');
|
|
67
|
+
* // => 'dwn://register?callback=https%3A%2F%2Fmyapp.com%2Fcallback'
|
|
68
|
+
* window.open(registerUrl);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function buildDwnRegisterUrl(callbackUrl: string): string {
|
|
72
|
+
return `${DWN_PROTOCOL_SCHEME}://${DWN_REGISTER_PATH}?callback=${encodeURIComponent(callbackUrl)}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ─── Payload encoding/decoding ───────────────────────────────────
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Encode a {@link DwnDiscoveryPayload} as a base64url string suitable
|
|
79
|
+
* for use in a URL fragment.
|
|
80
|
+
*
|
|
81
|
+
* @param payload - The discovery payload to encode.
|
|
82
|
+
* @returns A base64url-encoded string (no padding).
|
|
83
|
+
*/
|
|
84
|
+
export function encodeDwnDiscoveryPayload(payload: DwnDiscoveryPayload): string {
|
|
85
|
+
const json = JSON.stringify(payload);
|
|
86
|
+
return stringToBase64Url(json);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Decode a base64url-encoded string back into a {@link DwnDiscoveryPayload}.
|
|
91
|
+
*
|
|
92
|
+
* @param encoded - The base64url string from the URL fragment.
|
|
93
|
+
* @returns The parsed payload, or `undefined` if decoding or parsing fails.
|
|
94
|
+
*/
|
|
95
|
+
export function decodeDwnDiscoveryPayload(encoded: string): DwnDiscoveryPayload | undefined {
|
|
96
|
+
try {
|
|
97
|
+
const json = base64UrlToString(encoded);
|
|
98
|
+
const parsed: unknown = JSON.parse(json);
|
|
99
|
+
|
|
100
|
+
if (!isValidPayload(parsed)) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return parsed;
|
|
105
|
+
} catch {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ─── URL parsing ─────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Parse a `dwn://register?callback=<url>` URL into its components.
|
|
114
|
+
*
|
|
115
|
+
* @param url - The full `dwn://register?callback=...` URL.
|
|
116
|
+
* @returns The parsed parameters, or `undefined` if the URL is not a
|
|
117
|
+
* valid `dwn://register` URL or is missing the `callback` parameter.
|
|
118
|
+
*/
|
|
119
|
+
export function parseDwnRegisterUrl(url: string): DwnRegisterUrlParams | undefined {
|
|
120
|
+
try {
|
|
121
|
+
// dwn://register?callback=... is not a standard hierarchical URL, so
|
|
122
|
+
// we parse it manually to avoid URL constructor quirks with custom schemes.
|
|
123
|
+
const schemePrefix = `${DWN_PROTOCOL_SCHEME}://`;
|
|
124
|
+
if (!url.startsWith(schemePrefix)) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const withoutScheme = url.slice(schemePrefix.length);
|
|
129
|
+
|
|
130
|
+
// Split on '?' to separate the path from query parameters.
|
|
131
|
+
const questionIndex = withoutScheme.indexOf('?');
|
|
132
|
+
if (questionIndex === -1) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const path = withoutScheme.slice(0, questionIndex);
|
|
137
|
+
if (path !== DWN_REGISTER_PATH) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const queryString = withoutScheme.slice(questionIndex + 1);
|
|
142
|
+
const params = new URLSearchParams(queryString);
|
|
143
|
+
const callback = params.get('callback');
|
|
144
|
+
|
|
145
|
+
if (!callback || callback.length === 0) {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return { callback };
|
|
150
|
+
} catch {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Build the full callback redirect URL with the discovery payload
|
|
157
|
+
* encoded in the URL fragment.
|
|
158
|
+
*
|
|
159
|
+
* @param callbackUrl - The callback URL from the `dwn://register` request.
|
|
160
|
+
* @param payload - The discovery payload to encode in the fragment.
|
|
161
|
+
* @returns The full redirect URL (e.g. `https://notes.sh/dwn#eyJ...`).
|
|
162
|
+
*/
|
|
163
|
+
export function buildDwnDiscoveryRedirectUrl(
|
|
164
|
+
callbackUrl: string,
|
|
165
|
+
payload: DwnDiscoveryPayload,
|
|
166
|
+
): string {
|
|
167
|
+
const encoded = encodeDwnDiscoveryPayload(payload);
|
|
168
|
+
// Strip any existing fragment from the callback URL before appending ours.
|
|
169
|
+
const base = callbackUrl.split('#')[0];
|
|
170
|
+
return `${base}#${encoded}`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Read a {@link DwnDiscoveryPayload} from a URL's fragment (hash).
|
|
175
|
+
*
|
|
176
|
+
* Intended for use in the browser callback page that receives the
|
|
177
|
+
* redirect from electrobun-dwn.
|
|
178
|
+
*
|
|
179
|
+
* @param url - The full URL including the `#` fragment, or just the
|
|
180
|
+
* fragment string (with or without the leading `#`).
|
|
181
|
+
* @returns The parsed payload, or `undefined` if the fragment is missing
|
|
182
|
+
* or contains an invalid payload.
|
|
183
|
+
*/
|
|
184
|
+
export function readDwnDiscoveryPayloadFromUrl(url: string): DwnDiscoveryPayload | undefined {
|
|
185
|
+
const hashIndex = url.indexOf('#');
|
|
186
|
+
if (hashIndex === -1) {
|
|
187
|
+
// Maybe it's just the fragment without the leading #.
|
|
188
|
+
return decodeDwnDiscoveryPayload(url);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const fragment = url.slice(hashIndex + 1);
|
|
192
|
+
if (fragment.length === 0) {
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return decodeDwnDiscoveryPayload(fragment);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ─── Internal helpers ─────────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Type guard for a valid {@link DwnDiscoveryPayload}.
|
|
203
|
+
*
|
|
204
|
+
* The endpoint MUST point to a loopback address (`127.0.0.1`, `[::1]`,
|
|
205
|
+
* or `localhost`) because the `dwn://register` payload is only intended
|
|
206
|
+
* for local DWN discovery. Accepting arbitrary hostnames would allow a
|
|
207
|
+
* malicious payload to redirect agent traffic to a remote server.
|
|
208
|
+
*
|
|
209
|
+
* @see https://github.com/enboxorg/enbox/issues/633
|
|
210
|
+
*/
|
|
211
|
+
function isValidPayload(value: unknown): value is DwnDiscoveryPayload {
|
|
212
|
+
if (typeof value !== 'object' || value === null) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const record = value as Record<string, unknown>;
|
|
217
|
+
|
|
218
|
+
if (typeof record.endpoint !== 'string' || record.endpoint.length === 0) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (!isLoopbackEndpoint(record.endpoint)) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Returns `true` if the endpoint URL's hostname resolves to a loopback
|
|
231
|
+
* address. Accepts `127.0.0.1`, `::1` (with or without brackets), and
|
|
232
|
+
* `localhost` (bare or with any subdomain suffix, per RFC 6761 §6.3).
|
|
233
|
+
*
|
|
234
|
+
* This is a security boundary: the `dwn://register` redirect flow MUST
|
|
235
|
+
* NOT allow payloads that point to non-local servers.
|
|
236
|
+
*/
|
|
237
|
+
function isLoopbackEndpoint(endpoint: string): boolean {
|
|
238
|
+
try {
|
|
239
|
+
const url = new URL(endpoint);
|
|
240
|
+
const hostname = url.hostname.toLowerCase();
|
|
241
|
+
|
|
242
|
+
// IPv4 loopback: 127.0.0.1
|
|
243
|
+
if (hostname === '127.0.0.1') {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// IPv6 loopback: [::1] — URL.hostname strips the brackets.
|
|
248
|
+
if (hostname === '::1' || hostname === '[::1]') {
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// `localhost` or any subdomain (e.g. `foo.localhost`).
|
|
253
|
+
if (hostname === 'localhost' || hostname.endsWith('.localhost')) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return false;
|
|
258
|
+
} catch {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Encode a UTF-8 string as unpadded base64url (RFC 4648 §5).
|
|
265
|
+
*
|
|
266
|
+
* Uses `TextEncoder` to correctly handle all Unicode code points
|
|
267
|
+
* (including those above U+00FF that `btoa` cannot represent).
|
|
268
|
+
*
|
|
269
|
+
* This module MUST remain dependency-free — no imports from
|
|
270
|
+
* `@enbox/common` or any other package.
|
|
271
|
+
*/
|
|
272
|
+
function stringToBase64Url(input: string): string {
|
|
273
|
+
const bytes = new TextEncoder().encode(input);
|
|
274
|
+
// Build a binary string from the UTF-8 byte array so `btoa` can
|
|
275
|
+
// consume it (btoa only accepts Latin-1 / code points ≤ U+00FF).
|
|
276
|
+
let binary = '';
|
|
277
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
278
|
+
binary += String.fromCharCode(bytes[i]);
|
|
279
|
+
}
|
|
280
|
+
return btoa(binary)
|
|
281
|
+
.replace(/\+/g, '-')
|
|
282
|
+
.replace(/\//g, '_')
|
|
283
|
+
.replace(/=+$/, '');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Decode an unpadded base64url string back to a UTF-8 string.
|
|
288
|
+
*
|
|
289
|
+
* Re-adds padding and swaps base64url characters back to standard
|
|
290
|
+
* base64 before calling `atob`, then feeds the resulting bytes through
|
|
291
|
+
* `TextDecoder` for correct UTF-8 handling.
|
|
292
|
+
*/
|
|
293
|
+
function base64UrlToString(input: string): string {
|
|
294
|
+
// Restore standard base64 alphabet and padding.
|
|
295
|
+
let base64 = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
296
|
+
const remainder = base64.length % 4;
|
|
297
|
+
if (remainder === 2) {
|
|
298
|
+
base64 += '==';
|
|
299
|
+
} else if (remainder === 3) {
|
|
300
|
+
base64 += '=';
|
|
301
|
+
}
|
|
302
|
+
const binary = atob(base64);
|
|
303
|
+
const bytes = new Uint8Array(binary.length);
|
|
304
|
+
for (let i = 0; i < binary.length; i++) {
|
|
305
|
+
bytes[i] = binary.charCodeAt(i);
|
|
306
|
+
}
|
|
307
|
+
return new TextDecoder().decode(bytes);
|
|
308
|
+
}
|
package/src/dwn-encryption.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
} from '@enbox/dwn-sdk-js';
|
|
10
10
|
import type { KeyIdentifier, PublicKeyJwk } from '@enbox/crypto';
|
|
11
11
|
|
|
12
|
-
import type {
|
|
12
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
13
13
|
import type {
|
|
14
14
|
DwnMessageReply,
|
|
15
15
|
ProcessDwnRequest,
|
|
@@ -93,7 +93,7 @@ export async function encryptAndComputeCid(
|
|
|
93
93
|
* @throws If the DID has no keyAgreement verification method or it's not X25519.
|
|
94
94
|
*/
|
|
95
95
|
export async function getEncryptionKeyInfo(
|
|
96
|
-
agent:
|
|
96
|
+
agent: EnboxPlatformAgent,
|
|
97
97
|
didUri: string,
|
|
98
98
|
): Promise<{
|
|
99
99
|
keyId: string;
|
|
@@ -172,7 +172,7 @@ export async function getEncryptionKeyInfo(
|
|
|
172
172
|
* @param iv - Initialization vector
|
|
173
173
|
*/
|
|
174
174
|
export async function deriveContextEncryptionInput(
|
|
175
|
-
agent:
|
|
175
|
+
agent: EnboxPlatformAgent,
|
|
176
176
|
didUri: string,
|
|
177
177
|
contextId: string,
|
|
178
178
|
dek: Uint8Array,
|
|
@@ -208,7 +208,7 @@ export async function deriveContextEncryptionInput(
|
|
|
208
208
|
* @param derivationScheme - The key derivation scheme
|
|
209
209
|
*/
|
|
210
210
|
export function buildKmsDecryptCallback(
|
|
211
|
-
agent:
|
|
211
|
+
agent: EnboxPlatformAgent,
|
|
212
212
|
keyId: string,
|
|
213
213
|
keyUri: KeyIdentifier,
|
|
214
214
|
derivationScheme: typeof KeyDerivationScheme.ProtocolPath | typeof KeyDerivationScheme.ProtocolContext,
|
|
@@ -240,7 +240,7 @@ export function buildKmsDecryptCallback(
|
|
|
240
240
|
* @returns An EncryptionKeyDeriver callback object
|
|
241
241
|
*/
|
|
242
242
|
export async function getEncryptionKeyDeriver(
|
|
243
|
-
agent:
|
|
243
|
+
agent: EnboxPlatformAgent,
|
|
244
244
|
didUri: string,
|
|
245
245
|
): Promise<EncryptionKeyDeriver> {
|
|
246
246
|
const { keyId, keyUri } = await getEncryptionKeyInfo(agent, didUri);
|
|
@@ -266,7 +266,7 @@ export async function getEncryptionKeyDeriver(
|
|
|
266
266
|
* @returns A KeyDecrypter callback object
|
|
267
267
|
*/
|
|
268
268
|
export async function getKeyDecrypter(
|
|
269
|
-
agent:
|
|
269
|
+
agent: EnboxPlatformAgent,
|
|
270
270
|
didUri: string,
|
|
271
271
|
): Promise<KeyDecrypter> {
|
|
272
272
|
const { keyId, keyUri } = await getEncryptionKeyInfo(agent, didUri);
|
|
@@ -311,7 +311,7 @@ export function buildContextKeyDecrypter(
|
|
|
311
311
|
* @param fetchContextKeyRecordFn - Function to fetch context key records from key-delivery protocol
|
|
312
312
|
*/
|
|
313
313
|
export async function resolveKeyDecrypter(
|
|
314
|
-
agent:
|
|
314
|
+
agent: EnboxPlatformAgent,
|
|
315
315
|
authorDid: string,
|
|
316
316
|
recordsWrite: RecordsWriteMessage,
|
|
317
317
|
targetDid: string | undefined,
|
|
@@ -409,7 +409,7 @@ export async function resolveKeyDecrypter(
|
|
|
409
409
|
export async function maybeDecryptReply<T extends DwnInterface>(
|
|
410
410
|
request: ProcessDwnRequest<T> | SendDwnRequest<T>,
|
|
411
411
|
reply: DwnMessageReply[T],
|
|
412
|
-
agent:
|
|
412
|
+
agent: EnboxPlatformAgent,
|
|
413
413
|
contextDerivedKeyCache: { get(key: string): DerivedPrivateJwk | undefined; set(key: string, value: DerivedPrivateJwk): void },
|
|
414
414
|
fetchContextKeyRecordFn: (params: {
|
|
415
415
|
ownerDid: string;
|
package/src/dwn-key-delivery.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
RecordsReadReply,
|
|
7
7
|
} from '@enbox/dwn-sdk-js';
|
|
8
8
|
|
|
9
|
-
import type {
|
|
9
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
10
10
|
import type {
|
|
11
11
|
DwnMessage,
|
|
12
12
|
DwnMessageReply,
|
|
@@ -65,7 +65,7 @@ type ProcessRequestFn = <T extends DwnInterface>(
|
|
|
65
65
|
* @param installedCache - Cache for installation status
|
|
66
66
|
*/
|
|
67
67
|
export async function ensureKeyDeliveryProtocol(
|
|
68
|
-
agent:
|
|
68
|
+
agent: EnboxPlatformAgent,
|
|
69
69
|
tenantDid: string,
|
|
70
70
|
processRequest: ProcessRequestFn,
|
|
71
71
|
getProtocolDefinition: (tenantDid: string, protocolUri: string) => Promise<any>,
|
|
@@ -120,7 +120,7 @@ export async function ensureKeyDeliveryProtocol(
|
|
|
120
120
|
* @returns The recordId of the written contextKey record
|
|
121
121
|
*/
|
|
122
122
|
export async function writeContextKeyRecord(
|
|
123
|
-
agent:
|
|
123
|
+
agent: EnboxPlatformAgent,
|
|
124
124
|
params: WriteContextKeyParams,
|
|
125
125
|
processRequest: ProcessRequestFn,
|
|
126
126
|
ensureProtocol: (tenantDid: string) => Promise<void>,
|
|
@@ -221,7 +221,7 @@ export async function writeContextKeyRecord(
|
|
|
221
221
|
* @param getDwnEndpointUrlsForTarget - Function to resolve DWN endpoint URLs (with local discovery)
|
|
222
222
|
*/
|
|
223
223
|
export async function eagerSendContextKeyRecord(
|
|
224
|
-
agent:
|
|
224
|
+
agent: EnboxPlatformAgent,
|
|
225
225
|
tenantDid: string,
|
|
226
226
|
contextKeyMessage: DwnMessage[DwnInterface.RecordsWrite],
|
|
227
227
|
getDwnMessage: (params: { author: string; messageType: DwnInterface; messageCid: string }) => Promise<{ message: any; data?: Blob }>,
|
|
@@ -271,7 +271,7 @@ export async function eagerSendContextKeyRecord(
|
|
|
271
271
|
* @returns The decrypted `DerivedPrivateJwk`, or `undefined` if no matching record found
|
|
272
272
|
*/
|
|
273
273
|
export async function fetchContextKeyRecord(
|
|
274
|
-
agent:
|
|
274
|
+
agent: EnboxPlatformAgent,
|
|
275
275
|
params: FetchContextKeyParams,
|
|
276
276
|
processRequest: ProcessRequestFn,
|
|
277
277
|
getSigner: (author: string) => Promise<any>,
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
} from '@enbox/dwn-sdk-js';
|
|
9
9
|
|
|
10
10
|
import type { DwnSigner } from './types/dwn.js';
|
|
11
|
-
import type {
|
|
11
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
Encoder,
|
|
@@ -42,7 +42,7 @@ import { DwnInterface, dwnMessageConstructors } from './types/dwn.js';
|
|
|
42
42
|
* @param contextKeyCache - Cache for context key info
|
|
43
43
|
*/
|
|
44
44
|
export async function upgradeExternalRootRecord(
|
|
45
|
-
agent:
|
|
45
|
+
agent: EnboxPlatformAgent,
|
|
46
46
|
tenantDid: string,
|
|
47
47
|
recordsWrite: RecordsWriteMessage,
|
|
48
48
|
dwn: Dwn,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AgentKeyManager } from './types/key-manager.js';
|
|
2
2
|
import type { BearerDid } from '@enbox/dids';
|
|
3
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
4
|
+
import type { EnboxRpc } from '@enbox/dwn-clients';
|
|
3
5
|
import type { LocalDwnStrategy } from './local-dwn.js';
|
|
4
|
-
import type { Web5PlatformAgent } from './types/agent.js';
|
|
5
|
-
import type { Web5Rpc } from '@enbox/dwn-clients';
|
|
6
6
|
import type { DidInterface, DidRequest, DidResponse } from './did-api.js';
|
|
7
7
|
import type { DwnInterface, DwnResponse, ProcessDwnRequest, SendDwnRequest } from './types/dwn.js';
|
|
8
8
|
import type { ProcessVcRequest, SendVcRequest, VcResponse } from './types/vc.js';
|
|
@@ -17,15 +17,15 @@ import { AgentSyncApi } from './sync-api.js';
|
|
|
17
17
|
import { DwnDidStore } from './store-did.js';
|
|
18
18
|
import { DwnIdentityStore } from './store-identity.js';
|
|
19
19
|
import { DwnKeyStore } from './store-key.js';
|
|
20
|
+
import { EnboxRpcClient } from '@enbox/dwn-clients';
|
|
20
21
|
import { HdIdentityVault } from './hd-identity-vault.js';
|
|
21
22
|
import { LevelStore } from '@enbox/common';
|
|
22
23
|
import { LocalKeyManager } from './local-key-manager.js';
|
|
23
24
|
import { SyncEngineLevel } from './sync-engine-level.js';
|
|
24
|
-
import { Web5RpcClient } from '@enbox/dwn-clients';
|
|
25
25
|
import { DidDht, DidJwk } from '@enbox/dids';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Initialization parameters for {@link
|
|
28
|
+
* Initialization parameters for {@link EnboxUserAgent}, including an optional recovery phrase that
|
|
29
29
|
* can be used to derive keys to encrypt the vault and generate a DID.
|
|
30
30
|
*/
|
|
31
31
|
export type AgentInitializeParams = {
|
|
@@ -46,10 +46,10 @@ export type AgentInitializeParams = {
|
|
|
46
46
|
recoveryPhrase?: string;
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Optional dwnEndpoints to register didService endpoints during
|
|
49
|
+
* Optional dwnEndpoints to register didService endpoints during EnboxUserAgent initialization
|
|
50
50
|
*
|
|
51
51
|
* The dwnEndpoints are used to register DWN endpoints against the agent DID created during
|
|
52
|
-
*
|
|
52
|
+
* EnboxUserAgent.initialize() => DidDht.create(). This allows the
|
|
53
53
|
* agent to properly recover connectedDids from DWN. Also, this pattern can be used on the server
|
|
54
54
|
* side in place of the agentDid-->connectedDids pattern.
|
|
55
55
|
*/
|
|
@@ -64,7 +64,7 @@ export type AgentStartParams = {
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
export type AgentParams<TKeyManager extends AgentKeyManager = LocalKeyManager> = {
|
|
67
|
-
/** Optional. The Decentralized Identifier (DID) representing this
|
|
67
|
+
/** Optional. The Decentralized Identifier (DID) representing this Enbox User Agent. */
|
|
68
68
|
agentDid?: BearerDid;
|
|
69
69
|
/** Encrypted vault used for managing the Agent's DID and associated keys. */
|
|
70
70
|
agentVault: HdIdentityVault;
|
|
@@ -82,8 +82,8 @@ export type AgentParams<TKeyManager extends AgentKeyManager = LocalKeyManager> =
|
|
|
82
82
|
keyManager: TKeyManager;
|
|
83
83
|
/** Facilitates fetching, requesting, creating, revoking and validating revocation status of permissions */
|
|
84
84
|
permissionsApi: AgentPermissionsApi;
|
|
85
|
-
/** Remote procedure call (RPC) client used to communicate with other
|
|
86
|
-
rpcClient:
|
|
85
|
+
/** Remote procedure call (RPC) client used to communicate with other Enbox services. */
|
|
86
|
+
rpcClient: EnboxRpc;
|
|
87
87
|
/** Facilitates data synchronization of DWN records between nodes. */
|
|
88
88
|
syncApi: AgentSyncApi;
|
|
89
89
|
};
|
|
@@ -92,14 +92,14 @@ export type CreateUserAgentParams = Partial<AgentParams> & {
|
|
|
92
92
|
localDwnStrategy?: LocalDwnStrategy;
|
|
93
93
|
};
|
|
94
94
|
|
|
95
|
-
export class
|
|
95
|
+
export class EnboxUserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager> implements EnboxPlatformAgent<TKeyManager> {
|
|
96
96
|
public crypto: AgentCryptoApi;
|
|
97
97
|
public did: AgentDidApi<TKeyManager>;
|
|
98
98
|
public dwn: AgentDwnApi;
|
|
99
99
|
public identity: AgentIdentityApi<TKeyManager>;
|
|
100
100
|
public keyManager: TKeyManager;
|
|
101
101
|
public permissions: AgentPermissionsApi;
|
|
102
|
-
public rpc:
|
|
102
|
+
public rpc: EnboxRpc;
|
|
103
103
|
public sync: AgentSyncApi;
|
|
104
104
|
public vault: HdIdentityVault;
|
|
105
105
|
|
|
@@ -129,7 +129,7 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
129
129
|
get agentDid(): BearerDid {
|
|
130
130
|
if (this._agentDid === undefined) {
|
|
131
131
|
throw new Error(
|
|
132
|
-
'
|
|
132
|
+
'EnboxUserAgent: The "agentDid" property is not set. Ensure the agent is properly ' +
|
|
133
133
|
'initialized and a DID is assigned.'
|
|
134
134
|
);
|
|
135
135
|
}
|
|
@@ -148,7 +148,7 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
148
148
|
localDwnStrategy,
|
|
149
149
|
agentDid, agentVault, cryptoApi, didApi, dwnApi, identityApi, keyManager, permissionsApi, rpcClient, syncApi
|
|
150
150
|
}: CreateUserAgentParams = {}
|
|
151
|
-
): Promise<
|
|
151
|
+
): Promise<EnboxUserAgent> {
|
|
152
152
|
|
|
153
153
|
agentVault ??= new HdIdentityVault({
|
|
154
154
|
keyDerivationWorkFactor : 210_000,
|
|
@@ -177,12 +177,12 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
177
177
|
|
|
178
178
|
permissionsApi ??= new AgentPermissionsApi();
|
|
179
179
|
|
|
180
|
-
rpcClient ??= new
|
|
180
|
+
rpcClient ??= new EnboxRpcClient();
|
|
181
181
|
|
|
182
182
|
syncApi ??= new AgentSyncApi({ syncEngine: new SyncEngineLevel({ dataPath }) });
|
|
183
183
|
|
|
184
184
|
// Instantiate the Agent using the provided or default components.
|
|
185
|
-
return new
|
|
185
|
+
return new EnboxUserAgent({
|
|
186
186
|
agentDid,
|
|
187
187
|
agentVault,
|
|
188
188
|
cryptoApi,
|
|
@@ -206,7 +206,7 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
206
206
|
*
|
|
207
207
|
* This method is typically called once, the first time the Agent is launched, and is responsible
|
|
208
208
|
* for setting up the agent's operational environment, cryptographic key material, and readiness
|
|
209
|
-
* for processing
|
|
209
|
+
* for processing requests.
|
|
210
210
|
*
|
|
211
211
|
* The password is used to secure the Agent vault, and the recovery phrase is used to derive the
|
|
212
212
|
* cryptographic keys for the vault. If a recovery phrase is not provided, a new recovery phrase
|
|
@@ -261,3 +261,13 @@ export class Web5UserAgent<TKeyManager extends AgentKeyManager = LocalKeyManager
|
|
|
261
261
|
this.agentDid = await this.vault.getDid();
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
+
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
// Deprecated aliases — migration aid
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
/** @deprecated Use {@link EnboxUserAgent} instead. Will be removed in a future version. */
|
|
270
|
+
export const Web5UserAgent = EnboxUserAgent;
|
|
271
|
+
|
|
272
|
+
/** @deprecated Use {@link EnboxUserAgent} instead. Will be removed in a future version. */
|
|
273
|
+
export type Web5UserAgent = EnboxUserAgent;
|
package/src/identity-api.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { RequireOnly } from '@enbox/common';
|
|
|
3
3
|
import type { AgentDataStore } from './store-data.js';
|
|
4
4
|
import type { AgentKeyManager } from './types/key-manager.js';
|
|
5
5
|
import type { DidMethodCreateOptions } from './did-api.js';
|
|
6
|
-
import type {
|
|
6
|
+
import type { EnboxPlatformAgent } from './types/agent.js';
|
|
7
7
|
import type { IdentityMetadata, PortableIdentity } from './types/identity.js';
|
|
8
8
|
|
|
9
9
|
import { isPortableDid } from '@enbox/dids';
|
|
@@ -12,7 +12,7 @@ import { BearerIdentity } from './bearer-identity.js';
|
|
|
12
12
|
import { InMemoryIdentityStore } from './store-identity.js';
|
|
13
13
|
|
|
14
14
|
export interface IdentityApiParams<TKeyManager extends AgentKeyManager> {
|
|
15
|
-
agent?:
|
|
15
|
+
agent?: EnboxPlatformAgent<TKeyManager>;
|
|
16
16
|
|
|
17
17
|
store?: AgentDataStore<IdentityMetadata>;
|
|
18
18
|
}
|
|
@@ -36,7 +36,7 @@ export function isPortableIdentity(obj: unknown): obj is PortableIdentity {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* This API is used to manage and interact with Identities within the
|
|
39
|
+
* This API is used to manage and interact with Identities within the Enbox Agent framework.
|
|
40
40
|
* An Identity is a DID that is associated with metadata that describes the Identity.
|
|
41
41
|
* Metadata includes A name(label), and whether or not the Identity is connected (delegated to act on the behalf of another DID).
|
|
42
42
|
*
|
|
@@ -47,12 +47,12 @@ export function isPortableIdentity(obj: unknown): obj is PortableIdentity {
|
|
|
47
47
|
*/
|
|
48
48
|
export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyManager> {
|
|
49
49
|
/**
|
|
50
|
-
* Holds the instance of a `
|
|
51
|
-
* the `AgentIdentityApi`. This agent is used to interact with other
|
|
50
|
+
* Holds the instance of a `EnboxPlatformAgent` that represents the current execution context for
|
|
51
|
+
* the `AgentIdentityApi`. This agent is used to interact with other Enbox agent components. It's
|
|
52
52
|
* vital to ensure this instance is set to correctly contextualize operations within the broader
|
|
53
|
-
*
|
|
53
|
+
* Enbox Agent framework.
|
|
54
54
|
*/
|
|
55
|
-
private _agent?:
|
|
55
|
+
private _agent?: EnboxPlatformAgent<TKeyManager>;
|
|
56
56
|
|
|
57
57
|
private _store: AgentDataStore<IdentityMetadata>;
|
|
58
58
|
|
|
@@ -64,12 +64,12 @@ export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyMana
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* Retrieves the `
|
|
67
|
+
* Retrieves the `EnboxPlatformAgent` execution context.
|
|
68
68
|
*
|
|
69
|
-
* @returns The `
|
|
69
|
+
* @returns The `EnboxPlatformAgent` instance that represents the current execution context.
|
|
70
70
|
* @throws Will throw an error if the `agent` instance property is undefined.
|
|
71
71
|
*/
|
|
72
|
-
get agent():
|
|
72
|
+
get agent(): EnboxPlatformAgent<TKeyManager> {
|
|
73
73
|
if (this._agent === undefined) {
|
|
74
74
|
throw new Error('AgentIdentityApi: Unable to determine agent execution context.');
|
|
75
75
|
}
|
|
@@ -77,7 +77,7 @@ export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyMana
|
|
|
77
77
|
return this._agent;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
set agent(agent:
|
|
80
|
+
set agent(agent: EnboxPlatformAgent<TKeyManager>) {
|
|
81
81
|
this._agent = agent;
|
|
82
82
|
}
|
|
83
83
|
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,8 @@ export * from './bearer-identity.js';
|
|
|
13
13
|
export * from './crypto-api.js';
|
|
14
14
|
export * from './did-api.js';
|
|
15
15
|
export * from './dwn-api.js';
|
|
16
|
+
export * from './dwn-discovery-file.js';
|
|
17
|
+
export * from './dwn-discovery-payload.js';
|
|
16
18
|
export * from './dwn-encryption.js';
|
|
17
19
|
export * from './dwn-key-delivery.js';
|
|
18
20
|
export * from './dwn-record-upgrade.js';
|
|
@@ -33,4 +35,4 @@ export * from './test-harness.js';
|
|
|
33
35
|
export * from './utils.js';
|
|
34
36
|
export * from './connect.js';
|
|
35
37
|
export * from './oidc.js';
|
|
36
|
-
export * from './
|
|
38
|
+
export * from './enbox-user-agent.js';
|