@enbox/dids 0.0.1
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/LICENSE +201 -0
- package/README.md +1 -0
- package/dist/browser.js +77 -0
- package/dist/browser.js.map +7 -0
- package/dist/browser.mjs +77 -0
- package/dist/browser.mjs.map +7 -0
- package/dist/cjs/index.js +6303 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/utils.js +245 -0
- package/dist/cjs/utils.js.map +7 -0
- package/dist/esm/bearer-did.js +201 -0
- package/dist/esm/bearer-did.js.map +1 -0
- package/dist/esm/did-error.js +62 -0
- package/dist/esm/did-error.js.map +1 -0
- package/dist/esm/did.js +114 -0
- package/dist/esm/did.js.map +1 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/methods/did-dht.js +1241 -0
- package/dist/esm/methods/did-dht.js.map +1 -0
- package/dist/esm/methods/did-ion.js +570 -0
- package/dist/esm/methods/did-ion.js.map +1 -0
- package/dist/esm/methods/did-jwk.js +298 -0
- package/dist/esm/methods/did-jwk.js.map +1 -0
- package/dist/esm/methods/did-key.js +983 -0
- package/dist/esm/methods/did-key.js.map +1 -0
- package/dist/esm/methods/did-method.js +53 -0
- package/dist/esm/methods/did-method.js.map +1 -0
- package/dist/esm/methods/did-web.js +83 -0
- package/dist/esm/methods/did-web.js.map +1 -0
- package/dist/esm/resolver/resolver-cache-level.js +101 -0
- package/dist/esm/resolver/resolver-cache-level.js.map +1 -0
- package/dist/esm/resolver/resolver-cache-noop.js +24 -0
- package/dist/esm/resolver/resolver-cache-noop.js.map +1 -0
- package/dist/esm/resolver/universal-resolver.js +187 -0
- package/dist/esm/resolver/universal-resolver.js.map +1 -0
- package/dist/esm/types/did-core.js +51 -0
- package/dist/esm/types/did-core.js.map +1 -0
- package/dist/esm/types/did-resolution.js +12 -0
- package/dist/esm/types/did-resolution.js.map +1 -0
- package/dist/esm/types/multibase.js +2 -0
- package/dist/esm/types/multibase.js.map +1 -0
- package/dist/esm/types/portable-did.js +2 -0
- package/dist/esm/types/portable-did.js.map +1 -0
- package/dist/esm/utils.js +458 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/types/bearer-did.d.ts +143 -0
- package/dist/types/bearer-did.d.ts.map +1 -0
- package/dist/types/did-error.d.ts +50 -0
- package/dist/types/did-error.d.ts.map +1 -0
- package/dist/types/did.d.ts +125 -0
- package/dist/types/did.d.ts.map +1 -0
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/methods/did-dht.d.ts +682 -0
- package/dist/types/methods/did-dht.d.ts.map +1 -0
- package/dist/types/methods/did-ion.d.ts +492 -0
- package/dist/types/methods/did-ion.d.ts.map +1 -0
- package/dist/types/methods/did-jwk.d.ts +236 -0
- package/dist/types/methods/did-jwk.d.ts.map +1 -0
- package/dist/types/methods/did-key.d.ts +499 -0
- package/dist/types/methods/did-key.d.ts.map +1 -0
- package/dist/types/methods/did-method.d.ts +238 -0
- package/dist/types/methods/did-method.d.ts.map +1 -0
- package/dist/types/methods/did-web.d.ts +37 -0
- package/dist/types/methods/did-web.d.ts.map +1 -0
- package/dist/types/resolver/resolver-cache-level.d.ts +86 -0
- package/dist/types/resolver/resolver-cache-level.d.ts.map +1 -0
- package/dist/types/resolver/resolver-cache-noop.d.ts +9 -0
- package/dist/types/resolver/resolver-cache-noop.d.ts.map +1 -0
- package/dist/types/resolver/universal-resolver.d.ts +109 -0
- package/dist/types/resolver/universal-resolver.d.ts.map +1 -0
- package/dist/types/types/did-core.d.ts +523 -0
- package/dist/types/types/did-core.d.ts.map +1 -0
- package/dist/types/types/did-resolution.d.ts +85 -0
- package/dist/types/types/did-resolution.d.ts.map +1 -0
- package/dist/types/types/multibase.d.ts +28 -0
- package/dist/types/types/multibase.d.ts.map +1 -0
- package/dist/types/types/portable-did.d.ts +59 -0
- package/dist/types/types/portable-did.d.ts.map +1 -0
- package/dist/types/utils.d.ts +378 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/utils.js +28 -0
- package/dist/utils.js.map +7 -0
- package/package.json +116 -0
- package/src/bearer-did.ts +287 -0
- package/src/did-error.ts +75 -0
- package/src/did.ts +186 -0
- package/src/index.ts +21 -0
- package/src/methods/did-dht.ts +1637 -0
- package/src/methods/did-ion.ts +887 -0
- package/src/methods/did-jwk.ts +410 -0
- package/src/methods/did-key.ts +1248 -0
- package/src/methods/did-method.ts +276 -0
- package/src/methods/did-web.ts +96 -0
- package/src/resolver/resolver-cache-level.ts +163 -0
- package/src/resolver/resolver-cache-noop.ts +26 -0
- package/src/resolver/universal-resolver.ts +238 -0
- package/src/types/did-core.ts +580 -0
- package/src/types/did-resolution.ts +93 -0
- package/src/types/multibase.ts +29 -0
- package/src/types/portable-did.ts +64 -0
- package/src/utils.ts +532 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CryptoApi,
|
|
3
|
+
LocalKeyManager,
|
|
4
|
+
InferKeyGeneratorAlgorithm,
|
|
5
|
+
} from '@enbox/crypto';
|
|
6
|
+
|
|
7
|
+
import type { BearerDid } from '../bearer-did.js';
|
|
8
|
+
import type { DidMetadata } from '../types/portable-did.js';
|
|
9
|
+
import type {
|
|
10
|
+
DidDocument,
|
|
11
|
+
DidResolutionResult,
|
|
12
|
+
DidResolutionOptions,
|
|
13
|
+
DidVerificationMethod,
|
|
14
|
+
} from '../types/did-core.js';
|
|
15
|
+
|
|
16
|
+
import { DidVerificationRelationship } from '../types/did-core.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Represents options during the creation of a Decentralized Identifier (DID).
|
|
20
|
+
*
|
|
21
|
+
* Implementations of this interface may contain properties and methods that provide specific
|
|
22
|
+
* options or metadata during the DID creation processes following specific DID method
|
|
23
|
+
* specifications.
|
|
24
|
+
*/
|
|
25
|
+
export interface DidCreateOptions<TKms> {
|
|
26
|
+
/**
|
|
27
|
+
* Optional. An array of verification methods to be included in the DID document.
|
|
28
|
+
*/
|
|
29
|
+
verificationMethods?: DidCreateVerificationMethod<TKms>[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Options for additional verification methods added to the DID Document during the creation of a
|
|
34
|
+
* new Decentralized Identifier (DID).
|
|
35
|
+
*/
|
|
36
|
+
export interface DidCreateVerificationMethod<TKms> extends Pick<Partial<DidVerificationMethod>, 'controller' | 'id' | 'type'> {
|
|
37
|
+
/**
|
|
38
|
+
* The name of the cryptographic algorithm to be used for key generation.
|
|
39
|
+
*
|
|
40
|
+
* Examples might include `Ed25519` and `ES256K` but will vary depending on the DID method
|
|
41
|
+
* specification and the key management system in use.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const verificationMethod: DidCreateVerificationMethod = {
|
|
46
|
+
* algorithm: 'Ed25519'
|
|
47
|
+
* };
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
algorithm: TKms extends CryptoApi
|
|
51
|
+
? InferKeyGeneratorAlgorithm<TKms>
|
|
52
|
+
: InferKeyGeneratorAlgorithm<LocalKeyManager>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Optionally specify the purposes for which a verification method is intended to be used in a DID
|
|
56
|
+
* document.
|
|
57
|
+
*
|
|
58
|
+
* The `purposes` property defines the specific
|
|
59
|
+
* {@link DidVerificationRelationship | verification relationships} between the DID subject and
|
|
60
|
+
* the verification method. This enables the verification method to be utilized for distinct
|
|
61
|
+
* actions such as authentication, assertion, key agreement, capability delegation, and others. It
|
|
62
|
+
* is important for verifiers to recognize that a verification method must be associated with the
|
|
63
|
+
* relevant purpose in the DID document to be valid for that specific use case.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const verificationMethod: DidCreateVerificationMethod = {
|
|
68
|
+
* algorithm: 'Ed25519',
|
|
69
|
+
* controller: 'did:example:1234',
|
|
70
|
+
* purposes: ['authentication', 'assertionMethod']
|
|
71
|
+
* };
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
purposes?: (DidVerificationRelationship | keyof typeof DidVerificationRelationship)[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Defines the API for a specific DID method. It includes functionalities for creating and resolving
|
|
79
|
+
* DIDs.
|
|
80
|
+
*
|
|
81
|
+
* @typeparam T - The type of the DID instance associated with this method.
|
|
82
|
+
* @typeparam O - The type of the options used for creating the DID.
|
|
83
|
+
*/
|
|
84
|
+
export interface DidMethodApi<
|
|
85
|
+
TKms extends CryptoApi | undefined = CryptoApi,
|
|
86
|
+
TDid extends BearerDid = BearerDid,
|
|
87
|
+
TOptions extends DidCreateOptions<TKms> = DidCreateOptions<TKms>
|
|
88
|
+
> extends DidMethodResolver {
|
|
89
|
+
/**
|
|
90
|
+
* The name of the DID method.
|
|
91
|
+
*
|
|
92
|
+
* For example, in the DID `did:example:123456`, "example" would be the method name.
|
|
93
|
+
*/
|
|
94
|
+
methodName: string;
|
|
95
|
+
|
|
96
|
+
new (): DidMethod;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Creates a new DID.
|
|
100
|
+
*
|
|
101
|
+
* This function should generate a new DID in accordance with the DID method specification being
|
|
102
|
+
* implemented, using the provided `keyManager`, and optionally, any provided `options`.
|
|
103
|
+
*
|
|
104
|
+
* @param params - The parameters used to create the DID.
|
|
105
|
+
* @param params.keyManager - Optional. The cryptographic API used for key management.
|
|
106
|
+
* @param params.options - Optional. The options used for creating the DID.
|
|
107
|
+
* @returns A promise that resolves to the newly created DID instance.
|
|
108
|
+
*/
|
|
109
|
+
create(params: {
|
|
110
|
+
keyManager?: TKms;
|
|
111
|
+
options?: TOptions;
|
|
112
|
+
}): Promise<TDid>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Given a DID Document, return the verification method that will be used for signing messages and
|
|
116
|
+
* credentials.
|
|
117
|
+
*
|
|
118
|
+
* If given, the `methodId` parameter is used to select the verification method. If not given, a
|
|
119
|
+
* DID method specific approach is taken to selecting the verification method to return.
|
|
120
|
+
*
|
|
121
|
+
* @param params - The parameters for the `getSigningMethod` operation.
|
|
122
|
+
* @param params.didDocument - DID Document to get the verification method from.
|
|
123
|
+
* @param params.methodId - ID of the verification method to use for signing.
|
|
124
|
+
* @returns A promise that resolves to the erification method to use for signing.
|
|
125
|
+
*/
|
|
126
|
+
getSigningMethod(params: {
|
|
127
|
+
didDocument: DidDocument;
|
|
128
|
+
methodId?: string;
|
|
129
|
+
}): Promise<DidVerificationMethod>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Defines the interface for resolving a DID using a specific DID method.
|
|
134
|
+
*
|
|
135
|
+
* A DID resolver takes a DID URI as input and returns a {@link DidResolutionResult} object.
|
|
136
|
+
*
|
|
137
|
+
* @property {string} methodName - The name of the DID method.
|
|
138
|
+
* @method resolve - Asynchronous method to resolve a DID URI. Takes the DID URI and optional resolution options.
|
|
139
|
+
*/
|
|
140
|
+
export interface DidMethodResolver {
|
|
141
|
+
/**
|
|
142
|
+
* The name of the DID method.
|
|
143
|
+
*
|
|
144
|
+
* For example, in the DID `did:example:123456`, "example" would be the method name.
|
|
145
|
+
*/
|
|
146
|
+
methodName: string;
|
|
147
|
+
|
|
148
|
+
new (): DidMethod;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Resolves a DID URI.
|
|
152
|
+
*
|
|
153
|
+
* This function should resolve the DID URI in accordance with the DID method specification being
|
|
154
|
+
* implemented, using the provided `options`.
|
|
155
|
+
*
|
|
156
|
+
* @param didUri - The DID URI to be resolved.
|
|
157
|
+
* @param options - Optional. The options used for resolving the DID.
|
|
158
|
+
* @returns A {@link DidResolutionResult} object containing the DID document and metadata or an error.
|
|
159
|
+
*/
|
|
160
|
+
resolve(didUri: string, options?: DidResolutionOptions): Promise<DidResolutionResult>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Represents the result of a Decentralized Identifier (DID) registration operation.
|
|
165
|
+
*
|
|
166
|
+
* This type encapsulates the complete outcome of registering a DID, including the registration
|
|
167
|
+
* metadata, the DID document (if registration is successful), and metadata about the DID document.
|
|
168
|
+
*/
|
|
169
|
+
export interface DidRegistrationResult {
|
|
170
|
+
/**
|
|
171
|
+
* The DID document resulting from the registration process, if successful.
|
|
172
|
+
*
|
|
173
|
+
* If the registration operation was successful, this MUST contain a DID document
|
|
174
|
+
* corresponding to the DID. If the registration is unsuccessful, this value MUST be empty.
|
|
175
|
+
*
|
|
176
|
+
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
|
|
177
|
+
*/
|
|
178
|
+
didDocument: DidDocument | null;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Metadata about the DID Document.
|
|
182
|
+
*
|
|
183
|
+
* This structure contains information about the DID Document like creation and update timestamps,
|
|
184
|
+
* deactivation status, versioning information, and other details relevant to the DID Document.
|
|
185
|
+
*
|
|
186
|
+
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocumentmetadata | DID Core Specification, § DID Document Metadata}
|
|
187
|
+
*/
|
|
188
|
+
didDocumentMetadata: DidMetadata;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A metadata structure consisting of values relating to the results of the DID registration
|
|
192
|
+
* process.
|
|
193
|
+
*
|
|
194
|
+
* This structure is REQUIRED, and in the case of an error in the registration process,
|
|
195
|
+
* this MUST NOT be empty. If the registration is not successful, this structure MUST contain an
|
|
196
|
+
* `error` property describing the error.
|
|
197
|
+
*/
|
|
198
|
+
didRegistrationMetadata: DidRegistrationMetadata;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Represents metadata related to the result of a DID registration operation.
|
|
203
|
+
*
|
|
204
|
+
* This type includes fields that provide information about the outcome of a DID registration
|
|
205
|
+
* process (e.g., create, update, deactivate), including any errors that occurred.
|
|
206
|
+
*
|
|
207
|
+
* This metadata typically changes between invocations of the `create`, `update`, and `deactivate`
|
|
208
|
+
* functions, as it represents data about the registration process itself.
|
|
209
|
+
*/
|
|
210
|
+
export type DidRegistrationMetadata = {
|
|
211
|
+
/**
|
|
212
|
+
* An error code indicating issues encountered during the DID registration process.
|
|
213
|
+
*
|
|
214
|
+
* While the DID Core specification does not define a specific set of error codes for the result
|
|
215
|
+
* returned by the `create`, `update`, or `deactivate` functions, it is recommended to use the
|
|
216
|
+
* error codes defined in the DID Specification Registries for
|
|
217
|
+
* {@link https://www.w3.org/TR/did-spec-registries/#error | DID Resolution Metadata }.
|
|
218
|
+
*
|
|
219
|
+
* Recommended error codes include:
|
|
220
|
+
* - `internalError`: An unexpected error occurred during DID registration process.
|
|
221
|
+
* - `invalidDid`: The provided DID is invalid.
|
|
222
|
+
* - `invalidDidDocument`: The provided DID document does not conform to valid syntax.
|
|
223
|
+
* - `invalidDidDocumentLength`: The byte length of the provided DID document does not match the expected value.
|
|
224
|
+
* - `invalidSignature`: Verification of a signature failed.
|
|
225
|
+
* - `methodNotSupported`: The DID method specified is not supported.
|
|
226
|
+
* - Custom error codes can also be provided as strings.
|
|
227
|
+
*/
|
|
228
|
+
error?: string;
|
|
229
|
+
|
|
230
|
+
// Additional output metadata generated during DID registration.
|
|
231
|
+
[key: string]: any;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Base abstraction for all Decentralized Identifier (DID) method implementations.
|
|
236
|
+
*
|
|
237
|
+
* This base class serves as a foundational structure upon which specific DID methods
|
|
238
|
+
* can be implemented. Subclasses should furnish particular method and data models adherent
|
|
239
|
+
* to various DID methods, taking care to adhere to the
|
|
240
|
+
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core specification} and the
|
|
241
|
+
* respective DID method specifications.
|
|
242
|
+
*/
|
|
243
|
+
export class DidMethod {
|
|
244
|
+
/**
|
|
245
|
+
* MUST be implemented by all DID method implementations that extend {@link DidMethod}.
|
|
246
|
+
*
|
|
247
|
+
* Given the W3C DID Document of a DID, return the verification method that will be used for
|
|
248
|
+
* signing messages and credentials. If given, the `methodId` parameter is used to select the
|
|
249
|
+
* verification method. If not given, each DID method implementation will select a default
|
|
250
|
+
* verification method from the DID Document.
|
|
251
|
+
*
|
|
252
|
+
* @param _params - The parameters for the `getSigningMethod` operation.
|
|
253
|
+
* @param _params.didDocument - DID Document to get the verification method from.
|
|
254
|
+
* @param _params.methodId - ID of the verification method to use for signing.
|
|
255
|
+
* @returns Verification method to use for signing.
|
|
256
|
+
*/
|
|
257
|
+
public static async getSigningMethod(_params: {
|
|
258
|
+
didDocument: DidDocument;
|
|
259
|
+
methodId?: string;
|
|
260
|
+
}): Promise<DidVerificationMethod | undefined> {
|
|
261
|
+
throw new Error(`Not implemented: Classes extending DidMethod must implement getSigningMethod()`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* MUST be implemented by all DID method implementations that extend {@link DidMethod}.
|
|
266
|
+
*
|
|
267
|
+
* Resolves a DID URI to a DID Document.
|
|
268
|
+
*
|
|
269
|
+
* @param _didUri - The DID to be resolved.
|
|
270
|
+
* @param _options - Optional parameters for resolving the DID.
|
|
271
|
+
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
|
|
272
|
+
*/
|
|
273
|
+
public static async resolve(_didUri: string, _options?: DidResolutionOptions): Promise<DidResolutionResult> {
|
|
274
|
+
throw new Error(`Not implemented: Classes extending DidMethod must implement resolve()`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { DidDocument, DidResolutionOptions, DidResolutionResult } from '../types/did-core.js';
|
|
2
|
+
|
|
3
|
+
import { Did } from '../did.js';
|
|
4
|
+
import { DidMethod } from './did-method.js';
|
|
5
|
+
import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The `DidWeb` class provides an implementation of the `did:web` DID method.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - DID Resolution: Resolve a `did:web` to its corresponding DID Document.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* The `did:web` method uses a web domain's existing reputation and aims to integrate decentralized
|
|
15
|
+
* identities with the existing web infrastructure to drive adoption. It leverages familiar web
|
|
16
|
+
* security models and domain ownership to provide accessible, interoperable digital identity
|
|
17
|
+
* management.
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://w3c-ccg.github.io/did-method-web/ | DID Web Specification}
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* // DID Resolution
|
|
24
|
+
* const resolutionResult = await DidWeb.resolve({ did: did.uri });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class DidWeb extends DidMethod {
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Name of the DID method, as defined in the DID Web specification.
|
|
31
|
+
*/
|
|
32
|
+
public static methodName = 'web';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolves a `did:web` identifier to a DID Document.
|
|
36
|
+
*
|
|
37
|
+
* @param didUri - The DID to be resolved.
|
|
38
|
+
* @param _options - Optional parameters for resolving the DID. Unused by this DID method.
|
|
39
|
+
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
|
|
40
|
+
*/
|
|
41
|
+
public static async resolve(didUri: string, _options?: DidResolutionOptions): Promise<DidResolutionResult> {
|
|
42
|
+
// Attempt to parse the DID URI.
|
|
43
|
+
const parsedDid = Did.parse(didUri);
|
|
44
|
+
|
|
45
|
+
// If parsing failed, the DID is invalid.
|
|
46
|
+
if (!parsedDid) {
|
|
47
|
+
return {
|
|
48
|
+
...EMPTY_DID_RESOLUTION_RESULT,
|
|
49
|
+
didResolutionMetadata: { error: 'invalidDid' }
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// If the DID method is not "web", return an error.
|
|
54
|
+
if (parsedDid.method !== DidWeb.methodName) {
|
|
55
|
+
return {
|
|
56
|
+
...EMPTY_DID_RESOLUTION_RESULT,
|
|
57
|
+
didResolutionMetadata: { error: 'methodNotSupported' }
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Replace ":" with "/" in the identifier and prepend "https://" to obtain the fully qualified
|
|
62
|
+
// domain name and optional path.
|
|
63
|
+
let baseUrl = `https://${parsedDid.id.replace(/:/g, '/')}`;
|
|
64
|
+
|
|
65
|
+
// If the domain contains a percent encoded port value, decode the colon.
|
|
66
|
+
baseUrl = decodeURIComponent(baseUrl);
|
|
67
|
+
|
|
68
|
+
// Append the expected location of the DID document depending on whether a path was specified.
|
|
69
|
+
const didDocumentUrl = parsedDid.id.includes(':') ?
|
|
70
|
+
`${baseUrl}/did.json` :
|
|
71
|
+
`${baseUrl}/.well-known/did.json`;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// Perform an HTTP GET request to obtain the DID document.
|
|
75
|
+
const response = await fetch(didDocumentUrl);
|
|
76
|
+
|
|
77
|
+
// If the response status code is not 200, return an error.
|
|
78
|
+
if (!response.ok) throw new Error('HTTP error status code returned');
|
|
79
|
+
|
|
80
|
+
// Parse the DID document.
|
|
81
|
+
const didDocument = await response.json() as DidDocument;
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
...EMPTY_DID_RESOLUTION_RESULT,
|
|
85
|
+
didDocument,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
} catch (error: any) {
|
|
89
|
+
// If the DID document could not be retrieved, return an error.
|
|
90
|
+
return {
|
|
91
|
+
...EMPTY_DID_RESOLUTION_RESULT,
|
|
92
|
+
didResolutionMetadata: { error: 'notFound' }
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { AbstractLevel } from 'abstract-level';
|
|
2
|
+
|
|
3
|
+
import ms from 'ms';
|
|
4
|
+
import { Level } from 'level';
|
|
5
|
+
|
|
6
|
+
import type { DidResolutionResult } from '../types/did-core.js';
|
|
7
|
+
import type { DidResolverCache } from '../types/did-resolution.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Configuration parameters for creating a LevelDB-based cache for DID resolution results.
|
|
11
|
+
*
|
|
12
|
+
* Allows customization of the underlying database instance, storage location, and cache
|
|
13
|
+
* time-to-live (TTL) settings.
|
|
14
|
+
*/
|
|
15
|
+
export type DidResolverCacheLevelParams = {
|
|
16
|
+
/**
|
|
17
|
+
* Optional. An instance of `AbstractLevel` to use as the database. If not provided, a new
|
|
18
|
+
* LevelDB instance will be created at the specified `location`.
|
|
19
|
+
*/
|
|
20
|
+
db?: AbstractLevel<string | Buffer | Uint8Array, string, string>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Optional. The file system path or IndexedDB name where the LevelDB store will be created.
|
|
24
|
+
* Defaults to 'DATA/DID_RESOLVERCACHE' if not specified.
|
|
25
|
+
*/
|
|
26
|
+
location?: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Optional. The time-to-live for cache entries, expressed as a string (e.g., '1h', '15m').
|
|
30
|
+
* Determines how long a cache entry should remain valid before being considered expired. Defaults
|
|
31
|
+
* to '15m' if not specified.
|
|
32
|
+
*/
|
|
33
|
+
ttl?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Encapsulates a DID resolution result along with its expiration information for caching purposes.
|
|
38
|
+
*
|
|
39
|
+
* This type is used internally by the `DidResolverCacheLevel` to store DID resolution results
|
|
40
|
+
* with an associated time-to-live (TTL) value. The TTL is represented in milliseconds and
|
|
41
|
+
* determines when the cached entry is considered expired and eligible for removal.
|
|
42
|
+
*/
|
|
43
|
+
type CachedDidResolutionResult = {
|
|
44
|
+
/**
|
|
45
|
+
* The expiration time of the cache entry in milliseconds since the Unix epoch.
|
|
46
|
+
*
|
|
47
|
+
* This value is used to calculate whether the cached entry is still valid or has expired.
|
|
48
|
+
*/
|
|
49
|
+
ttlMillis: number;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The DID resolution result being cached.
|
|
53
|
+
*
|
|
54
|
+
* This object contains the resolved DID document and associated metadata.
|
|
55
|
+
*/
|
|
56
|
+
value: DidResolutionResult;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A Level-based cache implementation for storing and retrieving DID resolution results.
|
|
61
|
+
*
|
|
62
|
+
* This cache uses LevelDB for storage, allowing data persistence across process restarts or
|
|
63
|
+
* browser refreshes. It's suitable for both Node.js and browser environments.
|
|
64
|
+
*
|
|
65
|
+
* @remarks
|
|
66
|
+
* The LevelDB cache keeps data in memory for fast access and also writes to the filesystem in
|
|
67
|
+
* Node.js or indexedDB in browsers. Time-to-live (TTL) for cache entries is configurable.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```
|
|
71
|
+
* const cache = new DidResolverCacheLevel({ ttl: '15m' });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export class DidResolverCacheLevel implements DidResolverCache {
|
|
75
|
+
/** The underlying LevelDB store used for caching. */
|
|
76
|
+
protected cache;
|
|
77
|
+
|
|
78
|
+
/** The time-to-live for cache entries in milliseconds. */
|
|
79
|
+
protected ttl: number;
|
|
80
|
+
|
|
81
|
+
constructor({
|
|
82
|
+
db,
|
|
83
|
+
location = 'DATA/DID_RESOLVERCACHE',
|
|
84
|
+
ttl = '15m'
|
|
85
|
+
}: DidResolverCacheLevelParams = {}) {
|
|
86
|
+
this.cache = db ?? new Level<string, string>(location);
|
|
87
|
+
this.ttl = ms(ttl);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Retrieves a DID resolution result from the cache.
|
|
92
|
+
*
|
|
93
|
+
* If the cached item has exceeded its TTL, it's scheduled for deletion and undefined is returned.
|
|
94
|
+
*
|
|
95
|
+
* @param did - The DID string used as the key for retrieving the cached result.
|
|
96
|
+
* @returns The cached DID resolution result or undefined if not found or expired.
|
|
97
|
+
*/
|
|
98
|
+
async get(did: string): Promise<DidResolutionResult | void> {
|
|
99
|
+
try {
|
|
100
|
+
const str = await this.cache.get(did);
|
|
101
|
+
const cachedDidResolutionResult: CachedDidResolutionResult = JSON.parse(str);
|
|
102
|
+
|
|
103
|
+
if (Date.now() >= cachedDidResolutionResult.ttlMillis) {
|
|
104
|
+
// defer deletion to be called in the next tick of the js event loop
|
|
105
|
+
this.cache.nextTick(() => this.cache.del(did));
|
|
106
|
+
|
|
107
|
+
return;
|
|
108
|
+
} else {
|
|
109
|
+
return cachedDidResolutionResult.value;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
} catch(error: any) {
|
|
113
|
+
// Don't throw when a key wasn't found.
|
|
114
|
+
if (error.notFound) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Stores a DID resolution result in the cache with a TTL.
|
|
124
|
+
*
|
|
125
|
+
* @param did - The DID string used as the key for storing the result.
|
|
126
|
+
* @param value - The DID resolution result to be cached.
|
|
127
|
+
* @returns A promise that resolves when the operation is complete.
|
|
128
|
+
*/
|
|
129
|
+
set(did: string, value: DidResolutionResult): Promise<void> {
|
|
130
|
+
const cachedDidResolutionResult: CachedDidResolutionResult = { ttlMillis: Date.now() + this.ttl, value };
|
|
131
|
+
const str = JSON.stringify(cachedDidResolutionResult);
|
|
132
|
+
|
|
133
|
+
return this.cache.put(did, str);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Deletes a DID resolution result from the cache.
|
|
138
|
+
*
|
|
139
|
+
* @param did - The DID string used as the key for deletion.
|
|
140
|
+
* @returns A promise that resolves when the operation is complete.
|
|
141
|
+
*/
|
|
142
|
+
delete(did: string): Promise<void> {
|
|
143
|
+
return this.cache.del(did);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Clears all entries from the cache.
|
|
148
|
+
*
|
|
149
|
+
* @returns A promise that resolves when the operation is complete.
|
|
150
|
+
*/
|
|
151
|
+
clear(): Promise<void> {
|
|
152
|
+
return this.cache.clear();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Closes the underlying LevelDB store.
|
|
157
|
+
*
|
|
158
|
+
* @returns A promise that resolves when the store is closed.
|
|
159
|
+
*/
|
|
160
|
+
close(): Promise<void> {
|
|
161
|
+
return this.cache.close();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { DidResolutionResult } from '../types/did-core.js';
|
|
2
|
+
import type { DidResolverCache } from '../types/did-resolution.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* No-op cache that is used as the default cache for did-resolver.
|
|
6
|
+
*
|
|
7
|
+
* The motivation behind using a no-op cache as the default stems from the desire to maximize the
|
|
8
|
+
* potential for this library to be used in as many JS runtimes as possible.
|
|
9
|
+
*/
|
|
10
|
+
export const DidResolverCacheNoop: DidResolverCache = {
|
|
11
|
+
get: function (_key: string): Promise<DidResolutionResult> {
|
|
12
|
+
return null as any;
|
|
13
|
+
},
|
|
14
|
+
set: function (_key: string, _value: DidResolutionResult): Promise<void> {
|
|
15
|
+
return null as any;
|
|
16
|
+
},
|
|
17
|
+
delete: function (_key: string): Promise<void> {
|
|
18
|
+
return null as any;
|
|
19
|
+
},
|
|
20
|
+
clear: function (): Promise<void> {
|
|
21
|
+
return null as any;
|
|
22
|
+
},
|
|
23
|
+
close: function (): Promise<void> {
|
|
24
|
+
return null as any;
|
|
25
|
+
}
|
|
26
|
+
};
|