@dwk/vc 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +143 -0
- package/dist/config.d.ts +97 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +62 -0
- package/dist/config.js.map +1 -0
- package/dist/credential.d.ts +70 -0
- package/dist/credential.d.ts.map +1 -0
- package/dist/credential.js +139 -0
- package/dist/credential.js.map +1 -0
- package/dist/data-integrity.d.ts +102 -0
- package/dist/data-integrity.d.ts.map +1 -0
- package/dist/data-integrity.js +253 -0
- package/dist/data-integrity.js.map +1 -0
- package/dist/datetime.d.ts +26 -0
- package/dist/datetime.d.ts.map +1 -0
- package/dist/datetime.js +54 -0
- package/dist/datetime.js.map +1 -0
- package/dist/did-web.d.ts +93 -0
- package/dist/did-web.d.ts.map +1 -0
- package/dist/did-web.js +206 -0
- package/dist/did-web.js.map +1 -0
- package/dist/handler.d.ts +37 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +362 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/jcs.d.ts +31 -0
- package/dist/jcs.d.ts.map +1 -0
- package/dist/jcs.js +67 -0
- package/dist/jcs.js.map +1 -0
- package/dist/log.d.ts +34 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +32 -0
- package/dist/log.js.map +1 -0
- package/dist/multibase.d.ts +57 -0
- package/dist/multibase.d.ts.map +1 -0
- package/dist/multibase.js +165 -0
- package/dist/multibase.js.map +1 -0
- package/dist/status-list.d.ts +116 -0
- package/dist/status-list.d.ts.map +1 -0
- package/dist/status-list.js +241 -0
- package/dist/status-list.js.map +1 -0
- package/package.json +48 -0
- package/src/config.ts +158 -0
- package/src/credential.ts +188 -0
- package/src/data-integrity.ts +425 -0
- package/src/datetime.ts +57 -0
- package/src/did-web.ts +273 -0
- package/src/handler.ts +477 -0
- package/src/index.ts +133 -0
- package/src/jcs.ts +83 -0
- package/src/log.ts +35 -0
- package/src/multibase.ts +189 -0
- package/src/status-list.ts +356 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-integrity.d.ts","sourceRoot":"","sources":["../src/data-integrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAqC,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAQzE,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;CAAE,CAAC;AAEjE,+DAA+D;AAC/D,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAE9D,qDAAqD;AACrD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAE3E;AAED,KAAK,aAAa,GAAG,SAAS,GAAG,SAAS,CAAC;AAK3C,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AACD,KAAK,gBAAgB,GAAG,SAAS,CAAC;AAElC,yEAAyE;AACzE,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CACnC;AA0BD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAmCnE;AA8BD,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,sDAAsD;IACtD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;CAClC;AAED,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG;IAAE,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAEjE;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,UAAU,EACpB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,eAAe,CAAC,CAwB1B;AAED,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;CACpC;AAED,mFAAmF;AACnF,MAAM,MAAM,0BAA0B,GAAG,CACvC,EAAE,EAAE,MAAM,KACP,kBAAkB,GAAG,SAAS,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAAC;AAiE9E,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,QAAQ,CAAC,yBAAyB,EAAE,0BAA0B,CAAC;IAC/D,+DAA+D;IAC/D,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACxC;AAED,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AA6GD;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAW5B"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data Integrity proofs over JSON credentials, using the JCS cryptosuites.
|
|
3
|
+
*
|
|
4
|
+
* Implements `eddsa-jcs-2022` (Ed25519) and `ecdsa-jcs-2019` (ECDSA P-256 /
|
|
5
|
+
* P-384) from the W3C Data Integrity specs. The proof pipeline is:
|
|
6
|
+
*
|
|
7
|
+
* 1. Build a **proof configuration** (the proof object minus `proofValue`),
|
|
8
|
+
* copying the document's `@context`.
|
|
9
|
+
* 2. JCS-canonicalize the proof config and the document-without-proof, hash each
|
|
10
|
+
* with the cryptosuite's digest, and concatenate `proofConfigHash ‖ docHash`.
|
|
11
|
+
* 3. Sign (or verify) that concatenation with the verification key.
|
|
12
|
+
*
|
|
13
|
+
* The proof value is multibase base58-btc. ECDSA signatures use the IEEE P1363
|
|
14
|
+
* (`r ‖ s`) form Web Crypto produces, which is exactly what the cryptosuite
|
|
15
|
+
* expects. Signing/verification mirror the `@dwk/dpop` and `@dwk/http-signatures`
|
|
16
|
+
* posture — asymmetric only, an explicit cryptosuite allow-list, and the key is
|
|
17
|
+
* validated against the claimed cryptosuite.
|
|
18
|
+
*
|
|
19
|
+
* Pure aside from Web Crypto: plain-data in, plain-data out, no runtime bindings.
|
|
20
|
+
*
|
|
21
|
+
* @see https://www.w3.org/TR/vc-di-eddsa/
|
|
22
|
+
* @see https://www.w3.org/TR/vc-di-ecdsa/
|
|
23
|
+
*/
|
|
24
|
+
import { toXsdDateTime } from "./datetime";
|
|
25
|
+
import { canonicalize, canonicalizeToBytes } from "./jcs";
|
|
26
|
+
import { base58btcDecode, decodeMultikey, encodeMultibaseBase58btc, MULTIBASE_BASE58BTC, } from "./multibase";
|
|
27
|
+
/** Whether `value` names a supported cryptosuite. */
|
|
28
|
+
export function isSupportedCryptosuite(value) {
|
|
29
|
+
return value === "eddsa-jcs-2022" || value === "ecdsa-jcs-2019";
|
|
30
|
+
}
|
|
31
|
+
function ecParamsForCurve(curve) {
|
|
32
|
+
if (curve === "P-256") {
|
|
33
|
+
return {
|
|
34
|
+
cryptosuite: "ecdsa-jcs-2019",
|
|
35
|
+
componentHash: "SHA-256",
|
|
36
|
+
params: { name: "ECDSA", hash: "SHA-256" },
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (curve === "P-384") {
|
|
40
|
+
return {
|
|
41
|
+
cryptosuite: "ecdsa-jcs-2019",
|
|
42
|
+
componentHash: "SHA-384",
|
|
43
|
+
params: { name: "ECDSA", hash: "SHA-384" },
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
throw new Error(`@dwk/vc: unsupported EC curve "${curve}" for ecdsa-jcs-2019`);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Import a private signing key from a JWK and resolve the cryptosuite it
|
|
50
|
+
* implies: `OKP`/`Ed25519` → `eddsa-jcs-2022`; `EC`/`P-256`|`P-384` →
|
|
51
|
+
* `ecdsa-jcs-2019`. Throws for unsupported or non-private keys.
|
|
52
|
+
*/
|
|
53
|
+
export async function importSigner(jwk) {
|
|
54
|
+
if (jwk.d === undefined) {
|
|
55
|
+
throw new Error("@dwk/vc: signing key JWK is missing the private `d` member");
|
|
56
|
+
}
|
|
57
|
+
if (jwk.kty === "OKP" && jwk.crv === "Ed25519") {
|
|
58
|
+
const key = await crypto.subtle.importKey("jwk", jwk, { name: "Ed25519" }, false, ["sign"]);
|
|
59
|
+
return {
|
|
60
|
+
key,
|
|
61
|
+
cryptosuite: "eddsa-jcs-2022",
|
|
62
|
+
componentHash: "SHA-256",
|
|
63
|
+
params: { name: "Ed25519" },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (jwk.kty === "EC" && typeof jwk.crv === "string") {
|
|
67
|
+
const ec = ecParamsForCurve(jwk.crv);
|
|
68
|
+
const key = await crypto.subtle.importKey("jwk", jwk, { name: "ECDSA", namedCurve: jwk.crv }, false, ["sign"]);
|
|
69
|
+
return { key, ...ec };
|
|
70
|
+
}
|
|
71
|
+
throw new Error(`@dwk/vc: unsupported signing key (kty=${String(jwk.kty)}, crv=${String(jwk.crv)})`);
|
|
72
|
+
}
|
|
73
|
+
async function digest(hash, bytes) {
|
|
74
|
+
const out = await crypto.subtle.digest(hash, bytes);
|
|
75
|
+
return new Uint8Array(out);
|
|
76
|
+
}
|
|
77
|
+
/** `proofConfigHash ‖ documentHash`, the bytes a JCS cryptosuite signs. */
|
|
78
|
+
async function hashData(proofConfig, document, componentHash) {
|
|
79
|
+
const proofConfigHash = await digest(componentHash, canonicalizeToBytes(proofConfig));
|
|
80
|
+
const documentHash = await digest(componentHash, canonicalizeToBytes(document));
|
|
81
|
+
const out = new Uint8Array(proofConfigHash.length + documentHash.length);
|
|
82
|
+
out.set(proofConfigHash, 0);
|
|
83
|
+
out.set(documentHash, proofConfigHash.length);
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Attach a Data Integrity proof to `document`, returning a new secured document.
|
|
88
|
+
* Any existing `proof` on the input is excluded from the signed payload (a proof
|
|
89
|
+
* never signs over itself).
|
|
90
|
+
*/
|
|
91
|
+
export async function addProof(document, signer, options) {
|
|
92
|
+
const proofConfig = {
|
|
93
|
+
type: "DataIntegrityProof",
|
|
94
|
+
cryptosuite: signer.cryptosuite,
|
|
95
|
+
created: toXsdDateTime(options.created ?? new Date()),
|
|
96
|
+
verificationMethod: options.verificationMethod,
|
|
97
|
+
proofPurpose: options.proofPurpose ?? "assertionMethod",
|
|
98
|
+
};
|
|
99
|
+
// The proof config's `@context` MUST match the document's, when present.
|
|
100
|
+
if (document["@context"] !== undefined) {
|
|
101
|
+
proofConfig["@context"] = document["@context"];
|
|
102
|
+
}
|
|
103
|
+
const { proof: _existing, ...unsigned } = document;
|
|
104
|
+
void _existing;
|
|
105
|
+
const data = await hashData(proofConfig, unsigned, signer.componentHash);
|
|
106
|
+
const signature = await crypto.subtle.sign(signer.params, signer.key, data);
|
|
107
|
+
const proof = {
|
|
108
|
+
...proofConfig,
|
|
109
|
+
proofValue: encodeMultibaseBase58btc(new Uint8Array(signature)),
|
|
110
|
+
};
|
|
111
|
+
return { ...unsigned, proof };
|
|
112
|
+
}
|
|
113
|
+
/** Import a public verification key, requiring it to match `cryptosuite`. */
|
|
114
|
+
async function importVerifier(vm, cryptosuite) {
|
|
115
|
+
if (vm.publicKeyMultibase !== undefined) {
|
|
116
|
+
if (cryptosuite !== "eddsa-jcs-2022") {
|
|
117
|
+
throw new Error("@dwk/vc: publicKeyMultibase (Multikey) requires the eddsa-jcs-2022 cryptosuite");
|
|
118
|
+
}
|
|
119
|
+
const { rawPublicKey } = decodeMultikey(vm.publicKeyMultibase);
|
|
120
|
+
const key = await crypto.subtle.importKey("raw", rawPublicKey, { name: "Ed25519" }, false, ["verify"]);
|
|
121
|
+
return { key, componentHash: "SHA-256", params: { name: "Ed25519" } };
|
|
122
|
+
}
|
|
123
|
+
if (vm.publicKeyJwk !== undefined) {
|
|
124
|
+
const jwk = vm.publicKeyJwk;
|
|
125
|
+
if (cryptosuite === "eddsa-jcs-2022") {
|
|
126
|
+
if (jwk.kty !== "OKP" || jwk.crv !== "Ed25519") {
|
|
127
|
+
throw new Error("@dwk/vc: eddsa-jcs-2022 requires an Ed25519 key");
|
|
128
|
+
}
|
|
129
|
+
const key = await crypto.subtle.importKey("jwk", jwk, { name: "Ed25519" }, false, ["verify"]);
|
|
130
|
+
return { key, componentHash: "SHA-256", params: { name: "Ed25519" } };
|
|
131
|
+
}
|
|
132
|
+
// ecdsa-jcs-2019
|
|
133
|
+
if (jwk.kty !== "EC" || typeof jwk.crv !== "string") {
|
|
134
|
+
throw new Error("@dwk/vc: ecdsa-jcs-2019 requires an EC key");
|
|
135
|
+
}
|
|
136
|
+
const ec = ecParamsForCurve(jwk.crv);
|
|
137
|
+
const key = await crypto.subtle.importKey("jwk", jwk, { name: "ECDSA", namedCurve: jwk.crv }, false, ["verify"]);
|
|
138
|
+
return { key, componentHash: ec.componentHash, params: ec.params };
|
|
139
|
+
}
|
|
140
|
+
throw new Error("@dwk/vc: verification method has neither publicKeyMultibase nor publicKeyJwk");
|
|
141
|
+
}
|
|
142
|
+
function isJsonObject(value) {
|
|
143
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
144
|
+
}
|
|
145
|
+
function asProofArray(proof) {
|
|
146
|
+
if (proof === undefined || proof === null)
|
|
147
|
+
return [];
|
|
148
|
+
if (Array.isArray(proof))
|
|
149
|
+
return proof.filter(isJsonObject);
|
|
150
|
+
return isJsonObject(proof) ? [proof] : [];
|
|
151
|
+
}
|
|
152
|
+
function asContextArray(context) {
|
|
153
|
+
if (context === undefined)
|
|
154
|
+
return [];
|
|
155
|
+
return Array.isArray(context) ? context : [context];
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Whether the document's `@context` begins with every value in the proof's
|
|
159
|
+
* `@context`, in order (vc-di-eddsa §3.3.2 step 4.1). A proof without an
|
|
160
|
+
* `@context` imposes no constraint. Values are compared by JCS canonical form,
|
|
161
|
+
* so embedded context objects match structurally regardless of key order.
|
|
162
|
+
*/
|
|
163
|
+
function contextStartsWith(documentContext, proofContext) {
|
|
164
|
+
const proofArr = asContextArray(proofContext);
|
|
165
|
+
if (proofArr.length === 0)
|
|
166
|
+
return true;
|
|
167
|
+
const docArr = asContextArray(documentContext);
|
|
168
|
+
if (docArr.length < proofArr.length)
|
|
169
|
+
return false;
|
|
170
|
+
for (let i = 0; i < proofArr.length; i++) {
|
|
171
|
+
if (canonicalize(proofArr[i]) !== canonicalize(docArr[i]))
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
async function verifySingleProof(document, proof, options) {
|
|
177
|
+
if (proof.type !== "DataIntegrityProof") {
|
|
178
|
+
return `unsupported proof type "${String(proof.type)}"`;
|
|
179
|
+
}
|
|
180
|
+
if (!isSupportedCryptosuite(proof.cryptosuite)) {
|
|
181
|
+
return `unsupported cryptosuite "${String(proof.cryptosuite)}"`;
|
|
182
|
+
}
|
|
183
|
+
const expectedPurpose = options.expectedProofPurpose ?? "assertionMethod";
|
|
184
|
+
if (proof.proofPurpose !== expectedPurpose) {
|
|
185
|
+
return `proof purpose "${String(proof.proofPurpose)}" does not match expected "${expectedPurpose}"`;
|
|
186
|
+
}
|
|
187
|
+
if (typeof proof.verificationMethod !== "string") {
|
|
188
|
+
return "proof is missing a string verificationMethod";
|
|
189
|
+
}
|
|
190
|
+
if (typeof proof.proofValue !== "string") {
|
|
191
|
+
return "proof is missing a string proofValue";
|
|
192
|
+
}
|
|
193
|
+
// vc-di-eddsa §3.3.2 step 4.1: the secured document's `@context` MUST begin
|
|
194
|
+
// with the proof's `@context` values, in order, or verification fails.
|
|
195
|
+
if (!contextStartsWith(document["@context"], proof["@context"])) {
|
|
196
|
+
return "document @context does not start with the proof's @context values, in order";
|
|
197
|
+
}
|
|
198
|
+
// Both JCS cryptosuites mandate a base58-btc (`z`) proofValue; reject any
|
|
199
|
+
// other multibase encoding (e.g. base64url) rather than silently decoding it.
|
|
200
|
+
if (proof.proofValue[0] !== MULTIBASE_BASE58BTC) {
|
|
201
|
+
return `proofValue must be base58-btc multibase (a "${MULTIBASE_BASE58BTC}" prefix), got "${proof.proofValue[0] ?? ""}"`;
|
|
202
|
+
}
|
|
203
|
+
let signature;
|
|
204
|
+
try {
|
|
205
|
+
signature = base58btcDecode(proof.proofValue.slice(1));
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
return `proofValue is not valid base58-btc: ${error.message}`;
|
|
209
|
+
}
|
|
210
|
+
const vm = await options.resolveVerificationMethod(proof.verificationMethod);
|
|
211
|
+
if (vm === undefined) {
|
|
212
|
+
return `could not resolve verification method "${proof.verificationMethod}"`;
|
|
213
|
+
}
|
|
214
|
+
let verifier;
|
|
215
|
+
try {
|
|
216
|
+
verifier = await importVerifier(vm, proof.cryptosuite);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
return error.message;
|
|
220
|
+
}
|
|
221
|
+
const { proofValue: _pv, ...proofConfig } = proof;
|
|
222
|
+
void _pv;
|
|
223
|
+
const { proof: _existing, ...unsigned } = document;
|
|
224
|
+
void _existing;
|
|
225
|
+
const data = await hashData(proofConfig, unsigned, verifier.componentHash);
|
|
226
|
+
let ok;
|
|
227
|
+
try {
|
|
228
|
+
ok = await crypto.subtle.verify(verifier.params, verifier.key, signature, data);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
return `signature verification threw: ${error.message}`;
|
|
232
|
+
}
|
|
233
|
+
return ok ? null : "signature verification failed";
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Verify the Data Integrity proof(s) on `document`. A document with no proof, or
|
|
237
|
+
* any proof that fails, yields `verified: false` with the reasons collected in
|
|
238
|
+
* `errors`. Never throws — verification failures are returned, not raised.
|
|
239
|
+
*/
|
|
240
|
+
export async function verifyProof(document, options) {
|
|
241
|
+
const proofs = asProofArray(document.proof);
|
|
242
|
+
if (proofs.length === 0) {
|
|
243
|
+
return { verified: false, errors: ["document has no proof"] };
|
|
244
|
+
}
|
|
245
|
+
const errors = [];
|
|
246
|
+
for (const proof of proofs) {
|
|
247
|
+
const error = await verifySingleProof(document, proof, options);
|
|
248
|
+
if (error !== null)
|
|
249
|
+
errors.push(error);
|
|
250
|
+
}
|
|
251
|
+
return { verified: errors.length === 0, errors };
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=data-integrity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-integrity.js","sourceRoot":"","sources":["../src/data-integrity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XSD `dateTimeStamp` validation and canonicalization for VC date fields.
|
|
3
|
+
*
|
|
4
|
+
* VCDM 2.0 and the Data Integrity suites express temporal values — a
|
|
5
|
+
* credential's `validFrom`/`validUntil` and a proof's `created` — as XSD
|
|
6
|
+
* `dateTimeStamp` strings: an `xsd:dateTime` with a **mandatory** timezone
|
|
7
|
+
* offset. vc-di-eddsa §3.3.5 step 3 requires erroring on an invalid `created`,
|
|
8
|
+
* and a verifier must not silently treat a malformed `validUntil` as "no
|
|
9
|
+
* expiry". These pure helpers gate both, so unparseable datetimes fail loudly
|
|
10
|
+
* (at signing) or fail closed (at verification) rather than slipping through.
|
|
11
|
+
*
|
|
12
|
+
* @see https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Whether `value` is a valid XSD `dateTimeStamp`: a well-formed `xsd:dateTime`
|
|
16
|
+
* carrying a mandatory timezone that also denotes a real calendar date (so
|
|
17
|
+
* lexically-shaped-but-impossible dates like `2026-02-30` are rejected).
|
|
18
|
+
*/
|
|
19
|
+
export declare function isValidXsdDateTimeStamp(value: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Canonicalize a date value to a second-precision XSD `dateTimeStamp`. A `Date`
|
|
22
|
+
* is rendered in UTC (milliseconds dropped); a string is validated and passed
|
|
23
|
+
* through unchanged. Throws when a string is not a valid XSD `dateTimeStamp`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function toXsdDateTime(value: Date | string): string;
|
|
26
|
+
//# sourceMappingURL=datetime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datetime.d.ts","sourceRoot":"","sources":["../src/datetime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAgBH;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAO9D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAS1D"}
|
package/dist/datetime.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XSD `dateTimeStamp` validation and canonicalization for VC date fields.
|
|
3
|
+
*
|
|
4
|
+
* VCDM 2.0 and the Data Integrity suites express temporal values — a
|
|
5
|
+
* credential's `validFrom`/`validUntil` and a proof's `created` — as XSD
|
|
6
|
+
* `dateTimeStamp` strings: an `xsd:dateTime` with a **mandatory** timezone
|
|
7
|
+
* offset. vc-di-eddsa §3.3.5 step 3 requires erroring on an invalid `created`,
|
|
8
|
+
* and a verifier must not silently treat a malformed `validUntil` as "no
|
|
9
|
+
* expiry". These pure helpers gate both, so unparseable datetimes fail loudly
|
|
10
|
+
* (at signing) or fail closed (at verification) rather than slipping through.
|
|
11
|
+
*
|
|
12
|
+
* @see https://www.w3.org/TR/xmlschema11-2/#dateTimeStamp
|
|
13
|
+
*/
|
|
14
|
+
// xsd:dateTimeStamp — an xsd:dateTime that REQUIRES an explicit timezone (`Z`
|
|
15
|
+
// or `±HH:MM`). Mirrors the W3C XML Schema 1.1 lexical space. The day-of-month
|
|
16
|
+
// upper bound (28–31) is checked separately against the actual month/year.
|
|
17
|
+
const XSD_DATE_TIME_STAMP = /^(-?(?:[1-9][0-9]{3,}|0[0-9]{3}))-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T(?:([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](?:\.[0-9]+)?|24:00:00(?:\.0+)?)(?:Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))$/;
|
|
18
|
+
function daysInMonth(year, month) {
|
|
19
|
+
if (month === 2) {
|
|
20
|
+
const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
21
|
+
return leap ? 29 : 28;
|
|
22
|
+
}
|
|
23
|
+
return month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Whether `value` is a valid XSD `dateTimeStamp`: a well-formed `xsd:dateTime`
|
|
27
|
+
* carrying a mandatory timezone that also denotes a real calendar date (so
|
|
28
|
+
* lexically-shaped-but-impossible dates like `2026-02-30` are rejected).
|
|
29
|
+
*/
|
|
30
|
+
export function isValidXsdDateTimeStamp(value) {
|
|
31
|
+
const match = XSD_DATE_TIME_STAMP.exec(value);
|
|
32
|
+
if (match === null)
|
|
33
|
+
return false;
|
|
34
|
+
const year = Number(match[1]);
|
|
35
|
+
const month = Number(match[2]);
|
|
36
|
+
const day = Number(match[3]);
|
|
37
|
+
return day <= daysInMonth(year, month);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Canonicalize a date value to a second-precision XSD `dateTimeStamp`. A `Date`
|
|
41
|
+
* is rendered in UTC (milliseconds dropped); a string is validated and passed
|
|
42
|
+
* through unchanged. Throws when a string is not a valid XSD `dateTimeStamp`.
|
|
43
|
+
*/
|
|
44
|
+
export function toXsdDateTime(value) {
|
|
45
|
+
if (typeof value === "string") {
|
|
46
|
+
if (!isValidXsdDateTimeStamp(value)) {
|
|
47
|
+
throw new Error(`@dwk/vc: "${value}" is not a valid XSD dateTimeStamp`);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
// Drop milliseconds for the canonical, second-precision VC form.
|
|
52
|
+
return value.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=datetime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datetime.js","sourceRoot":"","sources":["../src/datetime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,8EAA8E;AAC9E,+EAA+E;AAC/E,2EAA2E;AAC3E,MAAM,mBAAmB,GACvB,yMAAyM,CAAC;AAE5M,SAAS,WAAW,CAAC,IAAY,EAAE,KAAa;IAC9C,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACxB,CAAC;IACD,OAAO,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACjC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7B,OAAO,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAoB;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,aAAa,KAAK,oCAAoC,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,iEAAiE;IACjE,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `did:web` ↔ URL mapping, DID-document construction, and verification-method
|
|
3
|
+
* resolution.
|
|
4
|
+
*
|
|
5
|
+
* The DID document itself (`/.well-known/did.json`) is a static artifact a static
|
|
6
|
+
* host can serve — {@link buildDidDocument} produces it — so this package does
|
|
7
|
+
* not need a Worker to *resolve* a DID. The Worker side uses
|
|
8
|
+
* {@link createDidWebResolver} during VC verification to fetch a credential
|
|
9
|
+
* issuer's DID document and locate the verification key referenced by a proof.
|
|
10
|
+
*
|
|
11
|
+
* Method/URL mapping follows the did:web rules: the first colon-separated
|
|
12
|
+
* component is the host (with a `%3A`-encoded port), remaining components are
|
|
13
|
+
* path segments, and a bare host resolves under `/.well-known/`.
|
|
14
|
+
*
|
|
15
|
+
* @see https://w3c-ccg.github.io/did-method-web/
|
|
16
|
+
*/
|
|
17
|
+
import type { JsonObject, VerificationMethod } from "./data-integrity";
|
|
18
|
+
/** The default did:web context documents emitted by {@link buildDidDocument}. */
|
|
19
|
+
export declare const DID_CONTEXT_V1 = "https://www.w3.org/ns/did/v1";
|
|
20
|
+
export declare const MULTIKEY_CONTEXT_V1 = "https://w3id.org/security/multikey/v1";
|
|
21
|
+
export declare const JWK_CONTEXT_V1 = "https://w3id.org/security/jwk/v1";
|
|
22
|
+
/**
|
|
23
|
+
* Convert a `did:web` identifier to the URL of its DID document. Throws if the
|
|
24
|
+
* input is not a `did:web` identifier.
|
|
25
|
+
*/
|
|
26
|
+
export declare function didWebToUrl(did: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Derive the `did:web` identifier a URL (or host) would publish. A bare origin
|
|
29
|
+
* (or one whose path is `/.well-known/did.json`) maps to `did:web:<host>`; a
|
|
30
|
+
* deeper path maps its segments to colon-separated components.
|
|
31
|
+
*/
|
|
32
|
+
export declare function urlToDidWeb(input: string): string;
|
|
33
|
+
/** Input describing one verification method to publish in a DID document. */
|
|
34
|
+
export interface VerificationMethodInput {
|
|
35
|
+
/** Method id. A bare fragment (`#key-0`) is resolved against the DID. */
|
|
36
|
+
readonly id: string;
|
|
37
|
+
/** Method type. Defaults to `"Multikey"` (or `"JsonWebKey"` for a JWK). */
|
|
38
|
+
readonly type?: string;
|
|
39
|
+
readonly publicKeyMultibase?: string;
|
|
40
|
+
readonly publicKeyJwk?: JsonWebKey;
|
|
41
|
+
}
|
|
42
|
+
/** Verification relationships a method can be referenced by. */
|
|
43
|
+
export interface VerificationRelationships {
|
|
44
|
+
/** Reference under `assertionMethod` (issuing credentials). Default `true`. */
|
|
45
|
+
readonly assertionMethod?: boolean;
|
|
46
|
+
/** Reference under `authentication`. Default `false`. */
|
|
47
|
+
readonly authentication?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/** Options for {@link buildDidDocument}. */
|
|
50
|
+
export interface BuildDidDocumentOptions {
|
|
51
|
+
readonly did: string;
|
|
52
|
+
readonly verificationMethods: readonly VerificationMethodInput[];
|
|
53
|
+
/** Relationships applied to every supplied method. */
|
|
54
|
+
readonly relationships?: VerificationRelationships;
|
|
55
|
+
/** Optional `alsoKnownAs` identifiers (e.g. an `https:` WebID). */
|
|
56
|
+
readonly alsoKnownAs?: readonly string[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build a `did:web` DID document from public verification methods. Emits the
|
|
60
|
+
* DID, Multikey, and (when a JWK method is present) JWK context documents, the
|
|
61
|
+
* `verificationMethod` array, and the requested verification relationships
|
|
62
|
+
* (defaulting to `assertionMethod`). Suitable for serialization to
|
|
63
|
+
* `/.well-known/did.json`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildDidDocument(options: BuildDidDocumentOptions): JsonObject;
|
|
66
|
+
/**
|
|
67
|
+
* Locate a verification method in a DID document by its id. A method `id` that
|
|
68
|
+
* is a relative reference (`#key-0`) is resolved against the document's `id`
|
|
69
|
+
* before comparison, per DID Core — foreign documents commonly use relative ids.
|
|
70
|
+
*/
|
|
71
|
+
export declare function findVerificationMethod(didDocument: JsonObject, id: string): VerificationMethod | undefined;
|
|
72
|
+
/** A minimal `fetch` used to retrieve DID documents. */
|
|
73
|
+
export type FetchLike = (input: string, init?: {
|
|
74
|
+
headers?: Record<string, string>;
|
|
75
|
+
}) => Promise<{
|
|
76
|
+
ok: boolean;
|
|
77
|
+
status: number;
|
|
78
|
+
json: () => Promise<unknown>;
|
|
79
|
+
}>;
|
|
80
|
+
/** Options for {@link createDidWebResolver}. */
|
|
81
|
+
export interface DidWebResolverOptions {
|
|
82
|
+
/** Override the fetch implementation (defaults to the global `fetch`). */
|
|
83
|
+
readonly fetch?: FetchLike;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build a {@link VerificationMethodResolver} that resolves a `did:web`
|
|
87
|
+
* verification-method id by fetching the controller's DID document over HTTPS
|
|
88
|
+
* and locating the referenced method. Returns `undefined` for non-`did:web`
|
|
89
|
+
* ids, fetch failures, and unknown methods — verification treats that as an
|
|
90
|
+
* unresolvable key rather than throwing.
|
|
91
|
+
*/
|
|
92
|
+
export declare function createDidWebResolver(options?: DidWebResolverOptions): (id: string) => Promise<VerificationMethod | undefined>;
|
|
93
|
+
//# sourceMappingURL=did-web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"did-web.d.ts","sourceRoot":"","sources":["../src/did-web.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAIvE,iFAAiF;AACjF,eAAO,MAAM,cAAc,iCAAiC,CAAC;AAC7D,eAAO,MAAM,mBAAmB,0CAA0C,CAAC;AAC3E,eAAO,MAAM,cAAc,qCAAqC,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA+B/C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAkBjD;AAED,6EAA6E;AAC7E,MAAM,WAAW,uBAAuB;IACtC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;CACpC;AAED,gEAAgE;AAChE,MAAM,WAAW,yBAAyB;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,yDAAyD;IACzD,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,mBAAmB,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACjE,sDAAsD;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,yBAAyB,CAAC;IACnD,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAMD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,UAAU,CAkD7E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,UAAU,EACvB,EAAE,EAAE,MAAM,GACT,kBAAkB,GAAG,SAAS,CAgBhC;AAED,wDAAwD;AACxD,MAAM,MAAM,SAAS,GAAG,CACtB,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KACxC,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC,CAAC;AAE5E,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,qBAA0B,GAClC,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CA8CzD"}
|