@metalabel/dfos-protocol 0.44.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chain/index.d.ts +14 -4
- package/dist/chain/index.js +8 -1
- package/dist/chunk-JVSC67DC.js +981 -0
- package/dist/{chunk-4YBXPYEU.js → chunk-ZRA7FRBE.js} +248 -28
- package/dist/credentials/index.d.ts +1 -1
- package/dist/{dfos-credential-X6uvPIth.d.ts → dfos-credential-BtiYPqBT.d.ts} +118 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +24 -2
- package/dist/key-proof/index.d.ts +203 -20
- package/dist/key-proof/index.js +17 -1
- package/examples/identity-restore.json +3 -3
- package/examples/identity-rotation.json +1 -1
- package/package.json +3 -2
- package/dist/chunk-VEJBAY3T.js +0 -200
package/dist/chunk-VEJBAY3T.js
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ED25519_PUB_MULTICODEC,
|
|
3
|
-
decodeMultikey,
|
|
4
|
-
encodeEd25519Multikey
|
|
5
|
-
} from "./chunk-IDVYITX7.js";
|
|
6
|
-
import {
|
|
7
|
-
base64urlDecode,
|
|
8
|
-
base64urlEncode,
|
|
9
|
-
importEd25519Keypair,
|
|
10
|
-
isValidEd25519Signature,
|
|
11
|
-
signPayloadEd25519
|
|
12
|
-
} from "./chunk-4LG2GEB2.js";
|
|
13
|
-
|
|
14
|
-
// src/key-proof/key-proof.ts
|
|
15
|
-
var KEY_ADD_JWS_TYP = "did:dfos:key-add";
|
|
16
|
-
var MAX_KEY_PROOF_SIZE = 4096;
|
|
17
|
-
var DEFAULT_KEY_PROOF_SKEW_SECONDS = 300;
|
|
18
|
-
var KeyProofVerifyError = class extends Error {
|
|
19
|
-
reason;
|
|
20
|
-
constructor(reason, message) {
|
|
21
|
-
super(message);
|
|
22
|
-
this.name = "KeyProofVerifyError";
|
|
23
|
-
this.reason = reason;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
var invalid = (reason, message) => new KeyProofVerifyError(reason, `invalid key proof: ${message}`);
|
|
27
|
-
var encoder = new TextEncoder();
|
|
28
|
-
var KEY_PROOF_MEMBERS = ["nonce", "audience", "publicKeyMultibase", "timestamp"];
|
|
29
|
-
var LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
|
|
30
|
-
var WHOLE_SECOND_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.000Z$/;
|
|
31
|
-
var PROTOCOL_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
32
|
-
var validateKeyProofPayload = (value) => {
|
|
33
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
34
|
-
throw invalid("schema", "expected a JSON object");
|
|
35
|
-
}
|
|
36
|
-
const raw = value;
|
|
37
|
-
for (const member of Object.keys(raw)) {
|
|
38
|
-
if (!KEY_PROOF_MEMBERS.includes(member)) {
|
|
39
|
-
throw invalid("schema", `unknown member ${JSON.stringify(member)} \u2014 the payload is closed`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
for (const member of KEY_PROOF_MEMBERS) {
|
|
43
|
-
if (typeof raw[member] !== "string" || raw[member] === "") {
|
|
44
|
-
throw invalid("schema", `${member} must be a non-empty string`);
|
|
45
|
-
}
|
|
46
|
-
if (LONE_SURROGATE.test(raw[member])) {
|
|
47
|
-
throw invalid("schema", `${member} must be well-formed Unicode`);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
const nonce = raw["nonce"];
|
|
51
|
-
const audience = raw["audience"];
|
|
52
|
-
const publicKeyMultibase = raw["publicKeyMultibase"];
|
|
53
|
-
const timestamp = raw["timestamp"];
|
|
54
|
-
if (audience !== audience.toLowerCase() || /[\s/\\?#]/.test(audience)) {
|
|
55
|
-
throw invalid("schema", "audience must be a lowercase authority, without a scheme or path");
|
|
56
|
-
}
|
|
57
|
-
const parsedMs = WHOLE_SECOND_TIMESTAMP.test(timestamp) ? Date.parse(timestamp) : Number.NaN;
|
|
58
|
-
if (!Number.isFinite(parsedMs) || new Date(parsedMs).toISOString() !== timestamp) {
|
|
59
|
-
throw invalid("schema", "timestamp must be ISO-8601 UTC whole-second .000Z");
|
|
60
|
-
}
|
|
61
|
-
return { nonce, audience, publicKeyMultibase, timestamp };
|
|
62
|
-
};
|
|
63
|
-
var keyProofSigningInput = (payload) => encoder.encode(JSON.stringify(keyProofPayloadObject(validateKeyProofPayload(payload))));
|
|
64
|
-
var keyProofPayloadObject = (payload) => ({
|
|
65
|
-
nonce: payload.nonce,
|
|
66
|
-
audience: payload.audience,
|
|
67
|
-
publicKeyMultibase: payload.publicKeyMultibase,
|
|
68
|
-
timestamp: payload.timestamp
|
|
69
|
-
});
|
|
70
|
-
var bytesEqual = (a, b) => a.length === b.length && a.every((byte, index) => byte === b[index]);
|
|
71
|
-
var normalizeTimestamp = (ms) => new Date(Math.floor(ms / 1e3) * 1e3).toISOString();
|
|
72
|
-
var signKeyProof = async (input) => {
|
|
73
|
-
if (input.typ === "") {
|
|
74
|
-
throw new Error("invalid key proof: typ must be a registered purpose value");
|
|
75
|
-
}
|
|
76
|
-
const { publicKey } = importEd25519Keypair(input.privateKey);
|
|
77
|
-
let timestamp;
|
|
78
|
-
if (input.timestamp === void 0) {
|
|
79
|
-
timestamp = normalizeTimestamp(input.now ? input.now() : Date.now());
|
|
80
|
-
} else {
|
|
81
|
-
const ms = Date.parse(input.timestamp);
|
|
82
|
-
if (!PROTOCOL_TIMESTAMP.test(input.timestamp) || !Number.isFinite(ms) || new Date(ms).toISOString() !== input.timestamp) {
|
|
83
|
-
throw new Error(`invalid key proof: unparseable timestamp: ${input.timestamp}`);
|
|
84
|
-
}
|
|
85
|
-
timestamp = normalizeTimestamp(ms);
|
|
86
|
-
}
|
|
87
|
-
const payload = validateKeyProofPayload({
|
|
88
|
-
nonce: input.nonce,
|
|
89
|
-
audience: input.audience,
|
|
90
|
-
publicKeyMultibase: encodeEd25519Multikey(publicKey),
|
|
91
|
-
timestamp
|
|
92
|
-
});
|
|
93
|
-
const headerB64 = base64urlEncode(JSON.stringify({ alg: "EdDSA", typ: input.typ }));
|
|
94
|
-
const payloadB64 = base64urlEncode(keyProofSigningInput(payload));
|
|
95
|
-
const signingInput = `${headerB64}.${payloadB64}`;
|
|
96
|
-
const signature = signPayloadEd25519(encoder.encode(signingInput), input.privateKey);
|
|
97
|
-
const proof = `${signingInput}.${base64urlEncode(signature)}`;
|
|
98
|
-
if (proof.length > MAX_KEY_PROOF_SIZE) {
|
|
99
|
-
throw new Error(`key proof exceeds max size: ${proof.length} > ${MAX_KEY_PROOF_SIZE}`);
|
|
100
|
-
}
|
|
101
|
-
return { proof, payload };
|
|
102
|
-
};
|
|
103
|
-
var verifyKeyProof = (jws, options) => {
|
|
104
|
-
if (options.expectedTyp === "") {
|
|
105
|
-
throw new Error("invalid key proof verifier: expectedTyp must be a registered purpose value");
|
|
106
|
-
}
|
|
107
|
-
const maxSkew = options.maxSkewSeconds ?? DEFAULT_KEY_PROOF_SKEW_SECONDS;
|
|
108
|
-
if (!Number.isSafeInteger(maxSkew) || maxSkew < 0) {
|
|
109
|
-
throw new Error("invalid key proof verifier: maxSkewSeconds must be a non-negative integer");
|
|
110
|
-
}
|
|
111
|
-
if (jws.length > MAX_KEY_PROOF_SIZE) {
|
|
112
|
-
throw invalid("size", `envelope exceeds max size: ${jws.length} > ${MAX_KEY_PROOF_SIZE}`);
|
|
113
|
-
}
|
|
114
|
-
const parts = jws.split(".");
|
|
115
|
-
if (parts.length !== 3) throw invalid("header", "failed to decode JWS");
|
|
116
|
-
const [headerB64, payloadB64] = parts;
|
|
117
|
-
let header;
|
|
118
|
-
try {
|
|
119
|
-
const decoded = JSON.parse(
|
|
120
|
-
new TextDecoder("utf-8", { fatal: true }).decode(base64urlDecode(headerB64))
|
|
121
|
-
);
|
|
122
|
-
if (typeof decoded !== "object" || decoded === null || Array.isArray(decoded)) {
|
|
123
|
-
throw new Error("protected header must be an object");
|
|
124
|
-
}
|
|
125
|
-
header = decoded;
|
|
126
|
-
} catch (err) {
|
|
127
|
-
throw invalid("header", err instanceof Error ? err.message : "failed to decode header");
|
|
128
|
-
}
|
|
129
|
-
if (header["alg"] !== "EdDSA") {
|
|
130
|
-
throw invalid("header", `unsupported algorithm: ${String(header["alg"])}`);
|
|
131
|
-
}
|
|
132
|
-
if ("crit" in header) throw invalid("header", "crit header is not supported");
|
|
133
|
-
for (const member of ["jwk", "jku", "x5c", "x5u"]) {
|
|
134
|
-
if (member in header) {
|
|
135
|
-
throw invalid("header", `${member} header is not allowed (the key rides in the payload)`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if ("kid" in header) {
|
|
139
|
-
throw invalid("header", "kid must be absent \u2014 the candidate key is in no chain");
|
|
140
|
-
}
|
|
141
|
-
const typ = header["typ"];
|
|
142
|
-
if (typeof typ !== "string" || typ !== options.expectedTyp) {
|
|
143
|
-
throw invalid("header", `invalid typ: expected ${options.expectedTyp}, got ${String(typ)}`);
|
|
144
|
-
}
|
|
145
|
-
let payload;
|
|
146
|
-
try {
|
|
147
|
-
const payloadBytes = base64urlDecode(payloadB64);
|
|
148
|
-
const source = new TextDecoder("utf-8", { fatal: true }).decode(payloadBytes);
|
|
149
|
-
payload = validateKeyProofPayload(JSON.parse(source));
|
|
150
|
-
if (!bytesEqual(keyProofSigningInput(payload), payloadBytes)) {
|
|
151
|
-
throw invalid("schema", "payload is not the canonical signing input for its members");
|
|
152
|
-
}
|
|
153
|
-
} catch (err) {
|
|
154
|
-
if (err instanceof KeyProofVerifyError) throw err;
|
|
155
|
-
throw invalid("schema", err instanceof Error ? err.message : "payload is not valid UTF-8 JSON");
|
|
156
|
-
}
|
|
157
|
-
if (payload.audience !== options.expectedAudience) {
|
|
158
|
-
throw invalid("audience", "audience does not match this verifier authority");
|
|
159
|
-
}
|
|
160
|
-
const now = Math.floor((options.now ? options.now() : Date.now()) / 1e3);
|
|
161
|
-
const issued = Math.floor(Date.parse(payload.timestamp) / 1e3);
|
|
162
|
-
if (Math.abs(now - issued) > maxSkew) {
|
|
163
|
-
throw invalid("freshness", "timestamp is outside the acceptance window");
|
|
164
|
-
}
|
|
165
|
-
let keyBytes;
|
|
166
|
-
try {
|
|
167
|
-
const decoded = decodeMultikey(payload.publicKeyMultibase);
|
|
168
|
-
if (decoded.codec !== ED25519_PUB_MULTICODEC) {
|
|
169
|
-
throw new Error("publicKeyMultibase is not an Ed25519 public key");
|
|
170
|
-
}
|
|
171
|
-
keyBytes = decoded.keyBytes;
|
|
172
|
-
} catch (err) {
|
|
173
|
-
throw invalid(
|
|
174
|
-
"signature",
|
|
175
|
-
err instanceof Error ? err.message : "undecodable publicKeyMultibase"
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
let verified = false;
|
|
179
|
-
try {
|
|
180
|
-
verified = isValidEd25519Signature(
|
|
181
|
-
encoder.encode(`${headerB64}.${payloadB64}`),
|
|
182
|
-
base64urlDecode(parts[2]),
|
|
183
|
-
keyBytes
|
|
184
|
-
);
|
|
185
|
-
} catch {
|
|
186
|
-
verified = false;
|
|
187
|
-
}
|
|
188
|
-
if (!verified) throw invalid("signature", "signature does not verify against publicKeyMultibase");
|
|
189
|
-
return { payload, typ, now };
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
export {
|
|
193
|
-
KEY_ADD_JWS_TYP,
|
|
194
|
-
MAX_KEY_PROOF_SIZE,
|
|
195
|
-
DEFAULT_KEY_PROOF_SKEW_SECONDS,
|
|
196
|
-
KeyProofVerifyError,
|
|
197
|
-
keyProofSigningInput,
|
|
198
|
-
signKeyProof,
|
|
199
|
-
verifyKeyProof
|
|
200
|
-
};
|