@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,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a cryptographic key with associated multicodec metadata.
|
|
3
|
+
*
|
|
4
|
+
* The `KeyWithMulticodec` type encapsulates a cryptographic key along with optional multicodec
|
|
5
|
+
* information. It is primarily used in functions that convert between cryptographic keys and their
|
|
6
|
+
* string representations, ensuring that the key's format and encoding are preserved and understood
|
|
7
|
+
* across different systems and applications.
|
|
8
|
+
*/
|
|
9
|
+
export type KeyWithMulticodec = {
|
|
10
|
+
/**
|
|
11
|
+
* A `Uint8Array` representing the raw bytes of the cryptographic key. This is the primary data of
|
|
12
|
+
* the type and is essential for cryptographic operations.
|
|
13
|
+
*/
|
|
14
|
+
keyBytes: Uint8Array,
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An optional number representing the multicodec code. This code uniquely identifies the encoding
|
|
18
|
+
* format or protocol associated with the key. The presence of this code is crucial for decoding
|
|
19
|
+
* the key correctly in different contexts.
|
|
20
|
+
*/
|
|
21
|
+
multicodecCode?: number,
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* An optional string representing the human-readable name of the multicodec. This name provides
|
|
25
|
+
* an easier way to identify the encoding format or protocol of the key, especially when the
|
|
26
|
+
* numerical code is not immediately recognizable.
|
|
27
|
+
*/
|
|
28
|
+
multicodecName?: string
|
|
29
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Jwk } from '@enbox/crypto';
|
|
2
|
+
|
|
3
|
+
import type { DidDocument, DidDocumentMetadata } from './did-core.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents metadata about a DID resulting from create, update, or deactivate operations.
|
|
7
|
+
*/
|
|
8
|
+
export interface DidMetadata extends DidDocumentMetadata {
|
|
9
|
+
/**
|
|
10
|
+
* For DID methods that support publishing, the `published` property indicates whether the DID
|
|
11
|
+
* document has been published to the respective network.
|
|
12
|
+
*
|
|
13
|
+
* A `true` value signifies that the DID document is publicly accessible on the network (e.g.,
|
|
14
|
+
* Mainline DHT), allowing it to be resolved by others. A `false` value implies the DID document
|
|
15
|
+
* is not published, limiting its visibility to public resolution. Absence of this property
|
|
16
|
+
* indicates that the DID method does not support publishing.
|
|
17
|
+
*/
|
|
18
|
+
published?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Format to document a DID identifier, along with its associated data, which can be exported,
|
|
23
|
+
* saved to a file, or imported. The intent is bundle all of the necessary metadata to enable usage
|
|
24
|
+
* of the DID in different contexts.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Format that documents the key material and metadata of a Decentralized Identifier (DID) to enable
|
|
28
|
+
* usage of the DID in different contexts.
|
|
29
|
+
*
|
|
30
|
+
* This format is useful for exporting, saving to a file, or importing a DID across process
|
|
31
|
+
* boundaries or between different DID method implementations.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* // Generate a new DID.
|
|
36
|
+
* const did = await DidExample.create();
|
|
37
|
+
*
|
|
38
|
+
* // Export to a PortableDid.
|
|
39
|
+
* const portableDid = await did.export();
|
|
40
|
+
*
|
|
41
|
+
* // Instantiate a BearerDid object from a PortableDid.
|
|
42
|
+
* const importedDid = await DidExample.import(portableDid);
|
|
43
|
+
* // The `importedDid` object should be equivalent to the original `did` object.
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export interface PortableDid {
|
|
47
|
+
/** {@inheritDoc Did#uri} */
|
|
48
|
+
uri: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The DID document associated with this DID.
|
|
52
|
+
*
|
|
53
|
+
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
|
|
54
|
+
*/
|
|
55
|
+
document: DidDocument;
|
|
56
|
+
|
|
57
|
+
/** {@inheritDoc DidMetadata} */
|
|
58
|
+
metadata: DidMetadata;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* An optional array of private keys associated with the DID document's verification methods.
|
|
62
|
+
*/
|
|
63
|
+
privateKeys?: Jwk[];
|
|
64
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
import type { Jwk } from '@enbox/crypto';
|
|
2
|
+
import type { RequireOnly } from '@enbox/common';
|
|
3
|
+
|
|
4
|
+
import { Convert, Multicodec } from '@enbox/common';
|
|
5
|
+
import { computeJwkThumbprint } from '@enbox/crypto';
|
|
6
|
+
|
|
7
|
+
import type { KeyWithMulticodec } from './types/multibase.js';
|
|
8
|
+
|
|
9
|
+
import { DidError, DidErrorCode } from './did-error.js';
|
|
10
|
+
import {
|
|
11
|
+
DidService,
|
|
12
|
+
DidDocument,
|
|
13
|
+
DidVerificationMethod,
|
|
14
|
+
DidVerificationRelationship,
|
|
15
|
+
} from './types/did-core.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Represents a Decentralized Web Node (DWN) service in a DID Document.
|
|
19
|
+
*
|
|
20
|
+
* A DWN DID service is a specialized type of DID service with the `type` set to
|
|
21
|
+
* `DecentralizedWebNode`. It includes specific properties `enc` and `sig` that are used to identify
|
|
22
|
+
* the public keys that can be used to interact with the DID Subject. The values of these properties
|
|
23
|
+
* are strings or arrays of strings containing one or more verification method `id` values present in
|
|
24
|
+
* the same DID document. If the `enc` and/or `sig` properties are an array of strings, an entity
|
|
25
|
+
* interacting with the DID subject is expected to use the verification methods in the order they
|
|
26
|
+
* are listed.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const service: DwnDidService = {
|
|
31
|
+
* id: 'did:example:123#dwn',
|
|
32
|
+
* type: 'DecentralizedWebNode',
|
|
33
|
+
* serviceEndpoint: 'https://enbox-production.up.railway.app',
|
|
34
|
+
* enc: 'did:example:123#key-1',
|
|
35
|
+
* sig: 'did:example:123#key-2'
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @see {@link https://identity.foundation/decentralized-web-node/spec/ | DIF Decentralized Web Node (DWN) Specification}
|
|
40
|
+
*/
|
|
41
|
+
export interface DwnDidService extends DidService {
|
|
42
|
+
/**
|
|
43
|
+
* One or more verification method `id` values that can be used to encrypt information
|
|
44
|
+
* intended for the DID subject.
|
|
45
|
+
*/
|
|
46
|
+
enc?: string | string[];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* One or more verification method `id` values that will be used by the DID subject to sign data
|
|
50
|
+
* or by another entity to verify signatures created by the DID subject.
|
|
51
|
+
*/
|
|
52
|
+
sig: string | string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Extracts the fragment part of a Decentralized Identifier (DID) verification method identifier.
|
|
57
|
+
*
|
|
58
|
+
* This function takes any input and aims to return only the fragment of a DID identifier,
|
|
59
|
+
* which comes after the '#' symbol in a DID string. It's designed specifically for handling
|
|
60
|
+
* DID verification method identifiers. The function returns undefined for non-string inputs, inputs
|
|
61
|
+
* that do not contain a '#', or complex data structures like objects or arrays, ensuring that only
|
|
62
|
+
* the fragment part of a DID string is extracted when present.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* console.log(extractDidFragment("did:example:123#key-1")); // Output: "key-1"
|
|
67
|
+
* console.log(extractDidFragment("did:example:123")); // Output: undefined
|
|
68
|
+
* console.log(extractDidFragment({ id: "did:example:123#0", type: "JsonWebKey" })); // Output: undefined
|
|
69
|
+
* console.log(extractDidFragment(undefined)); // Output: undefined
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @param input - The input to be processed. Can be of any type, but the function is designed
|
|
73
|
+
* to work with strings that represent DID verification method identifiers.
|
|
74
|
+
* @returns The fragment part of the DID identifier if the input is a string containing a '#'.
|
|
75
|
+
* Returns an empty string for all other inputs, including non-string types, strings
|
|
76
|
+
* without a '#', and complex data structures.
|
|
77
|
+
*/
|
|
78
|
+
export function extractDidFragment(input: unknown): string | undefined {
|
|
79
|
+
if (typeof input !== 'string') return undefined;
|
|
80
|
+
if (input.length === 0) return undefined;
|
|
81
|
+
return input.split('#').pop();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Retrieves services from a given DID document, optionally filtered by `id` or `type`.
|
|
86
|
+
*
|
|
87
|
+
* If no `id` or `type` filters are provided, all defined services are returned.
|
|
88
|
+
*
|
|
89
|
+
* The given DID Document must adhere to the
|
|
90
|
+
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* const didDocument = { ... }; // W3C DID document
|
|
95
|
+
* const services = getServices({ didDocument, type: 'DecentralizedWebNode' });
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* @param params - An object containing input parameters for retrieving services.
|
|
99
|
+
* @param params.didDocument - The DID document from which services are retrieved.
|
|
100
|
+
* @param params.id - Optional. A string representing the specific service ID to match. If provided, only the service with this ID will be returned.
|
|
101
|
+
* @param params.type - Optional. A string representing the specific service type to match. If provided, only the service(s) of this type will be returned.
|
|
102
|
+
* @returns An array of services. If no matching service is found, an empty array is returned.
|
|
103
|
+
*/
|
|
104
|
+
export function getServices({ didDocument, id, type }: {
|
|
105
|
+
didDocument: DidDocument;
|
|
106
|
+
id?: string;
|
|
107
|
+
type?: string;
|
|
108
|
+
}): DidService[] {
|
|
109
|
+
return didDocument?.service?.filter(service => {
|
|
110
|
+
if (id && service.id !== id) return false;
|
|
111
|
+
if (type && service.type !== type) return false;
|
|
112
|
+
return true;
|
|
113
|
+
}) ?? [];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Retrieves a verification method object from a DID document if there is a match for the given
|
|
118
|
+
* public key.
|
|
119
|
+
*
|
|
120
|
+
* This function searches the verification methods in a given DID document for a match with the
|
|
121
|
+
* provided public key (either in JWK or multibase format). If a matching verification method is
|
|
122
|
+
* found it is returned. If no match is found `null` is returned.
|
|
123
|
+
*
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* const didDocument = {
|
|
128
|
+
* // ... contents of a DID document ...
|
|
129
|
+
* };
|
|
130
|
+
* const publicKeyJwk = { kty: 'OKP', crv: 'Ed25519', x: '...' };
|
|
131
|
+
*
|
|
132
|
+
* const verificationMethod = await getVerificationMethodByKey({
|
|
133
|
+
* didDocument,
|
|
134
|
+
* publicKeyJwk
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @param params - An object containing input parameters for retrieving the verification method ID.
|
|
139
|
+
* @param params.didDocument - The DID document to search for the verification method.
|
|
140
|
+
* @param params.publicKeyJwk - The public key in JSON Web Key (JWK) format to match against the verification methods in the DID document.
|
|
141
|
+
* @param params.publicKeyMultibase - The public key as a multibase encoded string to match against the verification methods in the DID document.
|
|
142
|
+
* @returns A promise that resolves with the matching verification method, or `null` if no match is found.
|
|
143
|
+
* @throws Throws an `Error` if the `didDocument` parameter is missing or if the `didDocument` does not contain any verification methods.
|
|
144
|
+
*/
|
|
145
|
+
export async function getVerificationMethodByKey({ didDocument, publicKeyJwk, publicKeyMultibase }: {
|
|
146
|
+
didDocument: DidDocument;
|
|
147
|
+
publicKeyJwk?: Jwk;
|
|
148
|
+
publicKeyMultibase?: string;
|
|
149
|
+
}): Promise<DidVerificationMethod | null> {
|
|
150
|
+
// Collect all verification methods from the DID document.
|
|
151
|
+
const verificationMethods = getVerificationMethods({ didDocument });
|
|
152
|
+
|
|
153
|
+
for (let method of verificationMethods) {
|
|
154
|
+
if (publicKeyJwk && method.publicKeyJwk) {
|
|
155
|
+
const publicKeyThumbprint = await computeJwkThumbprint({ jwk: publicKeyJwk });
|
|
156
|
+
if (publicKeyThumbprint === await computeJwkThumbprint({ jwk: method.publicKeyJwk })) {
|
|
157
|
+
return method;
|
|
158
|
+
}
|
|
159
|
+
} else if (publicKeyMultibase && method.publicKeyMultibase) {
|
|
160
|
+
if (publicKeyMultibase === method.publicKeyMultibase) {
|
|
161
|
+
return method;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Retrieves all verification methods from a given DID document, including embedded methods.
|
|
171
|
+
*
|
|
172
|
+
* This function consolidates all verification methods into a single array for easy access and
|
|
173
|
+
* processing. It checks both the primary `verificationMethod` array and the individual verification
|
|
174
|
+
* relationship properties `authentication`, `assertionMethod`, `keyAgreement`,
|
|
175
|
+
* `capabilityInvocation`, and `capabilityDelegation` for embedded methods.
|
|
176
|
+
*
|
|
177
|
+
* The given DID Document must adhere to the
|
|
178
|
+
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* const didDocument = { ... }; // W3C DID document
|
|
183
|
+
* const verificationMethods = getVerificationMethods({ didDocument });
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @param params - An object containing input parameters for retrieving verification methods.
|
|
187
|
+
* @param params.didDocument - The DID document from which verification methods are retrieved.
|
|
188
|
+
* @returns An array of `DidVerificationMethod`. If no verification methods are found, an empty array is returned.
|
|
189
|
+
* @throws Throws an `TypeError` if the `didDocument` parameter is missing.
|
|
190
|
+
*/
|
|
191
|
+
export function getVerificationMethods({ didDocument }: {
|
|
192
|
+
didDocument: DidDocument;
|
|
193
|
+
}): DidVerificationMethod[] {
|
|
194
|
+
if (!didDocument) throw new TypeError(`Required parameter missing: 'didDocument'`);
|
|
195
|
+
|
|
196
|
+
const verificationMethods: DidVerificationMethod[] = [];
|
|
197
|
+
|
|
198
|
+
// Check the 'verificationMethod' array.
|
|
199
|
+
verificationMethods.push(...didDocument.verificationMethod?.filter(isDidVerificationMethod) ?? []);
|
|
200
|
+
|
|
201
|
+
// Check verification relationship properties for embedded verification methods.
|
|
202
|
+
Object.keys(DidVerificationRelationship).forEach((relationship) => {
|
|
203
|
+
verificationMethods.push(
|
|
204
|
+
...(didDocument[relationship as keyof DidDocument] as (string | DidVerificationMethod)[])
|
|
205
|
+
?.filter(isDidVerificationMethod) ?? []
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
return verificationMethods;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Retrieves all DID verification method types from a given DID document.
|
|
214
|
+
*
|
|
215
|
+
* The given DID Document must adhere to the
|
|
216
|
+
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* const didDocument = {
|
|
221
|
+
* verificationMethod: [
|
|
222
|
+
* {
|
|
223
|
+
* 'id' : 'did:example:123#key-0',
|
|
224
|
+
* 'type' : 'Ed25519VerificationKey2018',
|
|
225
|
+
* 'controller' : 'did:example:123',
|
|
226
|
+
* 'publicKeyBase58' : '3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J'
|
|
227
|
+
* },
|
|
228
|
+
* {
|
|
229
|
+
* 'id' : 'did:example:123#key-1',
|
|
230
|
+
* 'type' : 'X25519KeyAgreementKey2019',
|
|
231
|
+
* 'controller' : 'did:example:123',
|
|
232
|
+
* 'publicKeyBase58' : 'FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x'
|
|
233
|
+
* },
|
|
234
|
+
* {
|
|
235
|
+
* 'id' : 'did:example:123#key-3',
|
|
236
|
+
* 'type' : 'JsonWebKey2020',
|
|
237
|
+
* 'controller' : 'did:example:123',
|
|
238
|
+
* 'publicKeyJwk' : {
|
|
239
|
+
* 'kty' : 'EC',
|
|
240
|
+
* 'crv' : 'P-256',
|
|
241
|
+
* 'x' : 'Er6KSSnAjI70ObRWhlaMgqyIOQYrDJTE94ej5hybQ2M',
|
|
242
|
+
* 'y' : 'pPVzCOTJwgikPjuUE6UebfZySqEJ0ZtsWFpj7YSPGEk'
|
|
243
|
+
* }
|
|
244
|
+
* }
|
|
245
|
+
* ]
|
|
246
|
+
* },
|
|
247
|
+
* const vmTypes = getVerificationMethodTypes({ didDocument });
|
|
248
|
+
* console.log(vmTypes);
|
|
249
|
+
* // Output: ['Ed25519VerificationKey2018', 'X25519KeyAgreementKey2019', 'JsonWebKey2020']
|
|
250
|
+
* ```
|
|
251
|
+
*
|
|
252
|
+
* @param params - An object containing input parameters for retrieving types.
|
|
253
|
+
* @param params.didDocument - The DID document from which types are retrieved.
|
|
254
|
+
* @returns An array of types. If no types were found, an empty array is returned.
|
|
255
|
+
*/
|
|
256
|
+
export function getVerificationMethodTypes({ didDocument }: {
|
|
257
|
+
didDocument: DidDocument;
|
|
258
|
+
}): string[] {
|
|
259
|
+
// Collect all verification methods from the DID document.
|
|
260
|
+
const verificationMethods = getVerificationMethods({ didDocument });
|
|
261
|
+
|
|
262
|
+
// Map to extract 'type' from each verification method.
|
|
263
|
+
const types = verificationMethods.map(method => method.type);
|
|
264
|
+
|
|
265
|
+
return [...new Set(types)]; // Return only unique types.
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Retrieves a list of DID verification relationships by a specific method ID from a DID document.
|
|
270
|
+
*
|
|
271
|
+
* This function examines the specified DID document to identify any verification relationships
|
|
272
|
+
* (e.g., `authentication`, `assertionMethod`) that reference a verification method by its method ID
|
|
273
|
+
* or contain an embedded verification method matching the method ID. The method ID is typically a
|
|
274
|
+
* fragment of a DID (e.g., `did:example:123#key-1`) that uniquely identifies a verification method
|
|
275
|
+
* within the DID document.
|
|
276
|
+
*
|
|
277
|
+
* The search considers both direct references to verification methods by their IDs and verification
|
|
278
|
+
* methods embedded within the verification relationship arrays. It returns an array of
|
|
279
|
+
* `DidVerificationRelationship` enums corresponding to the verification relationships that contain
|
|
280
|
+
* the specified method ID.
|
|
281
|
+
*
|
|
282
|
+
* @param params - An object containing input parameters for retrieving verification relationships.
|
|
283
|
+
* @param params.didDocument - The DID document to search for verification relationships.
|
|
284
|
+
* @param params.methodId - The method ID to search for within the verification relationships.
|
|
285
|
+
* @returns An array of `DidVerificationRelationship` enums representing the types of verification
|
|
286
|
+
* relationships that reference the specified method ID.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```ts
|
|
290
|
+
* const didDocument: DidDocument = {
|
|
291
|
+
* // ...contents of a DID document...
|
|
292
|
+
* };
|
|
293
|
+
*
|
|
294
|
+
* const relationships = getVerificationRelationshipsById({
|
|
295
|
+
* didDocument,
|
|
296
|
+
* methodId: 'key-1'
|
|
297
|
+
* });
|
|
298
|
+
* console.log(relationships);
|
|
299
|
+
* // Output might include ['authentication', 'assertionMethod'] if those relationships
|
|
300
|
+
* // reference or contain the specified method ID.
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
export function getVerificationRelationshipsById({ didDocument, methodId }: {
|
|
304
|
+
didDocument: DidDocument;
|
|
305
|
+
methodId: string;
|
|
306
|
+
}): DidVerificationRelationship[] {
|
|
307
|
+
const relationships: DidVerificationRelationship[] = [];
|
|
308
|
+
|
|
309
|
+
Object.keys(DidVerificationRelationship).forEach((relationship) => {
|
|
310
|
+
if (Array.isArray(didDocument[relationship as keyof DidDocument])) {
|
|
311
|
+
const relationshipMethods = didDocument[relationship as keyof DidDocument] as (string | DidVerificationMethod)[];
|
|
312
|
+
|
|
313
|
+
const methodIdFragment = extractDidFragment(methodId);
|
|
314
|
+
|
|
315
|
+
// Check if the verification relationship property contains a matching method ID either
|
|
316
|
+
// directly referenced or as an embedded verification method.
|
|
317
|
+
const containsMethodId = relationshipMethods.some(method => {
|
|
318
|
+
const isByReferenceMatch = extractDidFragment(method) === methodIdFragment;
|
|
319
|
+
const isEmbeddedMethodMatch = isDidVerificationMethod(method) && extractDidFragment(method.id) === methodIdFragment;
|
|
320
|
+
return isByReferenceMatch || isEmbeddedMethodMatch;
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
if (containsMethodId) {
|
|
324
|
+
relationships.push(relationship as DidVerificationRelationship);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
return relationships;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Checks if a given object is a {@link DidService}.
|
|
334
|
+
*
|
|
335
|
+
* A {@link DidService} in the context of DID resources must include the properties `id`, `type`,
|
|
336
|
+
* and `serviceEndpoint`. The `serviceEndpoint` can be a `DidServiceEndpoint` or an array of
|
|
337
|
+
* `DidServiceEndpoint` objects.
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* ```ts
|
|
341
|
+
* const service = {
|
|
342
|
+
* id: "did:example:123#service-1",
|
|
343
|
+
* type: "OidcService",
|
|
344
|
+
* serviceEndpoint: "https://example.com/oidc"
|
|
345
|
+
* };
|
|
346
|
+
*
|
|
347
|
+
* if (isDidService(service)) {
|
|
348
|
+
* console.log('The object is a DidService');
|
|
349
|
+
* } else {
|
|
350
|
+
* console.log('The object is not a DidService');
|
|
351
|
+
* }
|
|
352
|
+
* ```
|
|
353
|
+
*
|
|
354
|
+
* @param obj - The object to be checked.
|
|
355
|
+
* @returns `true` if `obj` is a `DidService`; otherwise, `false`.
|
|
356
|
+
*/
|
|
357
|
+
export function isDidService(obj: unknown): obj is DidService {
|
|
358
|
+
// Validate that the given value is an object.
|
|
359
|
+
if (!obj || typeof obj !== 'object' || obj === null) return false;
|
|
360
|
+
|
|
361
|
+
// Validate that the object has the necessary properties of DidService.
|
|
362
|
+
return 'id' in obj && 'type' in obj && 'serviceEndpoint' in obj;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Checks if a given object is a {@link DwnDidService}.
|
|
367
|
+
*
|
|
368
|
+
* A {@link DwnDidService} is defined as {@link DidService} object with a `type` of
|
|
369
|
+
* "DecentralizedWebNode" and `enc` and `sig` properties, where both properties are either strings
|
|
370
|
+
* or arrays of strings.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```ts
|
|
374
|
+
* const didDocument: DidDocument = {
|
|
375
|
+
* id: 'did:example:123',
|
|
376
|
+
* verificationMethod: [
|
|
377
|
+
* {
|
|
378
|
+
* id: 'did:example:123#key-1',
|
|
379
|
+
* type: 'JsonWebKey2020',
|
|
380
|
+
* controller: 'did:example:123',
|
|
381
|
+
* publicKeyJwk: { ... }
|
|
382
|
+
* },
|
|
383
|
+
* {
|
|
384
|
+
* id: 'did:example:123#key-2',
|
|
385
|
+
* type: 'JsonWebKey2020',
|
|
386
|
+
* controller: 'did:example:123',
|
|
387
|
+
* publicKeyJwk: { ... }
|
|
388
|
+
* }
|
|
389
|
+
* ],
|
|
390
|
+
* service: [
|
|
391
|
+
* {
|
|
392
|
+
* id: 'did:example:123#dwn',
|
|
393
|
+
* type: 'DecentralizedWebNode',
|
|
394
|
+
* serviceEndpoint: 'https://enbox-production.up.railway.app',
|
|
395
|
+
* enc: 'did:example:123#key-1',
|
|
396
|
+
* sig: 'did:example:123#key-2'
|
|
397
|
+
* }
|
|
398
|
+
* ]
|
|
399
|
+
* };
|
|
400
|
+
*
|
|
401
|
+
* if (isDwnService(didDocument.service[0])) {
|
|
402
|
+
* console.log('The object is a DwnDidService');
|
|
403
|
+
* } else {
|
|
404
|
+
* console.log('The object is not a DwnDidService');
|
|
405
|
+
* }
|
|
406
|
+
* ```
|
|
407
|
+
*
|
|
408
|
+
* @see {@link https://identity.foundation/decentralized-web-node/spec/ | Decentralized Web Node (DWN) Specification}
|
|
409
|
+
*
|
|
410
|
+
* @param obj - The object to be checked.
|
|
411
|
+
* @returns `true` if `obj` is a DwnDidService; otherwise, `false`.
|
|
412
|
+
*/
|
|
413
|
+
export function isDwnDidService(obj: unknown): obj is DwnDidService {
|
|
414
|
+
// Validate that the given value is a {@link DidService}.
|
|
415
|
+
if (!isDidService(obj)) return false;
|
|
416
|
+
|
|
417
|
+
// Validate that the `type` property is `DecentralizedWebNode`.
|
|
418
|
+
if (obj.type !== 'DecentralizedWebNode') return false;
|
|
419
|
+
|
|
420
|
+
// Validate that the given object has the `enc` and `sig` properties.
|
|
421
|
+
if (!('enc' in obj && 'sig' in obj)) return false;
|
|
422
|
+
|
|
423
|
+
// Validate that the `enc` and `sig` properties are either strings or arrays of strings.
|
|
424
|
+
const isStringOrStringArray = (prop: any): boolean =>
|
|
425
|
+
typeof prop === 'string' || Array.isArray(prop) && prop.every(item => typeof item === 'string');
|
|
426
|
+
return (isStringOrStringArray(obj.enc)) && (isStringOrStringArray(obj.sig));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Checks if a given object is a DID Verification Method.
|
|
431
|
+
*
|
|
432
|
+
* A {@link DidVerificationMethod} in the context of DID resources must include the properties `id`,
|
|
433
|
+
* `type`, and `controller`.
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* ```ts
|
|
437
|
+
* const resource = {
|
|
438
|
+
* id : "did:example:123#0",
|
|
439
|
+
* type : "JsonWebKey2020",
|
|
440
|
+
* controller : "did:example:123",
|
|
441
|
+
* publicKeyJwk : { ... }
|
|
442
|
+
* };
|
|
443
|
+
*
|
|
444
|
+
* if (isDidVerificationMethod(resource)) {
|
|
445
|
+
* console.log('The resource is a DidVerificationMethod');
|
|
446
|
+
* } else {
|
|
447
|
+
* console.log('The resource is not a DidVerificationMethod');
|
|
448
|
+
* }
|
|
449
|
+
* ```
|
|
450
|
+
*
|
|
451
|
+
* @param obj - The object to be checked.
|
|
452
|
+
* @returns `true` if `obj` is a `DidVerificationMethod`; otherwise, `false`.
|
|
453
|
+
*/
|
|
454
|
+
export function isDidVerificationMethod(obj: unknown): obj is DidVerificationMethod {
|
|
455
|
+
// Validate that the given value is an object.
|
|
456
|
+
if (!obj || typeof obj !== 'object' || obj === null) return false;
|
|
457
|
+
|
|
458
|
+
// Validate that the object has the necessary properties of a DidVerificationMethod.
|
|
459
|
+
if (!('id' in obj && 'type' in obj && 'controller' in obj)) return false;
|
|
460
|
+
|
|
461
|
+
if (typeof obj.id !== 'string') return false;
|
|
462
|
+
if (typeof obj.type !== 'string') return false;
|
|
463
|
+
if (typeof obj.controller !== 'string') return false;
|
|
464
|
+
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Converts a cryptographic key to a multibase identifier.
|
|
470
|
+
*
|
|
471
|
+
* @remarks
|
|
472
|
+
* This method provides a way to represent a cryptographic key as a multibase identifier.
|
|
473
|
+
* It takes a `Uint8Array` representing the key, and either the multicodec code or multicodec name
|
|
474
|
+
* as input. The method first adds the multicodec prefix to the key, then encodes it into Base58
|
|
475
|
+
* format. Finally, it converts the Base58 encoded key into a multibase identifier.
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```ts
|
|
479
|
+
* const key = new Uint8Array([...]); // Cryptographic key as Uint8Array
|
|
480
|
+
* const multibaseId = keyBytesToMultibaseId({ key, multicodecName: 'ed25519-pub' });
|
|
481
|
+
* ```
|
|
482
|
+
*
|
|
483
|
+
* @param params - The parameters for the conversion.
|
|
484
|
+
* @returns The multibase identifier as a string.
|
|
485
|
+
*/
|
|
486
|
+
export function keyBytesToMultibaseId({ keyBytes, multicodecCode, multicodecName }:
|
|
487
|
+
RequireOnly<KeyWithMulticodec, 'keyBytes'>
|
|
488
|
+
): string {
|
|
489
|
+
const prefixedKey = Multicodec.addPrefix({
|
|
490
|
+
code : multicodecCode,
|
|
491
|
+
data : keyBytes,
|
|
492
|
+
name : multicodecName
|
|
493
|
+
});
|
|
494
|
+
const prefixedKeyB58 = Convert.uint8Array(prefixedKey).toBase58Btc();
|
|
495
|
+
const multibaseKeyId = Convert.base58Btc(prefixedKeyB58).toMultibase();
|
|
496
|
+
|
|
497
|
+
return multibaseKeyId;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Converts a multibase identifier to a cryptographic key.
|
|
502
|
+
*
|
|
503
|
+
* @remarks
|
|
504
|
+
* This function decodes a multibase identifier back into a cryptographic key. It first decodes the
|
|
505
|
+
* identifier from multibase format into Base58 format, and then converts it into a `Uint8Array`.
|
|
506
|
+
* Afterward, it removes the multicodec prefix, extracting the raw key data along with the
|
|
507
|
+
* multicodec code and name.
|
|
508
|
+
*
|
|
509
|
+
* @example
|
|
510
|
+
* ```ts
|
|
511
|
+
* const multibaseKeyId = '...'; // Multibase identifier of the key
|
|
512
|
+
* const { key, multicodecCode, multicodecName } = multibaseIdToKey({ multibaseKeyId });
|
|
513
|
+
* ```
|
|
514
|
+
*
|
|
515
|
+
* @param params - The parameters for the conversion.
|
|
516
|
+
* @param params.multibaseKeyId - The multibase identifier string of the key.
|
|
517
|
+
* @returns An object containing the key as a `Uint8Array` and its multicodec code and name.
|
|
518
|
+
* @throws `DidError` if the multibase identifier is invalid.
|
|
519
|
+
*/
|
|
520
|
+
export function multibaseIdToKeyBytes({ multibaseKeyId }: {
|
|
521
|
+
multibaseKeyId: string
|
|
522
|
+
}): Required<KeyWithMulticodec> {
|
|
523
|
+
try {
|
|
524
|
+
const prefixedKeyB58 = Convert.multibase(multibaseKeyId).toBase58Btc();
|
|
525
|
+
const prefixedKey = Convert.base58Btc(prefixedKeyB58).toUint8Array();
|
|
526
|
+
const { code, data, name } = Multicodec.removePrefix({ prefixedData: prefixedKey });
|
|
527
|
+
|
|
528
|
+
return { keyBytes: data, multicodecCode: code, multicodecName: name };
|
|
529
|
+
} catch (error: any) {
|
|
530
|
+
throw new DidError(DidErrorCode.InvalidDid, `Invalid multibase identifier: ${multibaseKeyId}`);
|
|
531
|
+
}
|
|
532
|
+
}
|