@oma3/omatrust 0.1.0-alpha.11 → 0.1.0-alpha.12
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/README.md +3 -0
- package/dist/app-registry/index.cjs +53 -0
- package/dist/app-registry/index.cjs.map +1 -1
- package/dist/app-registry/index.js +53 -0
- package/dist/app-registry/index.js.map +1 -1
- package/dist/identity/index.cjs +643 -164
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.d.cts +2 -2
- package/dist/identity/index.d.ts +2 -2
- package/dist/identity/index.js +616 -165
- package/dist/identity/index.js.map +1 -1
- package/dist/{index-QueRiudB.d.cts → index-B5OC9_8B.d.cts} +155 -4
- package/dist/index-Bu-xxcv9.d.ts +407 -0
- package/dist/{index-C2w5EvFH.d.ts → index-C6WNgPRx.d.ts} +155 -4
- package/dist/index-C7odEbp6.d.cts +407 -0
- package/dist/index.cjs +1000 -185
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +981 -185
- package/dist/index.js.map +1 -1
- package/dist/reputation/index.browser.cjs +153 -148
- package/dist/reputation/index.browser.cjs.map +1 -1
- package/dist/reputation/index.browser.js +153 -148
- package/dist/reputation/index.browser.js.map +1 -1
- package/dist/reputation/index.cjs +477 -140
- package/dist/reputation/index.cjs.map +1 -1
- package/dist/reputation/index.d.cts +2 -2
- package/dist/reputation/index.d.ts +2 -2
- package/dist/reputation/index.js +475 -141
- package/dist/reputation/index.js.map +1 -1
- package/dist/{types-dpYxRq8N.d.cts → types-Dn0OwaNj.d.cts} +37 -11
- package/dist/{types-dpYxRq8N.d.ts → types-Dn0OwaNj.d.ts} +37 -11
- package/dist/widgets/index.cjs.map +1 -1
- package/dist/widgets/index.d.cts +3 -0
- package/dist/widgets/index.d.ts +3 -0
- package/dist/widgets/index.js.map +1 -1
- package/package.json +4 -2
- package/dist/index-BOvk-7Ku.d.cts +0 -235
- package/dist/index-R78TpAhN.d.ts +0 -235
package/dist/identity/index.cjs
CHANGED
|
@@ -3,10 +3,34 @@
|
|
|
3
3
|
var ethers = require('ethers');
|
|
4
4
|
var jose = require('jose');
|
|
5
5
|
var canonicalize = require('canonicalize');
|
|
6
|
+
var cid = require('multiformats/cid');
|
|
7
|
+
var sha2 = require('multiformats/hashes/sha2');
|
|
8
|
+
var raw = require('multiformats/codecs/raw');
|
|
9
|
+
var base32 = require('multiformats/bases/base32');
|
|
10
|
+
var base58 = require('multiformats/bases/base58');
|
|
6
11
|
|
|
7
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
13
|
|
|
14
|
+
function _interopNamespace(e) {
|
|
15
|
+
if (e && e.__esModule) return e;
|
|
16
|
+
var n = Object.create(null);
|
|
17
|
+
if (e) {
|
|
18
|
+
Object.keys(e).forEach(function (k) {
|
|
19
|
+
if (k !== 'default') {
|
|
20
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
21
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return e[k]; }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
n.default = e;
|
|
29
|
+
return Object.freeze(n);
|
|
30
|
+
}
|
|
31
|
+
|
|
9
32
|
var canonicalize__default = /*#__PURE__*/_interopDefault(canonicalize);
|
|
33
|
+
var raw__namespace = /*#__PURE__*/_interopNamespace(raw);
|
|
10
34
|
|
|
11
35
|
// src/identity/did.ts
|
|
12
36
|
|
|
@@ -14,23 +38,23 @@ var canonicalize__default = /*#__PURE__*/_interopDefault(canonicalize);
|
|
|
14
38
|
var OmaTrustError = class extends Error {
|
|
15
39
|
code;
|
|
16
40
|
details;
|
|
17
|
-
constructor(
|
|
41
|
+
constructor(code2, message, details) {
|
|
18
42
|
super(message);
|
|
19
43
|
this.name = "OmaTrustError";
|
|
20
|
-
this.code =
|
|
44
|
+
this.code = code2;
|
|
21
45
|
this.details = details;
|
|
22
46
|
}
|
|
23
47
|
};
|
|
24
48
|
|
|
25
49
|
// src/shared/assert.ts
|
|
26
|
-
function assertString(value, name,
|
|
50
|
+
function assertString(value, name, code2 = "INVALID_INPUT") {
|
|
27
51
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
28
|
-
throw new OmaTrustError(
|
|
52
|
+
throw new OmaTrustError(code2, `${name} must be a non-empty string`, { value });
|
|
29
53
|
}
|
|
30
54
|
}
|
|
31
|
-
function assertObject(value, name,
|
|
55
|
+
function assertObject(value, name, code2 = "INVALID_INPUT") {
|
|
32
56
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
33
|
-
throw new OmaTrustError(
|
|
57
|
+
throw new OmaTrustError(code2, `${name} must be an object`, { value });
|
|
34
58
|
}
|
|
35
59
|
}
|
|
36
60
|
|
|
@@ -87,6 +111,158 @@ function parseCaip2(caip2) {
|
|
|
87
111
|
}
|
|
88
112
|
return { namespace, reference };
|
|
89
113
|
}
|
|
114
|
+
var VALID_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
|
|
115
|
+
var PRIVATE_KEY_FIELDS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
|
|
116
|
+
var REQUIRED_PUBLIC_FIELDS = {
|
|
117
|
+
EC: ["crv", "x", "y"],
|
|
118
|
+
OKP: ["crv", "x"],
|
|
119
|
+
RSA: ["n", "e"]
|
|
120
|
+
};
|
|
121
|
+
function validatePublicJwk(jwk) {
|
|
122
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
123
|
+
return { valid: false, error: "JWK must be a non-null object" };
|
|
124
|
+
}
|
|
125
|
+
const obj = jwk;
|
|
126
|
+
const kty = obj.kty;
|
|
127
|
+
if (typeof kty !== "string" || !VALID_KTY.has(kty)) {
|
|
128
|
+
return {
|
|
129
|
+
valid: false,
|
|
130
|
+
error: `Invalid or missing kty (must be one of: ${[...VALID_KTY].join(", ")})`
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
for (const field of PRIVATE_KEY_FIELDS) {
|
|
134
|
+
if (field in obj) {
|
|
135
|
+
return {
|
|
136
|
+
valid: false,
|
|
137
|
+
error: `JWK contains private key field "${field}" \u2014 only public keys are allowed`
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const required = REQUIRED_PUBLIC_FIELDS[kty];
|
|
142
|
+
if (required) {
|
|
143
|
+
for (const field of required) {
|
|
144
|
+
if (!(field in obj) || obj[field] === void 0 || obj[field] === null || obj[field] === "") {
|
|
145
|
+
return {
|
|
146
|
+
valid: false,
|
|
147
|
+
error: `Missing required public key field "${field}" for kty="${kty}"`
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { valid: true };
|
|
153
|
+
}
|
|
154
|
+
function canonicalizeJwkJson(jwk) {
|
|
155
|
+
const sorted = Object.keys(jwk).sort();
|
|
156
|
+
const obj = {};
|
|
157
|
+
for (const key of sorted) {
|
|
158
|
+
obj[key] = jwk[key];
|
|
159
|
+
}
|
|
160
|
+
return JSON.stringify(obj);
|
|
161
|
+
}
|
|
162
|
+
function jwkToDidJwk(jwk) {
|
|
163
|
+
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
164
|
+
const validation = validatePublicJwk(jwk);
|
|
165
|
+
if (!validation.valid) {
|
|
166
|
+
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
167
|
+
}
|
|
168
|
+
const canonical = canonicalizeJwkJson(jwk);
|
|
169
|
+
const encoded = jose.base64url.encode(new TextEncoder().encode(canonical));
|
|
170
|
+
return `did:jwk:${encoded}`;
|
|
171
|
+
}
|
|
172
|
+
function didJwkToJwk(didJwk) {
|
|
173
|
+
if (typeof didJwk !== "string" || !didJwk.startsWith("did:jwk:")) {
|
|
174
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:jwk DID", { input: didJwk });
|
|
175
|
+
}
|
|
176
|
+
const parts = didJwk.split(":");
|
|
177
|
+
if (parts.length !== 3) {
|
|
178
|
+
throw new OmaTrustError("INVALID_DID", "did:jwk must have exactly 3 colon-separated parts", {
|
|
179
|
+
input: didJwk
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const encoded = parts[2];
|
|
183
|
+
if (!encoded || encoded.length === 0) {
|
|
184
|
+
throw new OmaTrustError("INVALID_DID", "Missing base64url-encoded JWK identifier", {
|
|
185
|
+
input: didJwk
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
let decoded;
|
|
189
|
+
try {
|
|
190
|
+
const bytes = jose.base64url.decode(encoded);
|
|
191
|
+
decoded = new TextDecoder().decode(bytes);
|
|
192
|
+
} catch {
|
|
193
|
+
throw new OmaTrustError("INVALID_DID", "Failed to base64url-decode did:jwk identifier", {
|
|
194
|
+
input: didJwk
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
let jwk;
|
|
198
|
+
try {
|
|
199
|
+
jwk = JSON.parse(decoded);
|
|
200
|
+
} catch {
|
|
201
|
+
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk identifier is not valid JSON", {
|
|
202
|
+
input: didJwk
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
206
|
+
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk must be a JSON object", {
|
|
207
|
+
input: didJwk
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
const validation = validatePublicJwk(jwk);
|
|
211
|
+
if (!validation.valid) {
|
|
212
|
+
throw new OmaTrustError("INVALID_DID", validation.error ?? "Invalid public JWK in did:jwk", {
|
|
213
|
+
input: didJwk
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return jwk;
|
|
217
|
+
}
|
|
218
|
+
function extractPublicKeyFields(jwk) {
|
|
219
|
+
const result = {};
|
|
220
|
+
const metadataFields = /* @__PURE__ */ new Set(["kid", "use", "key_ops", "alg", "ext"]);
|
|
221
|
+
for (const [key, value] of Object.entries(jwk)) {
|
|
222
|
+
if (PRIVATE_KEY_FIELDS.has(key)) continue;
|
|
223
|
+
if (metadataFields.has(key)) continue;
|
|
224
|
+
result[key] = value;
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
function publicJwkEquals(a, b) {
|
|
229
|
+
assertObject(a, "a", "INVALID_JWK");
|
|
230
|
+
assertObject(b, "b", "INVALID_JWK");
|
|
231
|
+
const aObj = a;
|
|
232
|
+
const bObj = b;
|
|
233
|
+
for (const field of PRIVATE_KEY_FIELDS) {
|
|
234
|
+
if (field in aObj) {
|
|
235
|
+
throw new OmaTrustError(
|
|
236
|
+
"INVALID_JWK",
|
|
237
|
+
`First JWK contains private key field "${field}"`,
|
|
238
|
+
{ field }
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
if (field in bObj) {
|
|
242
|
+
throw new OmaTrustError(
|
|
243
|
+
"INVALID_JWK",
|
|
244
|
+
`Second JWK contains private key field "${field}"`,
|
|
245
|
+
{ field }
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const aPublic = extractPublicKeyFields(aObj);
|
|
250
|
+
const bPublic = extractPublicKeyFields(bObj);
|
|
251
|
+
return canonicalizeJwkJson(aPublic) === canonicalizeJwkJson(bPublic);
|
|
252
|
+
}
|
|
253
|
+
async function computeJwkThumbprint(jwk, digestAlgorithm = "sha256") {
|
|
254
|
+
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
255
|
+
const validation = validatePublicJwk(jwk);
|
|
256
|
+
if (!validation.valid) {
|
|
257
|
+
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
258
|
+
}
|
|
259
|
+
const alg = digestAlgorithm === "sha256" ? "sha256" : digestAlgorithm === "sha384" ? "sha384" : "sha512";
|
|
260
|
+
return jose.calculateJwkThumbprint(jwk, alg);
|
|
261
|
+
}
|
|
262
|
+
async function formatJktValue(jwk) {
|
|
263
|
+
const thumbprint = await computeJwkThumbprint(jwk, "sha256");
|
|
264
|
+
return `jkt=S256:${thumbprint}`;
|
|
265
|
+
}
|
|
90
266
|
|
|
91
267
|
// src/identity/did.ts
|
|
92
268
|
var DID_REGEX = /^did:[a-z0-9]+:.+$/i;
|
|
@@ -162,7 +338,7 @@ function normalizeDidKey(input) {
|
|
|
162
338
|
}
|
|
163
339
|
function normalizeDid(input) {
|
|
164
340
|
assertString(input, "input", "INVALID_DID");
|
|
165
|
-
const trimmed = input.trim();
|
|
341
|
+
const trimmed = input.trim().split("#")[0];
|
|
166
342
|
if (!trimmed.startsWith("did:")) {
|
|
167
343
|
return normalizeDidWeb(trimmed);
|
|
168
344
|
}
|
|
@@ -351,6 +527,15 @@ function validateDidPkh(did) {
|
|
|
351
527
|
};
|
|
352
528
|
}
|
|
353
529
|
}
|
|
530
|
+
if (namespace === "solana") {
|
|
531
|
+
if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address)) {
|
|
532
|
+
return {
|
|
533
|
+
valid: false,
|
|
534
|
+
method: "pkh",
|
|
535
|
+
error: `Invalid Solana address "${address}" (must be 32-44 base58 characters)`
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
}
|
|
354
539
|
return { valid: true, method: "pkh" };
|
|
355
540
|
}
|
|
356
541
|
function validateDidJwk(did) {
|
|
@@ -404,6 +589,10 @@ function validateDidJwk(did) {
|
|
|
404
589
|
error: "DID must reference a public key \u2014 private key component (d) is not allowed"
|
|
405
590
|
};
|
|
406
591
|
}
|
|
592
|
+
const jwkValidation = validatePublicJwk(jwk);
|
|
593
|
+
if (!jwkValidation.valid) {
|
|
594
|
+
return { valid: false, method: "jwk", error: jwkValidation.error };
|
|
595
|
+
}
|
|
407
596
|
return { valid: true, method: "jwk" };
|
|
408
597
|
}
|
|
409
598
|
function normalizeDidJwk(input) {
|
|
@@ -470,158 +659,6 @@ function assertBareDid(input, paramName = "did") {
|
|
|
470
659
|
);
|
|
471
660
|
}
|
|
472
661
|
}
|
|
473
|
-
var VALID_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
|
|
474
|
-
var PRIVATE_KEY_FIELDS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
|
|
475
|
-
var REQUIRED_PUBLIC_FIELDS = {
|
|
476
|
-
EC: ["crv", "x", "y"],
|
|
477
|
-
OKP: ["crv", "x"],
|
|
478
|
-
RSA: ["n", "e"]
|
|
479
|
-
};
|
|
480
|
-
function validatePublicJwk(jwk) {
|
|
481
|
-
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
482
|
-
return { valid: false, error: "JWK must be a non-null object" };
|
|
483
|
-
}
|
|
484
|
-
const obj = jwk;
|
|
485
|
-
const kty = obj.kty;
|
|
486
|
-
if (typeof kty !== "string" || !VALID_KTY.has(kty)) {
|
|
487
|
-
return {
|
|
488
|
-
valid: false,
|
|
489
|
-
error: `Invalid or missing kty (must be one of: ${[...VALID_KTY].join(", ")})`
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
for (const field of PRIVATE_KEY_FIELDS) {
|
|
493
|
-
if (field in obj) {
|
|
494
|
-
return {
|
|
495
|
-
valid: false,
|
|
496
|
-
error: `JWK contains private key field "${field}" \u2014 only public keys are allowed`
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
const required = REQUIRED_PUBLIC_FIELDS[kty];
|
|
501
|
-
if (required) {
|
|
502
|
-
for (const field of required) {
|
|
503
|
-
if (!(field in obj) || obj[field] === void 0 || obj[field] === null || obj[field] === "") {
|
|
504
|
-
return {
|
|
505
|
-
valid: false,
|
|
506
|
-
error: `Missing required public key field "${field}" for kty="${kty}"`
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
return { valid: true };
|
|
512
|
-
}
|
|
513
|
-
function canonicalizeJwkJson(jwk) {
|
|
514
|
-
const sorted = Object.keys(jwk).sort();
|
|
515
|
-
const obj = {};
|
|
516
|
-
for (const key of sorted) {
|
|
517
|
-
obj[key] = jwk[key];
|
|
518
|
-
}
|
|
519
|
-
return JSON.stringify(obj);
|
|
520
|
-
}
|
|
521
|
-
function jwkToDidJwk(jwk) {
|
|
522
|
-
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
523
|
-
const validation = validatePublicJwk(jwk);
|
|
524
|
-
if (!validation.valid) {
|
|
525
|
-
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
526
|
-
}
|
|
527
|
-
const canonical = canonicalizeJwkJson(jwk);
|
|
528
|
-
const encoded = jose.base64url.encode(new TextEncoder().encode(canonical));
|
|
529
|
-
return `did:jwk:${encoded}`;
|
|
530
|
-
}
|
|
531
|
-
function didJwkToJwk(didJwk) {
|
|
532
|
-
if (typeof didJwk !== "string" || !didJwk.startsWith("did:jwk:")) {
|
|
533
|
-
throw new OmaTrustError("INVALID_DID", "Expected a did:jwk DID", { input: didJwk });
|
|
534
|
-
}
|
|
535
|
-
const parts = didJwk.split(":");
|
|
536
|
-
if (parts.length !== 3) {
|
|
537
|
-
throw new OmaTrustError("INVALID_DID", "did:jwk must have exactly 3 colon-separated parts", {
|
|
538
|
-
input: didJwk
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
const encoded = parts[2];
|
|
542
|
-
if (!encoded || encoded.length === 0) {
|
|
543
|
-
throw new OmaTrustError("INVALID_DID", "Missing base64url-encoded JWK identifier", {
|
|
544
|
-
input: didJwk
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
let decoded;
|
|
548
|
-
try {
|
|
549
|
-
const bytes = jose.base64url.decode(encoded);
|
|
550
|
-
decoded = new TextDecoder().decode(bytes);
|
|
551
|
-
} catch {
|
|
552
|
-
throw new OmaTrustError("INVALID_DID", "Failed to base64url-decode did:jwk identifier", {
|
|
553
|
-
input: didJwk
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
let jwk;
|
|
557
|
-
try {
|
|
558
|
-
jwk = JSON.parse(decoded);
|
|
559
|
-
} catch {
|
|
560
|
-
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk identifier is not valid JSON", {
|
|
561
|
-
input: didJwk
|
|
562
|
-
});
|
|
563
|
-
}
|
|
564
|
-
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
565
|
-
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk must be a JSON object", {
|
|
566
|
-
input: didJwk
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
const validation = validatePublicJwk(jwk);
|
|
570
|
-
if (!validation.valid) {
|
|
571
|
-
throw new OmaTrustError("INVALID_DID", validation.error ?? "Invalid public JWK in did:jwk", {
|
|
572
|
-
input: didJwk
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
return jwk;
|
|
576
|
-
}
|
|
577
|
-
function extractPublicKeyFields(jwk) {
|
|
578
|
-
const result = {};
|
|
579
|
-
const metadataFields = /* @__PURE__ */ new Set(["kid", "use", "key_ops", "alg", "ext"]);
|
|
580
|
-
for (const [key, value] of Object.entries(jwk)) {
|
|
581
|
-
if (PRIVATE_KEY_FIELDS.has(key)) continue;
|
|
582
|
-
if (metadataFields.has(key)) continue;
|
|
583
|
-
result[key] = value;
|
|
584
|
-
}
|
|
585
|
-
return result;
|
|
586
|
-
}
|
|
587
|
-
function publicJwkEquals(a, b) {
|
|
588
|
-
assertObject(a, "a", "INVALID_JWK");
|
|
589
|
-
assertObject(b, "b", "INVALID_JWK");
|
|
590
|
-
const aObj = a;
|
|
591
|
-
const bObj = b;
|
|
592
|
-
for (const field of PRIVATE_KEY_FIELDS) {
|
|
593
|
-
if (field in aObj) {
|
|
594
|
-
throw new OmaTrustError(
|
|
595
|
-
"INVALID_JWK",
|
|
596
|
-
`First JWK contains private key field "${field}"`,
|
|
597
|
-
{ field }
|
|
598
|
-
);
|
|
599
|
-
}
|
|
600
|
-
if (field in bObj) {
|
|
601
|
-
throw new OmaTrustError(
|
|
602
|
-
"INVALID_JWK",
|
|
603
|
-
`Second JWK contains private key field "${field}"`,
|
|
604
|
-
{ field }
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
const aPublic = extractPublicKeyFields(aObj);
|
|
609
|
-
const bPublic = extractPublicKeyFields(bObj);
|
|
610
|
-
return canonicalizeJwkJson(aPublic) === canonicalizeJwkJson(bPublic);
|
|
611
|
-
}
|
|
612
|
-
async function computeJwkThumbprint(jwk, digestAlgorithm = "sha256") {
|
|
613
|
-
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
614
|
-
const validation = validatePublicJwk(jwk);
|
|
615
|
-
if (!validation.valid) {
|
|
616
|
-
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
617
|
-
}
|
|
618
|
-
const alg = digestAlgorithm === "sha256" ? "sha256" : digestAlgorithm === "sha384" ? "sha384" : "sha512";
|
|
619
|
-
return jose.calculateJwkThumbprint(jwk, alg);
|
|
620
|
-
}
|
|
621
|
-
async function formatJktValue(jwk) {
|
|
622
|
-
const thumbprint = await computeJwkThumbprint(jwk, "sha256");
|
|
623
|
-
return `jkt=S256:${thumbprint}`;
|
|
624
|
-
}
|
|
625
662
|
|
|
626
663
|
// src/shared/did-document.ts
|
|
627
664
|
async function fetchDidDocument(domain) {
|
|
@@ -784,7 +821,7 @@ function extractControllerEvmAddress(controllerDid) {
|
|
|
784
821
|
function extractAuthorizationMetadata(result) {
|
|
785
822
|
const payload = result.payload;
|
|
786
823
|
const resourceUrl = typeof payload.resourceUrl === "string" ? payload.resourceUrl : null;
|
|
787
|
-
const issuedAt = typeof payload.issuedAt === "string" ? payload.issuedAt : null;
|
|
824
|
+
const issuedAt = typeof payload.issuedAt === "string" ? payload.issuedAt : typeof payload.issuedAt === "number" ? payload.issuedAt : null;
|
|
788
825
|
let subjectDid = null;
|
|
789
826
|
if (resourceUrl) {
|
|
790
827
|
try {
|
|
@@ -793,48 +830,487 @@ function extractAuthorizationMetadata(result) {
|
|
|
793
830
|
} catch {
|
|
794
831
|
}
|
|
795
832
|
}
|
|
833
|
+
if ("publicKeyDid" in result) {
|
|
834
|
+
const jwsResult = result;
|
|
835
|
+
return {
|
|
836
|
+
controllerDid: jwsResult.publicKeyDid,
|
|
837
|
+
subjectDid,
|
|
838
|
+
resourceUrl,
|
|
839
|
+
issuedAt,
|
|
840
|
+
kid: jwsResult.kid,
|
|
841
|
+
publicKeyJwk: jwsResult.publicKeyJwk,
|
|
842
|
+
signer: null
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
const eip712Result = result;
|
|
846
|
+
const signerAddress = eip712Result.signer.toLowerCase();
|
|
796
847
|
return {
|
|
797
|
-
controllerDid:
|
|
848
|
+
controllerDid: `did:pkh:eip155:1:${signerAddress}`,
|
|
798
849
|
subjectDid,
|
|
799
850
|
resourceUrl,
|
|
800
851
|
issuedAt,
|
|
801
|
-
kid:
|
|
802
|
-
publicKeyJwk:
|
|
852
|
+
kid: null,
|
|
853
|
+
publicKeyJwk: null,
|
|
854
|
+
signer: eip712Result.signer
|
|
803
855
|
};
|
|
804
856
|
}
|
|
857
|
+
var VALID_ALGORITHMS = /* @__PURE__ */ new Set(["keccak256", "sha256"]);
|
|
858
|
+
var MAX_JSON_DEPTH = 32;
|
|
859
|
+
function assertDepthLimit(depth, context) {
|
|
860
|
+
if (depth > MAX_JSON_DEPTH) {
|
|
861
|
+
const msg = context ? `JSON nesting depth exceeds maximum of ${MAX_JSON_DEPTH} at ${context}` : `JSON nesting depth exceeds maximum of ${MAX_JSON_DEPTH}`;
|
|
862
|
+
throw new OmaTrustError("INVALID_INPUT", msg);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
function parseJsonStrict(input) {
|
|
866
|
+
if (typeof input !== "string") {
|
|
867
|
+
throw new OmaTrustError("INVALID_INPUT", "Input must be a string");
|
|
868
|
+
}
|
|
869
|
+
const duplicateKeys = detectDuplicateKeys(input);
|
|
870
|
+
if (duplicateKeys.length > 0) {
|
|
871
|
+
throw new OmaTrustError(
|
|
872
|
+
"INVALID_INPUT",
|
|
873
|
+
`Duplicate JSON key${duplicateKeys.length > 1 ? "s" : ""} detected: ${duplicateKeys.map((k) => `"${k}"`).join(", ")}`,
|
|
874
|
+
{ duplicateKeys }
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
try {
|
|
878
|
+
return JSON.parse(input);
|
|
879
|
+
} catch {
|
|
880
|
+
throw new OmaTrustError("INVALID_INPUT", "Input is not valid JSON");
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
function detectDuplicateKeys(input) {
|
|
884
|
+
const duplicates = [];
|
|
885
|
+
const objectKeyStack = [];
|
|
886
|
+
let inString = false;
|
|
887
|
+
let escaped = false;
|
|
888
|
+
let currentKey = "";
|
|
889
|
+
let collectingKey = false;
|
|
890
|
+
let afterColon = false;
|
|
891
|
+
let i = 0;
|
|
892
|
+
while (i < input.length) {
|
|
893
|
+
const ch = input[i];
|
|
894
|
+
if (escaped) {
|
|
895
|
+
if (collectingKey) currentKey += ch;
|
|
896
|
+
escaped = false;
|
|
897
|
+
i++;
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
if (ch === "\\") {
|
|
901
|
+
escaped = true;
|
|
902
|
+
if (collectingKey) currentKey += ch;
|
|
903
|
+
i++;
|
|
904
|
+
continue;
|
|
905
|
+
}
|
|
906
|
+
if (ch === '"') {
|
|
907
|
+
if (!inString) {
|
|
908
|
+
inString = true;
|
|
909
|
+
if (objectKeyStack.length > 0 && !afterColon) {
|
|
910
|
+
collectingKey = true;
|
|
911
|
+
currentKey = "";
|
|
912
|
+
}
|
|
913
|
+
} else {
|
|
914
|
+
inString = false;
|
|
915
|
+
if (collectingKey) {
|
|
916
|
+
collectingKey = false;
|
|
917
|
+
const keySet = objectKeyStack[objectKeyStack.length - 1];
|
|
918
|
+
if (keySet.has(currentKey)) {
|
|
919
|
+
if (!duplicates.includes(currentKey)) {
|
|
920
|
+
duplicates.push(currentKey);
|
|
921
|
+
}
|
|
922
|
+
} else {
|
|
923
|
+
keySet.add(currentKey);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
i++;
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
930
|
+
if (inString) {
|
|
931
|
+
if (collectingKey) currentKey += ch;
|
|
932
|
+
i++;
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
if (ch === "{") {
|
|
936
|
+
objectKeyStack.push(/* @__PURE__ */ new Set());
|
|
937
|
+
assertDepthLimit(objectKeyStack.length);
|
|
938
|
+
afterColon = false;
|
|
939
|
+
} else if (ch === "}") {
|
|
940
|
+
objectKeyStack.pop();
|
|
941
|
+
afterColon = objectKeyStack.length > 0;
|
|
942
|
+
} else if (ch === "[") {
|
|
943
|
+
objectKeyStack.push(/* @__PURE__ */ new Set(["__array__"]));
|
|
944
|
+
assertDepthLimit(objectKeyStack.length);
|
|
945
|
+
afterColon = false;
|
|
946
|
+
} else if (ch === "]") {
|
|
947
|
+
objectKeyStack.pop();
|
|
948
|
+
afterColon = objectKeyStack.length > 0;
|
|
949
|
+
} else if (ch === ":") {
|
|
950
|
+
afterColon = true;
|
|
951
|
+
} else if (ch === ",") {
|
|
952
|
+
afterColon = false;
|
|
953
|
+
}
|
|
954
|
+
i++;
|
|
955
|
+
}
|
|
956
|
+
return duplicates;
|
|
957
|
+
}
|
|
958
|
+
function assertJsonSafe(value, path = "$", depth = 0) {
|
|
959
|
+
assertDepthLimit(depth, path);
|
|
960
|
+
if (value === void 0) {
|
|
961
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: undefined`);
|
|
962
|
+
}
|
|
963
|
+
if (value === null) return;
|
|
964
|
+
switch (typeof value) {
|
|
965
|
+
case "string":
|
|
966
|
+
case "boolean":
|
|
967
|
+
return;
|
|
968
|
+
case "number":
|
|
969
|
+
if (!Number.isFinite(value)) {
|
|
970
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: ${value} (must be finite number)`);
|
|
971
|
+
}
|
|
972
|
+
return;
|
|
973
|
+
case "bigint":
|
|
974
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: BigInt (use number or string)`);
|
|
975
|
+
case "function":
|
|
976
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: function`);
|
|
977
|
+
case "symbol":
|
|
978
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: Symbol`);
|
|
979
|
+
case "object":
|
|
980
|
+
if (value instanceof Date) {
|
|
981
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: Date (use ISO string or timestamp)`);
|
|
982
|
+
}
|
|
983
|
+
if (value instanceof RegExp) {
|
|
984
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: RegExp`);
|
|
985
|
+
}
|
|
986
|
+
if (Array.isArray(value)) {
|
|
987
|
+
for (let i = 0; i < value.length; i++) {
|
|
988
|
+
assertJsonSafe(value[i], `${path}[${i}]`, depth + 1);
|
|
989
|
+
}
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
for (const [key, val] of Object.entries(value)) {
|
|
993
|
+
assertJsonSafe(val, `${path}.${key}`, depth + 1);
|
|
994
|
+
}
|
|
995
|
+
return;
|
|
996
|
+
default:
|
|
997
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: unknown type "${typeof value}"`);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
805
1000
|
function canonicalizeJson(obj) {
|
|
1001
|
+
assertJsonSafe(obj);
|
|
806
1002
|
const jcs = canonicalize__default.default(obj);
|
|
807
1003
|
if (!jcs) {
|
|
808
1004
|
throw new OmaTrustError("INVALID_INPUT", "Object cannot be canonicalized", { obj });
|
|
809
1005
|
}
|
|
810
1006
|
return jcs;
|
|
811
1007
|
}
|
|
812
|
-
function
|
|
1008
|
+
function canonicalizeAndKeccak256(obj) {
|
|
813
1009
|
const jcsJson = canonicalizeJson(obj);
|
|
814
1010
|
return {
|
|
815
1011
|
jcsJson,
|
|
816
1012
|
hash: ethers.keccak256(ethers.toUtf8Bytes(jcsJson))
|
|
817
1013
|
};
|
|
818
1014
|
}
|
|
1015
|
+
function canonicalizeForHash(obj) {
|
|
1016
|
+
return canonicalizeAndKeccak256(obj);
|
|
1017
|
+
}
|
|
819
1018
|
function hashCanonicalizedJson(obj, algorithm) {
|
|
1019
|
+
if (!VALID_ALGORITHMS.has(algorithm)) {
|
|
1020
|
+
throw new OmaTrustError("INVALID_INPUT", `Unsupported hash algorithm: "${algorithm}". Must be "keccak256" or "sha256".`, { algorithm });
|
|
1021
|
+
}
|
|
820
1022
|
const jcs = canonicalizeJson(obj);
|
|
821
1023
|
const bytes = ethers.toUtf8Bytes(jcs);
|
|
822
1024
|
return algorithm === "keccak256" ? ethers.keccak256(bytes) : ethers.sha256(bytes);
|
|
823
1025
|
}
|
|
1026
|
+
var DID_ARTIFACT_PREFIX = "did:artifact:";
|
|
1027
|
+
var CID_VERSION = 1;
|
|
1028
|
+
var RAW_CODEC = raw__namespace.code;
|
|
1029
|
+
var SHA2_256_CODE = 18;
|
|
1030
|
+
var SHA2_256_DIGEST_LENGTH = 32;
|
|
1031
|
+
async function artifactDidFromBytes(bytes) {
|
|
1032
|
+
if (!(bytes instanceof Uint8Array) || bytes.length === 0) {
|
|
1033
|
+
throw new OmaTrustError(
|
|
1034
|
+
"INVALID_INPUT",
|
|
1035
|
+
"bytes must be a non-empty Uint8Array"
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1038
|
+
const digest = await sha2.sha256.digest(bytes);
|
|
1039
|
+
const cid$1 = cid.CID.createV1(RAW_CODEC, digest);
|
|
1040
|
+
return `${DID_ARTIFACT_PREFIX}${cid$1.toString(base32.base32)}`;
|
|
1041
|
+
}
|
|
1042
|
+
async function artifactDidFromJson(input) {
|
|
1043
|
+
const value = typeof input === "string" ? parseJsonStrict(input) : input;
|
|
1044
|
+
const jcs = canonicalizeJson(value);
|
|
1045
|
+
const bytes = new TextEncoder().encode(jcs);
|
|
1046
|
+
const digest = await sha2.sha256.digest(bytes);
|
|
1047
|
+
const cid$1 = cid.CID.createV1(RAW_CODEC, digest);
|
|
1048
|
+
return `${DID_ARTIFACT_PREFIX}${cid$1.toString(base32.base32)}`;
|
|
1049
|
+
}
|
|
1050
|
+
function parseArtifactDid(did) {
|
|
1051
|
+
if (typeof did !== "string" || !did.startsWith(DID_ARTIFACT_PREFIX)) {
|
|
1052
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:artifact DID", { did });
|
|
1053
|
+
}
|
|
1054
|
+
const identifier = did.slice(DID_ARTIFACT_PREFIX.length);
|
|
1055
|
+
if (!identifier || identifier.length === 0) {
|
|
1056
|
+
throw new OmaTrustError("INVALID_DID", "Missing method-specific identifier", { did });
|
|
1057
|
+
}
|
|
1058
|
+
if (identifier[0] !== "b") {
|
|
1059
|
+
throw new OmaTrustError(
|
|
1060
|
+
"INVALID_DID",
|
|
1061
|
+
`Invalid multibase prefix "${identifier[0]}", expected "b" (base32lower)`,
|
|
1062
|
+
{ did }
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
let cid$1;
|
|
1066
|
+
try {
|
|
1067
|
+
cid$1 = cid.CID.parse(identifier, base32.base32);
|
|
1068
|
+
} catch (err) {
|
|
1069
|
+
throw new OmaTrustError(
|
|
1070
|
+
"INVALID_DID",
|
|
1071
|
+
"Failed to decode base32 CID from did:artifact identifier",
|
|
1072
|
+
{ did, cause: err }
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
if (cid$1.version !== CID_VERSION) {
|
|
1076
|
+
throw new OmaTrustError(
|
|
1077
|
+
"INVALID_DID",
|
|
1078
|
+
`CID version must be 1, got ${cid$1.version}`,
|
|
1079
|
+
{ did }
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
if (cid$1.code !== RAW_CODEC) {
|
|
1083
|
+
throw new OmaTrustError(
|
|
1084
|
+
"INVALID_DID",
|
|
1085
|
+
`Multicodec must be raw (0x55), got 0x${cid$1.code.toString(16)}`,
|
|
1086
|
+
{ did }
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
if (cid$1.multihash.code !== SHA2_256_CODE) {
|
|
1090
|
+
throw new OmaTrustError(
|
|
1091
|
+
"INVALID_DID",
|
|
1092
|
+
`Multihash function must be sha2-256 (0x12), got 0x${cid$1.multihash.code.toString(16)}`,
|
|
1093
|
+
{ did }
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
if (cid$1.multihash.digest.length !== SHA2_256_DIGEST_LENGTH) {
|
|
1097
|
+
throw new OmaTrustError(
|
|
1098
|
+
"INVALID_DID",
|
|
1099
|
+
`SHA-256 digest must be 32 bytes, got ${cid$1.multihash.digest.length}`,
|
|
1100
|
+
{ did }
|
|
1101
|
+
);
|
|
1102
|
+
}
|
|
1103
|
+
const digest = cid$1.multihash.digest;
|
|
1104
|
+
const digestHex = Array.from(digest).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1105
|
+
return { did, identifier, digest, digestHex };
|
|
1106
|
+
}
|
|
1107
|
+
async function verifyDidArtifact(did, content) {
|
|
1108
|
+
let parsed;
|
|
1109
|
+
try {
|
|
1110
|
+
parsed = parseArtifactDid(did);
|
|
1111
|
+
} catch (err) {
|
|
1112
|
+
return {
|
|
1113
|
+
valid: false,
|
|
1114
|
+
reason: err instanceof OmaTrustError ? err.message : "Invalid did:artifact DID"
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
const expectedHex = parsed.digestHex;
|
|
1118
|
+
if (typeof content === "string" || typeof content === "object" && content !== null && !(content instanceof Uint8Array)) {
|
|
1119
|
+
try {
|
|
1120
|
+
const value = typeof content === "string" ? parseJsonStrict(content) : content;
|
|
1121
|
+
const jcs = canonicalizeJson(value);
|
|
1122
|
+
const jcsBytes = new TextEncoder().encode(jcs);
|
|
1123
|
+
const digest2 = await sha2.sha256.digest(jcsBytes);
|
|
1124
|
+
const digestHex2 = Array.from(digest2.digest).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1125
|
+
if (digestHex2 === expectedHex) {
|
|
1126
|
+
return { valid: true, matchedAs: "json" };
|
|
1127
|
+
}
|
|
1128
|
+
} catch {
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
let rawBytes;
|
|
1132
|
+
if (content instanceof Uint8Array) {
|
|
1133
|
+
rawBytes = content;
|
|
1134
|
+
} else if (typeof content === "string") {
|
|
1135
|
+
rawBytes = new TextEncoder().encode(content);
|
|
1136
|
+
} else {
|
|
1137
|
+
return {
|
|
1138
|
+
valid: false,
|
|
1139
|
+
reason: "Content did not match as canonical JSON and is not raw bytes"
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
const digest = await sha2.sha256.digest(rawBytes);
|
|
1143
|
+
const digestHex = Array.from(digest.digest).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1144
|
+
if (digestHex === expectedHex) {
|
|
1145
|
+
return { valid: true, matchedAs: "binary" };
|
|
1146
|
+
}
|
|
1147
|
+
return {
|
|
1148
|
+
valid: false,
|
|
1149
|
+
reason: "Content does not match the did:artifact identifier (neither as canonical JSON nor as raw bytes)"
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
function didEthrToDidPkh(did) {
|
|
1153
|
+
if (typeof did !== "string" || !did.startsWith("did:ethr:")) {
|
|
1154
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:ethr DID", { did });
|
|
1155
|
+
}
|
|
1156
|
+
const remainder = did.slice("did:ethr:".length);
|
|
1157
|
+
if (!remainder) {
|
|
1158
|
+
throw new OmaTrustError("INVALID_DID", "Missing identifier in did:ethr DID", { did });
|
|
1159
|
+
}
|
|
1160
|
+
let chainId;
|
|
1161
|
+
let address;
|
|
1162
|
+
const parts = remainder.split(":");
|
|
1163
|
+
if (parts.length === 1) {
|
|
1164
|
+
chainId = "1";
|
|
1165
|
+
address = parts[0];
|
|
1166
|
+
} else if (parts.length === 2) {
|
|
1167
|
+
const rawChainId = parts[0];
|
|
1168
|
+
address = parts[1];
|
|
1169
|
+
if (rawChainId.startsWith("0x")) {
|
|
1170
|
+
chainId = String(parseInt(rawChainId, 16));
|
|
1171
|
+
} else if (/^\d+$/.test(rawChainId)) {
|
|
1172
|
+
chainId = rawChainId;
|
|
1173
|
+
} else {
|
|
1174
|
+
const networkMap = {
|
|
1175
|
+
mainnet: "1",
|
|
1176
|
+
goerli: "5",
|
|
1177
|
+
sepolia: "11155111",
|
|
1178
|
+
polygon: "137",
|
|
1179
|
+
arbitrum: "42161",
|
|
1180
|
+
optimism: "10",
|
|
1181
|
+
base: "8453"
|
|
1182
|
+
};
|
|
1183
|
+
const mapped = networkMap[rawChainId.toLowerCase()];
|
|
1184
|
+
if (!mapped) {
|
|
1185
|
+
throw new OmaTrustError(
|
|
1186
|
+
"INVALID_DID",
|
|
1187
|
+
`Unknown did:ethr network "${rawChainId}"`,
|
|
1188
|
+
{ did, network: rawChainId }
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
chainId = mapped;
|
|
1192
|
+
}
|
|
1193
|
+
} else {
|
|
1194
|
+
throw new OmaTrustError("INVALID_DID", "Invalid did:ethr format", { did });
|
|
1195
|
+
}
|
|
1196
|
+
if (!ethers.isAddress(address)) {
|
|
1197
|
+
throw new OmaTrustError("INVALID_DID", "Invalid Ethereum address in did:ethr DID", {
|
|
1198
|
+
did,
|
|
1199
|
+
address
|
|
1200
|
+
});
|
|
1201
|
+
}
|
|
1202
|
+
const checksummed = ethers.getAddress(address);
|
|
1203
|
+
return `did:pkh:eip155:${chainId}:${checksummed.toLowerCase()}`;
|
|
1204
|
+
}
|
|
1205
|
+
var MULTICODEC_KEY_TYPES = {
|
|
1206
|
+
// Ed25519 public key: 0xed (varint encoded as [0xed, 0x01])
|
|
1207
|
+
237: { kty: "OKP", crv: "Ed25519" },
|
|
1208
|
+
// X25519 public key: 0xec (varint encoded as [0xec, 0x01])
|
|
1209
|
+
236: { kty: "OKP", crv: "X25519" },
|
|
1210
|
+
// secp256k1 public key (compressed): 0xe7 (varint encoded as [0xe7, 0x01])
|
|
1211
|
+
231: { kty: "EC", crv: "secp256k1", coordSize: 33 },
|
|
1212
|
+
// P-256 public key (compressed): 0x80 0x24 (varint 0x1200)
|
|
1213
|
+
4608: { kty: "EC", crv: "P-256", coordSize: 33 },
|
|
1214
|
+
// P-384 public key (compressed): 0x81 0x24 (varint 0x1201)
|
|
1215
|
+
4609: { kty: "EC", crv: "P-384", coordSize: 49 }
|
|
1216
|
+
};
|
|
1217
|
+
function readVarint(bytes, offset) {
|
|
1218
|
+
let value = 0;
|
|
1219
|
+
let shift = 0;
|
|
1220
|
+
let bytesRead = 0;
|
|
1221
|
+
while (offset + bytesRead < bytes.length) {
|
|
1222
|
+
const byte = bytes[offset + bytesRead];
|
|
1223
|
+
value |= (byte & 127) << shift;
|
|
1224
|
+
bytesRead++;
|
|
1225
|
+
if ((byte & 128) === 0) {
|
|
1226
|
+
return { value, bytesRead };
|
|
1227
|
+
}
|
|
1228
|
+
shift += 7;
|
|
1229
|
+
if (shift > 28) {
|
|
1230
|
+
throw new OmaTrustError("INVALID_DID", "Varint too long in did:key multicodec prefix");
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
throw new OmaTrustError("INVALID_DID", "Truncated varint in did:key multicodec prefix");
|
|
1234
|
+
}
|
|
1235
|
+
function decompressEcKey(compressedKey, crv) {
|
|
1236
|
+
throw new OmaTrustError(
|
|
1237
|
+
"UNSUPPORTED_KEY_TYPE",
|
|
1238
|
+
`Cannot convert compressed EC key (${crv}) from did:key to did:jwk. Decompressing EC points requires elliptic curve arithmetic. For EVM keys, use didEthrToDidPkh() instead.`,
|
|
1239
|
+
{ crv, keyLength: compressedKey.length }
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
function didKeyToDidJwk(did) {
|
|
1243
|
+
if (typeof did !== "string" || !did.startsWith("did:key:")) {
|
|
1244
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:key DID", { did });
|
|
1245
|
+
}
|
|
1246
|
+
const identifier = did.slice("did:key:".length);
|
|
1247
|
+
if (!identifier || !identifier.startsWith("z")) {
|
|
1248
|
+
throw new OmaTrustError(
|
|
1249
|
+
"INVALID_DID",
|
|
1250
|
+
"did:key identifier must start with 'z' (base58btc multibase prefix)",
|
|
1251
|
+
{ did }
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
let decoded;
|
|
1255
|
+
try {
|
|
1256
|
+
decoded = base58.base58btc.decode(identifier);
|
|
1257
|
+
} catch (err) {
|
|
1258
|
+
throw new OmaTrustError(
|
|
1259
|
+
"INVALID_DID",
|
|
1260
|
+
"Failed to decode base58btc from did:key identifier",
|
|
1261
|
+
{ did, cause: err }
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
if (decoded.length < 3) {
|
|
1265
|
+
throw new OmaTrustError("INVALID_DID", "did:key decoded bytes too short", { did });
|
|
1266
|
+
}
|
|
1267
|
+
const { value: codecValue, bytesRead } = readVarint(decoded, 0);
|
|
1268
|
+
const keyType = MULTICODEC_KEY_TYPES[codecValue];
|
|
1269
|
+
if (!keyType) {
|
|
1270
|
+
throw new OmaTrustError(
|
|
1271
|
+
"UNSUPPORTED_KEY_TYPE",
|
|
1272
|
+
`Unsupported multicodec key type 0x${codecValue.toString(16)} in did:key`,
|
|
1273
|
+
{ did, codec: `0x${codecValue.toString(16)}` }
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
const keyBytes = decoded.slice(bytesRead);
|
|
1277
|
+
if (keyType.kty === "OKP") {
|
|
1278
|
+
if (keyBytes.length !== 32) {
|
|
1279
|
+
throw new OmaTrustError(
|
|
1280
|
+
"INVALID_DID",
|
|
1281
|
+
`Expected 32-byte ${keyType.crv} key, got ${keyBytes.length} bytes`,
|
|
1282
|
+
{ did, crv: keyType.crv }
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
const jwk = {
|
|
1286
|
+
kty: keyType.kty,
|
|
1287
|
+
crv: keyType.crv,
|
|
1288
|
+
x: jose.base64url.encode(keyBytes)
|
|
1289
|
+
};
|
|
1290
|
+
return jwkToDidJwk(jwk);
|
|
1291
|
+
}
|
|
1292
|
+
return decompressEcKey(keyBytes, keyType.crv).x.toString();
|
|
1293
|
+
}
|
|
824
1294
|
|
|
1295
|
+
exports.artifactDidFromBytes = artifactDidFromBytes;
|
|
1296
|
+
exports.artifactDidFromJson = artifactDidFromJson;
|
|
825
1297
|
exports.assertBareDid = assertBareDid;
|
|
1298
|
+
exports.assertJsonSafe = assertJsonSafe;
|
|
826
1299
|
exports.buildCaip10 = buildCaip10;
|
|
827
1300
|
exports.buildCaip2 = buildCaip2;
|
|
828
1301
|
exports.buildDidPkh = buildDidPkh;
|
|
829
1302
|
exports.buildDidPkhFromCaip10 = buildDidPkhFromCaip10;
|
|
830
1303
|
exports.buildDidWeb = buildDidWeb;
|
|
831
1304
|
exports.buildEvmDidPkh = buildEvmDidPkh;
|
|
1305
|
+
exports.canonicalizeAndKeccak256 = canonicalizeAndKeccak256;
|
|
832
1306
|
exports.canonicalizeForHash = canonicalizeForHash;
|
|
833
1307
|
exports.canonicalizeJson = canonicalizeJson;
|
|
834
1308
|
exports.computeDidAddress = computeDidAddress;
|
|
835
1309
|
exports.computeDidHash = computeDidHash;
|
|
836
1310
|
exports.computeJwkThumbprint = computeJwkThumbprint;
|
|
1311
|
+
exports.didEthrToDidPkh = didEthrToDidPkh;
|
|
837
1312
|
exports.didJwkToJwk = didJwkToJwk;
|
|
1313
|
+
exports.didKeyToDidJwk = didKeyToDidJwk;
|
|
838
1314
|
exports.didToAddress = didToAddress;
|
|
839
1315
|
exports.extractAddressFromDid = extractAddressFromDid;
|
|
840
1316
|
exports.extractAuthorizationMetadata = extractAuthorizationMetadata;
|
|
@@ -861,14 +1337,17 @@ exports.normalizeDidKey = normalizeDidKey;
|
|
|
861
1337
|
exports.normalizeDidPkh = normalizeDidPkh;
|
|
862
1338
|
exports.normalizeDidWeb = normalizeDidWeb;
|
|
863
1339
|
exports.normalizeDomain = normalizeDomain;
|
|
1340
|
+
exports.parseArtifactDid = parseArtifactDid;
|
|
864
1341
|
exports.parseCaip10 = parseCaip10;
|
|
865
1342
|
exports.parseCaip2 = parseCaip2;
|
|
866
1343
|
exports.parseDidUrl = parseDidUrl;
|
|
1344
|
+
exports.parseJsonStrict = parseJsonStrict;
|
|
867
1345
|
exports.publicJwkEquals = publicJwkEquals;
|
|
868
1346
|
exports.resolveDidUrlToControllerDid = resolveDidUrlToControllerDid;
|
|
869
1347
|
exports.resolveDidUrlToPublicKey = resolveDidUrlToPublicKey;
|
|
870
1348
|
exports.validateDidAddress = validateDidAddress;
|
|
871
1349
|
exports.validatePrivateKeyDid = validatePrivateKeyDid;
|
|
872
1350
|
exports.validatePublicJwk = validatePublicJwk;
|
|
1351
|
+
exports.verifyDidArtifact = verifyDidArtifact;
|
|
873
1352
|
//# sourceMappingURL=index.cjs.map
|
|
874
1353
|
//# sourceMappingURL=index.cjs.map
|