@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
package/package.json
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@enbox/dids",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "TBD DIDs library",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cjs/index.js",
|
|
7
|
+
"module": "./dist/esm/index.js",
|
|
8
|
+
"types": "./dist/types/index.d.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"clean": "rimraf dist coverage tests/compiled",
|
|
11
|
+
"build:esm": "rimraf dist/esm dist/types && pnpm tsc -p tsconfig.json",
|
|
12
|
+
"build:cjs": "rimraf dist/cjs && node build/cjs-bundle.js && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json",
|
|
13
|
+
"build:browser": "rimraf dist/browser.mjs dist/browser.js && node build/bundles.js",
|
|
14
|
+
"build:tests:node": "rimraf tests/compiled && pnpm tsc -p tests/tsconfig.json",
|
|
15
|
+
"build:tests:browser": "rimraf tests/compiled && node build/esbuild-tests.cjs",
|
|
16
|
+
"build": "pnpm clean && pnpm build:esm && pnpm build:cjs && pnpm build:browser",
|
|
17
|
+
"lint": "eslint . --max-warnings 0",
|
|
18
|
+
"lint:fix": "eslint . --fix",
|
|
19
|
+
"test:node": "pnpm build:tests:node && pnpm c8 mocha",
|
|
20
|
+
"test:browser": "pnpm build:tests:browser && web-test-runner"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/enboxorg/enbox/tree/main/packages/dids#readme",
|
|
23
|
+
"bugs": "https://github.com/enboxorg/enbox/issues",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/enboxorg/enbox.git",
|
|
27
|
+
"directory": "packages/dids"
|
|
28
|
+
},
|
|
29
|
+
"license": "Apache-2.0",
|
|
30
|
+
"contributors": [
|
|
31
|
+
{
|
|
32
|
+
"name": "Daniel Buchner",
|
|
33
|
+
"url": "https://github.com/csuwildcat"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "Frank Hinek",
|
|
37
|
+
"url": "https://github.com/frankhinek"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "Moe Jangda",
|
|
41
|
+
"url": "https://github.com/mistermoe"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"src"
|
|
47
|
+
],
|
|
48
|
+
"exports": {
|
|
49
|
+
".": {
|
|
50
|
+
"types": "./dist/types/index.d.ts",
|
|
51
|
+
"import": "./dist/esm/index.js",
|
|
52
|
+
"require": "./dist/cjs/index.js"
|
|
53
|
+
},
|
|
54
|
+
"./utils": {
|
|
55
|
+
"types": "./dist/types/utils.d.ts",
|
|
56
|
+
"import": "./dist/esm/utils.js",
|
|
57
|
+
"require": "./dist/cjs/utils.js"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"react-native": "./dist/esm/index.js",
|
|
61
|
+
"keywords": [
|
|
62
|
+
"decentralized",
|
|
63
|
+
"decentralized-identity",
|
|
64
|
+
"DID",
|
|
65
|
+
"did:ion",
|
|
66
|
+
"did:key",
|
|
67
|
+
"did-utils",
|
|
68
|
+
"self-sovereign-identity",
|
|
69
|
+
"web5"
|
|
70
|
+
],
|
|
71
|
+
"publishConfig": {
|
|
72
|
+
"access": "public"
|
|
73
|
+
},
|
|
74
|
+
"engines": {
|
|
75
|
+
"node": ">=18.0.0"
|
|
76
|
+
},
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"@decentralized-identity/ion-sdk": "1.0.4",
|
|
79
|
+
"@dnsquery/dns-packet": "6.1.1",
|
|
80
|
+
"@enbox/common": "workspace:*",
|
|
81
|
+
"@enbox/crypto": "workspace:*",
|
|
82
|
+
"abstract-level": "1.0.4",
|
|
83
|
+
"bencode": "4.0.0",
|
|
84
|
+
"buffer": "6.0.3",
|
|
85
|
+
"level": "8.0.1",
|
|
86
|
+
"ms": "2.1.3"
|
|
87
|
+
},
|
|
88
|
+
"devDependencies": {
|
|
89
|
+
"@playwright/test": "1.45.3",
|
|
90
|
+
"@types/bencode": "2.0.4",
|
|
91
|
+
"@types/chai": "4.3.16",
|
|
92
|
+
"@types/chai-as-promised": "7.1.8",
|
|
93
|
+
"@types/eslint": "8.56.10",
|
|
94
|
+
"@types/mocha": "10.0.7",
|
|
95
|
+
"@types/ms": "0.7.34",
|
|
96
|
+
"@types/node": "20.14.8",
|
|
97
|
+
"@types/sinon": "17.0.3",
|
|
98
|
+
"@typescript-eslint/eslint-plugin": "7.9.0",
|
|
99
|
+
"@typescript-eslint/parser": "7.14.1",
|
|
100
|
+
"@web/test-runner": "0.18.2",
|
|
101
|
+
"@web/test-runner-playwright": "0.11.0",
|
|
102
|
+
"c8": "9.1.0",
|
|
103
|
+
"chai": "5.1.1",
|
|
104
|
+
"chai-as-promised": "7.1.2",
|
|
105
|
+
"esbuild": "0.23.0",
|
|
106
|
+
"eslint": "9.5.0",
|
|
107
|
+
"eslint-plugin-mocha": "10.4.3",
|
|
108
|
+
"mocha": "10.7.0",
|
|
109
|
+
"mocha-junit-reporter": "2.2.1",
|
|
110
|
+
"playwright": "1.45.3",
|
|
111
|
+
"rimraf": "5.0.7",
|
|
112
|
+
"sinon": "18.0.0",
|
|
113
|
+
"source-map-loader": "5.0.0",
|
|
114
|
+
"typescript": "5.5.4"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Jwk,
|
|
3
|
+
Signer,
|
|
4
|
+
CryptoApi,
|
|
5
|
+
KeyIdentifier,
|
|
6
|
+
EnclosedSignParams,
|
|
7
|
+
KmsExportKeyParams,
|
|
8
|
+
KmsImportKeyParams,
|
|
9
|
+
KeyImporterExporter,
|
|
10
|
+
EnclosedVerifyParams,
|
|
11
|
+
} from '@enbox/crypto';
|
|
12
|
+
|
|
13
|
+
import { LocalKeyManager, CryptoUtils } from '@enbox/crypto';
|
|
14
|
+
|
|
15
|
+
import type { DidDocument } from './types/did-core.js';
|
|
16
|
+
import type { DidMetadata, PortableDid } from './types/portable-did.js';
|
|
17
|
+
|
|
18
|
+
import { DidError, DidErrorCode } from './did-error.js';
|
|
19
|
+
import { extractDidFragment, getVerificationMethods } from './utils.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A `BearerDidSigner` extends the {@link Signer} interface to include specific properties for
|
|
23
|
+
* signing with a Decentralized Identifier (DID). It encapsulates the algorithm and key identifier,
|
|
24
|
+
* which are often needed when signing JWTs, JWSs, JWEs, and other data structures.
|
|
25
|
+
*
|
|
26
|
+
* Typically, the algorithm and key identifier are used to populate the `alg` and `kid` fields of a
|
|
27
|
+
* JWT or JWS header.
|
|
28
|
+
*/
|
|
29
|
+
export interface BearerDidSigner extends Signer {
|
|
30
|
+
/**
|
|
31
|
+
* The cryptographic algorithm identifier used for signing operations.
|
|
32
|
+
*
|
|
33
|
+
* Typically, this value is used to populate the `alg` field of a JWT or JWS header. The
|
|
34
|
+
* registered algorithm names are defined in the
|
|
35
|
+
* {@link https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms | IANA JSON Web Signature and Encryption Algorithms registry}.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* "ES256" // ECDSA using P-256 and SHA-256
|
|
39
|
+
*/
|
|
40
|
+
algorithm: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The unique identifier of the key within the DID document that is used for signing and
|
|
44
|
+
* verification operations.
|
|
45
|
+
*
|
|
46
|
+
* This identifier must be a DID URI with a fragment (e.g., did:method:123#key-0) that references
|
|
47
|
+
* a specific verification method in the DID document. It allows users of a `BearerDidSigner` to
|
|
48
|
+
* determine the DID and key that will be used for signing and verification operations.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* "did:dht:123#key-1" // A fragment identifier referring to a key in the DID document
|
|
52
|
+
*/
|
|
53
|
+
keyId: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Represents a Decentralized Identifier (DID) along with its DID document, key manager, metadata,
|
|
58
|
+
* and convenience functions.
|
|
59
|
+
*/
|
|
60
|
+
export class BearerDid {
|
|
61
|
+
/** {@inheritDoc Did#uri} */
|
|
62
|
+
uri: string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The DID document associated with this DID.
|
|
66
|
+
*
|
|
67
|
+
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
|
|
68
|
+
*/
|
|
69
|
+
document: DidDocument;
|
|
70
|
+
|
|
71
|
+
/** {@inheritDoc DidMetadata} */
|
|
72
|
+
metadata: DidMetadata;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Key Management System (KMS) used to manage the DIDs keys and sign data.
|
|
76
|
+
*
|
|
77
|
+
* Each DID method requires at least one key be present in the provided `keyManager`.
|
|
78
|
+
*/
|
|
79
|
+
keyManager: CryptoApi;
|
|
80
|
+
|
|
81
|
+
constructor({ uri, document, metadata, keyManager }: {
|
|
82
|
+
uri: string,
|
|
83
|
+
document: DidDocument,
|
|
84
|
+
metadata: DidMetadata,
|
|
85
|
+
keyManager: CryptoApi
|
|
86
|
+
}) {
|
|
87
|
+
this.uri = uri;
|
|
88
|
+
this.document = document;
|
|
89
|
+
this.metadata = metadata;
|
|
90
|
+
this.keyManager = keyManager;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Converts a `BearerDid` object to a portable format containing the URI and verification methods
|
|
95
|
+
* associated with the DID.
|
|
96
|
+
*
|
|
97
|
+
* This method is useful when you need to represent the key material and metadata associated with
|
|
98
|
+
* a DID in format that can be used independently of the specific DID method implementation. It
|
|
99
|
+
* extracts both public and private keys from the DID's key manager and organizes them into a
|
|
100
|
+
* `PortableDid` structure.
|
|
101
|
+
*
|
|
102
|
+
* @remarks
|
|
103
|
+
* If the DID's key manager does not allow private keys to be exported, the `PortableDid` returned
|
|
104
|
+
* will not contain a `privateKeys` property. This enables the importing and exporting DIDs that
|
|
105
|
+
* use the same underlying KMS even if the KMS does not support exporting private keys. Examples
|
|
106
|
+
* include hardware security modules (HSMs) and cloud-based KMS services like AWS KMS.
|
|
107
|
+
*
|
|
108
|
+
* If the DID's key manager does support exporting private keys, the resulting `PortableDid` will
|
|
109
|
+
* include a `privateKeys` property which contains the same number of entries as there are
|
|
110
|
+
* verification methods as the DID document, each with its associated private key and the
|
|
111
|
+
* purpose(s) for which the key can be used (e.g., `authentication`, `assertionMethod`, etc.).
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* // Assuming `did` is an instance of BearerDid
|
|
116
|
+
* const portableDid = await did.export();
|
|
117
|
+
* // portableDid now contains the DID URI, document, metadata, and optionally, private keys.
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @returns A `PortableDid` containing the URI, DID document, metadata, and optionally private
|
|
121
|
+
* keys associated with the `BearerDid`.
|
|
122
|
+
* @throws An error if the DID document does not contain any verification methods or the keys for
|
|
123
|
+
* any verification method are missing in the key manager.
|
|
124
|
+
*/
|
|
125
|
+
public async export(): Promise<PortableDid> {
|
|
126
|
+
// Verify the DID document contains at least one verification method.
|
|
127
|
+
if (!(Array.isArray(this.document.verificationMethod) && this.document.verificationMethod.length > 0)) {
|
|
128
|
+
throw new Error(`DID document for '${this.uri}' is missing verification methods`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Create a new `PortableDid` copy object to store the exported data.
|
|
132
|
+
let portableDid: PortableDid = JSON.parse(JSON.stringify({
|
|
133
|
+
uri : this.uri,
|
|
134
|
+
document : this.document,
|
|
135
|
+
metadata : this.metadata
|
|
136
|
+
}));
|
|
137
|
+
|
|
138
|
+
// If the BearerDid's key manager supports exporting private keys, add them to the portable DID.
|
|
139
|
+
if ('exportKey' in this.keyManager && typeof this.keyManager.exportKey === 'function') {
|
|
140
|
+
const privateKeys: Jwk[] = [];
|
|
141
|
+
for (let vm of this.document.verificationMethod) {
|
|
142
|
+
if (!vm.publicKeyJwk) {
|
|
143
|
+
throw new Error(`Verification method '${vm.id}' does not contain a public key in JWK format`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Compute the key URI of the verification method's public key.
|
|
147
|
+
const keyUri = await this.keyManager.getKeyUri({ key: vm.publicKeyJwk });
|
|
148
|
+
|
|
149
|
+
// Retrieve the private key from the key manager.
|
|
150
|
+
const privateKey = await this.keyManager.exportKey({ keyUri }) as Jwk;
|
|
151
|
+
|
|
152
|
+
// Add the verification method to the key set.
|
|
153
|
+
privateKeys.push({ ...privateKey });
|
|
154
|
+
}
|
|
155
|
+
portableDid.privateKeys = privateKeys;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return portableDid;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Return a {@link Signer} that can be used to sign messages, credentials, or arbitrary data.
|
|
163
|
+
*
|
|
164
|
+
* If given, the `methodId` parameter is used to select a key from the verification methods
|
|
165
|
+
* present in the DID Document.
|
|
166
|
+
*
|
|
167
|
+
* If `methodID` is not given, the first verification method intended for signing claims is used.
|
|
168
|
+
*
|
|
169
|
+
* @param params - The parameters for the `getSigner` operation.
|
|
170
|
+
* @param params.methodId - ID of the verification method key that will be used for sign and
|
|
171
|
+
* verify operations. Optional.
|
|
172
|
+
* @returns An instantiated {@link Signer} that can be used to sign and verify data.
|
|
173
|
+
*/
|
|
174
|
+
public async getSigner(params?: { methodId: string }): Promise<BearerDidSigner> {
|
|
175
|
+
// Attempt to find a verification method that matches the given method ID, or if not given,
|
|
176
|
+
// find the first verification method intended for signing claims.
|
|
177
|
+
const verificationMethod = this.document.verificationMethod?.find(
|
|
178
|
+
vm => extractDidFragment(vm.id) === (extractDidFragment(params?.methodId) ?? extractDidFragment(this.document.assertionMethod?.[0]))
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
if (!(verificationMethod && verificationMethod.publicKeyJwk)) {
|
|
182
|
+
throw new DidError(DidErrorCode.InternalError, 'A verification method intended for signing could not be determined from the DID Document');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Compute the expected key URI of the signing key.
|
|
186
|
+
const keyUri = await this.keyManager.getKeyUri({ key: verificationMethod.publicKeyJwk });
|
|
187
|
+
|
|
188
|
+
// Get the public key to be used for verify operations, which also verifies that the key is
|
|
189
|
+
// present in the key manager's store.
|
|
190
|
+
const publicKey = await this.keyManager.getPublicKey({ keyUri });
|
|
191
|
+
|
|
192
|
+
// Bind the DID's key manager to the signer.
|
|
193
|
+
const keyManager = this.keyManager;
|
|
194
|
+
|
|
195
|
+
// Determine the signing algorithm.
|
|
196
|
+
const algorithm = CryptoUtils.getJoseSignatureAlgorithmFromPublicKey(publicKey);
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
algorithm : algorithm,
|
|
200
|
+
keyId : verificationMethod.id,
|
|
201
|
+
|
|
202
|
+
async sign({ data }: EnclosedSignParams): Promise<Uint8Array> {
|
|
203
|
+
const signature = await keyManager.sign({ data, keyUri: keyUri! }); // `keyUri` is guaranteed to be defined at this point.
|
|
204
|
+
return signature;
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
async verify({ data, signature }: EnclosedVerifyParams): Promise<boolean> {
|
|
208
|
+
const isValid = await keyManager.verify({ data, key: publicKey!, signature }); // `publicKey` is guaranteed to be defined at this point.
|
|
209
|
+
return isValid;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Instantiates a {@link BearerDid} object from a given {@link PortableDid}.
|
|
216
|
+
*
|
|
217
|
+
* This method allows for the creation of a `BearerDid` object using a previously created DID's
|
|
218
|
+
* key material, DID document, and metadata.
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```ts
|
|
222
|
+
* // Export an existing BearerDid to PortableDid format.
|
|
223
|
+
* const portableDid = await did.export();
|
|
224
|
+
* // Reconstruct a BearerDid object from the PortableDid.
|
|
225
|
+
* const did = await BearerDid.import({ portableDid });
|
|
226
|
+
* ```
|
|
227
|
+
*
|
|
228
|
+
* @param params - The parameters for the import operation.
|
|
229
|
+
* @param params.portableDid - The PortableDid object to import.
|
|
230
|
+
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
|
|
231
|
+
* generate keys and sign data. If not given, a new
|
|
232
|
+
* {@link LocalKeyManager} instance will be created and
|
|
233
|
+
* used.
|
|
234
|
+
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
|
|
235
|
+
* provided PortableDid.
|
|
236
|
+
* @throws An error if the PortableDid document does not contain any verification methods or the
|
|
237
|
+
* keys for any verification method are missing in the key manager.
|
|
238
|
+
*/
|
|
239
|
+
public static async import({ portableDid, keyManager = new LocalKeyManager() }: {
|
|
240
|
+
keyManager?: CryptoApi & KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams>;
|
|
241
|
+
portableDid: PortableDid;
|
|
242
|
+
}): Promise<BearerDid> {
|
|
243
|
+
|
|
244
|
+
// Get all verification methods from the given DID document, including embedded methods.
|
|
245
|
+
const verificationMethods = getVerificationMethods({ didDocument: portableDid.document });
|
|
246
|
+
|
|
247
|
+
// Validate that the DID document contains at least one verification method.
|
|
248
|
+
if (verificationMethods.length === 0) {
|
|
249
|
+
throw new DidError(DidErrorCode.InvalidDidDocument, `At least one verification method is required but 0 were given`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// If given, import the private key material into the key manager.
|
|
253
|
+
for (let key of portableDid.privateKeys ?? []) {
|
|
254
|
+
|
|
255
|
+
// confirm th key does not already exist before importing it to avoid failures from the key manager
|
|
256
|
+
const keyUri = await keyManager.getKeyUri({ key });
|
|
257
|
+
const keyExists = await keyManager.getPublicKey({ keyUri }).then(() => true).catch(() => false);
|
|
258
|
+
if (!keyExists) {
|
|
259
|
+
await keyManager.importKey({ key });
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Validate that the key material for every verification method in the DID document is present
|
|
264
|
+
// in the key manager.
|
|
265
|
+
for (let vm of verificationMethods) {
|
|
266
|
+
if (!vm.publicKeyJwk) {
|
|
267
|
+
throw new Error(`Verification method '${vm.id}' does not contain a public key in JWK format`);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Compute the key URI of the verification method's public key.
|
|
271
|
+
const keyUri = await keyManager.getKeyUri({ key: vm.publicKeyJwk });
|
|
272
|
+
|
|
273
|
+
// Verify that the key is present in the key manager. If not, an error is thrown.
|
|
274
|
+
await keyManager.getPublicKey({ keyUri });
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Use the given PortableDid to construct the BearerDid object.
|
|
278
|
+
const did = new BearerDid({
|
|
279
|
+
uri : portableDid.uri,
|
|
280
|
+
document : portableDid.document,
|
|
281
|
+
metadata : portableDid.metadata,
|
|
282
|
+
keyManager
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return did;
|
|
286
|
+
}
|
|
287
|
+
}
|
package/src/did-error.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A custom error class for DID-related errors.
|
|
3
|
+
*/
|
|
4
|
+
export class DidError extends Error {
|
|
5
|
+
/**
|
|
6
|
+
* Constructs an instance of DidError, a custom error class for handling DID-related errors.
|
|
7
|
+
*
|
|
8
|
+
* @param code - A {@link DidErrorCode} representing the specific type of error encountered.
|
|
9
|
+
* @param message - A human-readable description of the error.
|
|
10
|
+
*/
|
|
11
|
+
constructor(public code: DidErrorCode, message: string) {
|
|
12
|
+
super(`${code}: ${message}`);
|
|
13
|
+
this.name = 'DidError';
|
|
14
|
+
|
|
15
|
+
// Ensures that instanceof works properly, the correct prototype chain when using inheritance,
|
|
16
|
+
// and that V8 stack traces (like Chrome, Edge, and Node.js) are more readable and relevant.
|
|
17
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
18
|
+
|
|
19
|
+
// Captures the stack trace in V8 engines (like Chrome, Edge, and Node.js).
|
|
20
|
+
// In non-V8 environments, the stack trace will still be captured.
|
|
21
|
+
if (Error.captureStackTrace) {
|
|
22
|
+
Error.captureStackTrace(this, DidError);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* An enumeration of possible DID error codes.
|
|
29
|
+
*/
|
|
30
|
+
export enum DidErrorCode {
|
|
31
|
+
/** The DID supplied does not conform to valid syntax. */
|
|
32
|
+
InvalidDid = 'invalidDid',
|
|
33
|
+
|
|
34
|
+
/** The supplied method name is not supported by the DID method and/or DID resolver implementation. */
|
|
35
|
+
MethodNotSupported = 'methodNotSupported',
|
|
36
|
+
|
|
37
|
+
/** An unexpected error occurred during the requested DID operation. */
|
|
38
|
+
InternalError = 'internalError',
|
|
39
|
+
|
|
40
|
+
/** The DID document supplied does not conform to valid syntax. */
|
|
41
|
+
InvalidDidDocument = 'invalidDidDocument',
|
|
42
|
+
|
|
43
|
+
/** The byte length of a DID document does not match the expected value. */
|
|
44
|
+
InvalidDidDocumentLength = 'invalidDidDocumentLength',
|
|
45
|
+
|
|
46
|
+
/** The DID URL supplied to the dereferencing function does not conform to valid syntax. */
|
|
47
|
+
InvalidDidUrl = 'invalidDidUrl',
|
|
48
|
+
|
|
49
|
+
/** The given proof of a previous DID is invalid */
|
|
50
|
+
InvalidPreviousDidProof = 'invalidPreviousDidProof',
|
|
51
|
+
|
|
52
|
+
/** An invalid public key is detected during a DID operation. */
|
|
53
|
+
InvalidPublicKey = 'invalidPublicKey',
|
|
54
|
+
|
|
55
|
+
/** The byte length of a public key does not match the expected value. */
|
|
56
|
+
InvalidPublicKeyLength = 'invalidPublicKeyLength',
|
|
57
|
+
|
|
58
|
+
/** An invalid public key type was detected during a DID operation. */
|
|
59
|
+
InvalidPublicKeyType = 'invalidPublicKeyType',
|
|
60
|
+
|
|
61
|
+
/** Verification of a signature failed during a DID operation. */
|
|
62
|
+
InvalidSignature = 'invalidSignature',
|
|
63
|
+
|
|
64
|
+
/** The DID resolver was unable to find the DID document resulting from the resolution request. */
|
|
65
|
+
NotFound = 'notFound',
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The representation requested via the `accept` input metadata property is not supported by the
|
|
69
|
+
* DID method and/or DID resolver implementation.
|
|
70
|
+
*/
|
|
71
|
+
RepresentationNotSupported = 'representationNotSupported',
|
|
72
|
+
|
|
73
|
+
/** The type of a public key is not supported by the DID method and/or DID resolver implementation. */
|
|
74
|
+
UnsupportedPublicKeyType = 'unsupportedPublicKeyType',
|
|
75
|
+
}
|
package/src/did.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `Did` class represents a Decentralized Identifier (DID) Uniform Resource Identifier (URI).
|
|
3
|
+
*
|
|
4
|
+
* This class provides a method for parsing a DID URI string into its component parts, as well as a
|
|
5
|
+
* method for serializing a DID URI object into a string.
|
|
6
|
+
*
|
|
7
|
+
* A DID URI is composed of the following components:
|
|
8
|
+
* - scheme
|
|
9
|
+
* - method
|
|
10
|
+
* - id
|
|
11
|
+
* - path
|
|
12
|
+
* - query
|
|
13
|
+
* - fragment
|
|
14
|
+
* - params
|
|
15
|
+
*
|
|
16
|
+
* @see {@link https://www.w3.org/TR/did-core/#did-syntax | DID Core Specification, § DID Syntax}
|
|
17
|
+
*/
|
|
18
|
+
export class Did {
|
|
19
|
+
/** Regular expression pattern for matching the method component of a DID URI. */
|
|
20
|
+
static readonly METHOD_PATTERN = '([a-z0-9]+)';
|
|
21
|
+
/** Regular expression pattern for matching percent-encoded characters in a method identifier. */
|
|
22
|
+
static readonly PCT_ENCODED_PATTERN = '(?:%[0-9a-fA-F]{2})';
|
|
23
|
+
/** Regular expression pattern for matching the characters allowed in a method identifier. */
|
|
24
|
+
static readonly ID_CHAR_PATTERN = `(?:[a-zA-Z0-9._-]|${Did.PCT_ENCODED_PATTERN})`;
|
|
25
|
+
/** Regular expression pattern for matching the method identifier component of a DID URI. */
|
|
26
|
+
static readonly METHOD_ID_PATTERN = `((?:${Did.ID_CHAR_PATTERN}*:)*(${Did.ID_CHAR_PATTERN}+))`;
|
|
27
|
+
/** Regular expression pattern for matching the path component of a DID URI. */
|
|
28
|
+
static readonly PATH_PATTERN = `(/[^#?]*)?`;
|
|
29
|
+
/** Regular expression pattern for matching the query component of a DID URI. */
|
|
30
|
+
static readonly QUERY_PATTERN = `([?][^#]*)?`;
|
|
31
|
+
/** Regular expression pattern for matching the fragment component of a DID URI. */
|
|
32
|
+
static readonly FRAGMENT_PATTERN = `(#.*)?`;
|
|
33
|
+
/** Regular expression pattern for matching all of the components of a DID URI. */
|
|
34
|
+
static readonly DID_URI_PATTERN = new RegExp(
|
|
35
|
+
`^did:(?<method>${Did.METHOD_PATTERN}):(?<id>${Did.METHOD_ID_PATTERN})(?<path>${Did.PATH_PATTERN})(?<query>${Did.QUERY_PATTERN})(?<fragment>${Did.FRAGMENT_PATTERN})$`
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A string representation of the DID.
|
|
40
|
+
*
|
|
41
|
+
* A DID is a URI composed of three parts: the scheme `did:`, a method identifier, and a unique,
|
|
42
|
+
* method-specific identifier specified by the DID method.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* did:dht:h4d3ixkwt6q5a455tucw7j14jmqyghdtbr6cpiz6on5oxj5bpr3o
|
|
46
|
+
*/
|
|
47
|
+
uri: string;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The name of the DID method.
|
|
51
|
+
*
|
|
52
|
+
* Examples of DID method names are `dht`, `jwk`, and `web`, among others.
|
|
53
|
+
*/
|
|
54
|
+
method: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The DID method identifier.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* h4d3ixkwt6q5a455tucw7j14jmqyghdtbr6cpiz6on5oxj5bpr3o
|
|
61
|
+
*/
|
|
62
|
+
id: string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Optional path component of the DID URI.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* did:web:tbd.website/path
|
|
69
|
+
*/
|
|
70
|
+
path?: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Optional query component of the DID URI.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* did:web:tbd.website?versionId=1
|
|
77
|
+
*/
|
|
78
|
+
query?: string;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Optional fragment component of the DID URI.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* did:web:tbd.website#key-1
|
|
85
|
+
*/
|
|
86
|
+
fragment?: string;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Optional query parameters in the DID URI.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* did:web:tbd.website?service=files&relativeRef=/whitepaper.pdf
|
|
93
|
+
*/
|
|
94
|
+
params?: Record<string, string>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Constructs a new `Did` instance from individual components.
|
|
98
|
+
*
|
|
99
|
+
* @param params - An object containing the parameters to be included in the DID URI.
|
|
100
|
+
* @param params.method - The name of the DID method.
|
|
101
|
+
* @param params.id - The DID method identifier.
|
|
102
|
+
* @param params.path - Optional. The path component of the DID URI.
|
|
103
|
+
* @param params.query - Optional. The query component of the DID URI.
|
|
104
|
+
* @param params.fragment - Optional. The fragment component of the DID URI.
|
|
105
|
+
* @param params.params - Optional. The query parameters in the DID URI.
|
|
106
|
+
*/
|
|
107
|
+
constructor({ method, id, path, query, fragment, params }: {
|
|
108
|
+
method: string,
|
|
109
|
+
id: string,
|
|
110
|
+
path?: string,
|
|
111
|
+
query?: string,
|
|
112
|
+
fragment?: string,
|
|
113
|
+
params?: Record<string, string>
|
|
114
|
+
}) {
|
|
115
|
+
this.uri = `did:${method}:${id}`;
|
|
116
|
+
this.method = method;
|
|
117
|
+
this.id = id;
|
|
118
|
+
this.path = path;
|
|
119
|
+
this.query = query;
|
|
120
|
+
this.fragment = fragment;
|
|
121
|
+
this.params = params;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Parses a DID URI string into its individual components.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* const did = Did.parse('did:example:123?service=agent&relativeRef=/credentials#degree');
|
|
130
|
+
*
|
|
131
|
+
* console.log(did.uri) // Output: 'did:example:123'
|
|
132
|
+
* console.log(did.method) // Output: 'example'
|
|
133
|
+
* console.log(did.id) // Output: '123'
|
|
134
|
+
* console.log(did.query) // Output: 'service=agent&relativeRef=/credentials'
|
|
135
|
+
* console.log(did.fragment) // Output: 'degree'
|
|
136
|
+
* console.log(did.params) // Output: { service: 'agent', relativeRef: '/credentials' }
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @params didUri - The DID URI string to be parsed.
|
|
140
|
+
* @returns A `Did` object representing the parsed DID URI, or `null` if the input string is not a valid DID URI.
|
|
141
|
+
*/
|
|
142
|
+
static parse(didUri: string): Did | null {
|
|
143
|
+
// Return null if the input string is empty or not provided.
|
|
144
|
+
if (!didUri) return null;
|
|
145
|
+
|
|
146
|
+
// Execute the regex pattern on the input string to extract URI components.
|
|
147
|
+
const match = Did.DID_URI_PATTERN.exec(didUri);
|
|
148
|
+
|
|
149
|
+
// If the pattern does not match, or if the required groups are not found, return null.
|
|
150
|
+
if (!match || !match.groups) return null;
|
|
151
|
+
|
|
152
|
+
// Extract the method, id, params, path, query, and fragment from the regex match groups.
|
|
153
|
+
const { method, id, path, query, fragment } = match.groups;
|
|
154
|
+
|
|
155
|
+
// Initialize a new Did object with the uri, method and id.
|
|
156
|
+
const did: Did = {
|
|
157
|
+
uri: `did:${method}:${id}`,
|
|
158
|
+
method,
|
|
159
|
+
id,
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// If path is present, add it to the Did object.
|
|
163
|
+
if (path) did.path = path;
|
|
164
|
+
|
|
165
|
+
// If query is present, add it to the Did object, removing the leading '?'.
|
|
166
|
+
if (query) did.query = query.slice(1);
|
|
167
|
+
|
|
168
|
+
// If fragment is present, add it to the Did object, removing the leading '#'.
|
|
169
|
+
if (fragment) did.fragment = fragment.slice(1);
|
|
170
|
+
|
|
171
|
+
// If query params are present, parse them into a key-value object and add to the Did object.
|
|
172
|
+
if (query) {
|
|
173
|
+
const parsedParams = {} as Record<string, string>;
|
|
174
|
+
// Split the query string by '&' to get individual parameter strings.
|
|
175
|
+
const paramPairs = query.slice(1).split('&');
|
|
176
|
+
for (const pair of paramPairs) {
|
|
177
|
+
// Split each parameter string by '=' to separate keys and values.
|
|
178
|
+
const [key, value] = pair.split('=');
|
|
179
|
+
parsedParams[key] = value;
|
|
180
|
+
}
|
|
181
|
+
did.params = parsedParams;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return did;
|
|
185
|
+
}
|
|
186
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export * from './types/did-core.js';
|
|
2
|
+
export * from './types/did-resolution.js';
|
|
3
|
+
export type * from './types/multibase.js';
|
|
4
|
+
export type * from './types/portable-did.js';
|
|
5
|
+
|
|
6
|
+
export * from './did.js';
|
|
7
|
+
export * from './did-error.js';
|
|
8
|
+
export * from './bearer-did.js';
|
|
9
|
+
|
|
10
|
+
export * from './methods/did-dht.js';
|
|
11
|
+
export * from './methods/did-ion.js';
|
|
12
|
+
export * from './methods/did-jwk.js';
|
|
13
|
+
export * from './methods/did-key.js';
|
|
14
|
+
export * from './methods/did-method.js';
|
|
15
|
+
export * from './methods/did-web.js';
|
|
16
|
+
|
|
17
|
+
export * from './resolver/resolver-cache-level.js';
|
|
18
|
+
export * from './resolver/resolver-cache-noop.js';
|
|
19
|
+
export * from './resolver/universal-resolver.js';
|
|
20
|
+
|
|
21
|
+
export * as utils from './utils.js';
|