@oma3/omatrust 0.1.0-alpha.11 → 0.1.0-alpha.13
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-Bu-xxcv9.d.ts +407 -0
- package/dist/index-C7odEbp6.d.cts +407 -0
- package/dist/index-CnWY9arI.d.cts +612 -0
- package/dist/index-DREQRFIE.d.ts +612 -0
- package/dist/index.cjs +1316 -202
- 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 +1297 -202
- 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 +884 -163
- 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 +860 -164
- 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-C2w5EvFH.d.ts +0 -329
- package/dist/index-QueRiudB.d.cts +0 -329
- package/dist/index-R78TpAhN.d.ts +0 -235
package/dist/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { keccak256, toUtf8Bytes, isAddress, getAddress, sha256, ZeroAddress, Signature, formatUnits, verifyTypedData, Interface, Contract, hexlify, randomBytes, id } from 'ethers';
|
|
2
2
|
import { base64url, calculateJwkThumbprint, decodeProtectedHeader, importJWK, compactVerify } from 'jose';
|
|
3
3
|
import canonicalize from 'canonicalize';
|
|
4
|
+
import { CID } from 'multiformats/cid';
|
|
5
|
+
import { sha256 as sha256$1 } from 'multiformats/hashes/sha2';
|
|
6
|
+
import * as raw from 'multiformats/codecs/raw';
|
|
7
|
+
import { base32 } from 'multiformats/bases/base32';
|
|
8
|
+
import { base58btc } from 'multiformats/bases/base58';
|
|
4
9
|
import { SchemaEncoder, EAS } from '@ethereum-attestation-service/eas-sdk';
|
|
5
10
|
import { resolveTxt } from 'dns/promises';
|
|
6
11
|
|
|
@@ -14,31 +19,31 @@ var __export = (target, all) => {
|
|
|
14
19
|
var OmaTrustError = class extends Error {
|
|
15
20
|
code;
|
|
16
21
|
details;
|
|
17
|
-
constructor(
|
|
22
|
+
constructor(code2, message, details) {
|
|
18
23
|
super(message);
|
|
19
24
|
this.name = "OmaTrustError";
|
|
20
|
-
this.code =
|
|
25
|
+
this.code = code2;
|
|
21
26
|
this.details = details;
|
|
22
27
|
}
|
|
23
28
|
};
|
|
24
|
-
function toOmaTrustError(
|
|
25
|
-
return new OmaTrustError(
|
|
29
|
+
function toOmaTrustError(code2, message, details) {
|
|
30
|
+
return new OmaTrustError(code2, message, details);
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
// src/shared/assert.ts
|
|
29
|
-
function assertString(value, name,
|
|
34
|
+
function assertString(value, name, code2 = "INVALID_INPUT") {
|
|
30
35
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
31
|
-
throw new OmaTrustError(
|
|
36
|
+
throw new OmaTrustError(code2, `${name} must be a non-empty string`, { value });
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
|
-
function assertNumber(value, name,
|
|
39
|
+
function assertNumber(value, name, code2 = "INVALID_INPUT") {
|
|
35
40
|
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
36
|
-
throw new OmaTrustError(
|
|
41
|
+
throw new OmaTrustError(code2, `${name} must be a valid number`, { value });
|
|
37
42
|
}
|
|
38
43
|
}
|
|
39
|
-
function assertObject(value, name,
|
|
44
|
+
function assertObject(value, name, code2 = "INVALID_INPUT") {
|
|
40
45
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
41
|
-
throw new OmaTrustError(
|
|
46
|
+
throw new OmaTrustError(code2, `${name} must be an object`, { value });
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
49
|
function asError(err) {
|
|
@@ -51,19 +56,25 @@ function asError(err) {
|
|
|
51
56
|
// src/identity/index.ts
|
|
52
57
|
var identity_exports = {};
|
|
53
58
|
__export(identity_exports, {
|
|
59
|
+
artifactDidFromBytes: () => artifactDidFromBytes,
|
|
60
|
+
artifactDidFromJson: () => artifactDidFromJson,
|
|
54
61
|
assertBareDid: () => assertBareDid,
|
|
62
|
+
assertJsonSafe: () => assertJsonSafe,
|
|
55
63
|
buildCaip10: () => buildCaip10,
|
|
56
64
|
buildCaip2: () => buildCaip2,
|
|
57
65
|
buildDidPkh: () => buildDidPkh,
|
|
58
66
|
buildDidPkhFromCaip10: () => buildDidPkhFromCaip10,
|
|
59
67
|
buildDidWeb: () => buildDidWeb,
|
|
60
68
|
buildEvmDidPkh: () => buildEvmDidPkh,
|
|
69
|
+
canonicalizeAndKeccak256: () => canonicalizeAndKeccak256,
|
|
61
70
|
canonicalizeForHash: () => canonicalizeForHash,
|
|
62
71
|
canonicalizeJson: () => canonicalizeJson,
|
|
63
72
|
computeDidAddress: () => computeDidAddress,
|
|
64
73
|
computeDidHash: () => computeDidHash,
|
|
65
74
|
computeJwkThumbprint: () => computeJwkThumbprint,
|
|
75
|
+
didEthrToDidPkh: () => didEthrToDidPkh,
|
|
66
76
|
didJwkToJwk: () => didJwkToJwk,
|
|
77
|
+
didKeyToDidJwk: () => didKeyToDidJwk,
|
|
67
78
|
didToAddress: () => didToAddress,
|
|
68
79
|
extractAddressFromDid: () => extractAddressFromDid,
|
|
69
80
|
extractAuthorizationMetadata: () => extractAuthorizationMetadata,
|
|
@@ -90,15 +101,18 @@ __export(identity_exports, {
|
|
|
90
101
|
normalizeDidPkh: () => normalizeDidPkh,
|
|
91
102
|
normalizeDidWeb: () => normalizeDidWeb,
|
|
92
103
|
normalizeDomain: () => normalizeDomain,
|
|
104
|
+
parseArtifactDid: () => parseArtifactDid,
|
|
93
105
|
parseCaip10: () => parseCaip10,
|
|
94
106
|
parseCaip2: () => parseCaip2,
|
|
95
107
|
parseDidUrl: () => parseDidUrl,
|
|
108
|
+
parseJsonStrict: () => parseJsonStrict,
|
|
96
109
|
publicJwkEquals: () => publicJwkEquals,
|
|
97
110
|
resolveDidUrlToControllerDid: () => resolveDidUrlToControllerDid,
|
|
98
111
|
resolveDidUrlToPublicKey: () => resolveDidUrlToPublicKey,
|
|
99
112
|
validateDidAddress: () => validateDidAddress,
|
|
100
113
|
validatePrivateKeyDid: () => validatePrivateKeyDid,
|
|
101
|
-
validatePublicJwk: () => validatePublicJwk
|
|
114
|
+
validatePublicJwk: () => validatePublicJwk,
|
|
115
|
+
verifyDidArtifact: () => verifyDidArtifact
|
|
102
116
|
});
|
|
103
117
|
|
|
104
118
|
// src/identity/caip.ts
|
|
@@ -154,6 +168,158 @@ function parseCaip2(caip2) {
|
|
|
154
168
|
}
|
|
155
169
|
return { namespace, reference };
|
|
156
170
|
}
|
|
171
|
+
var VALID_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
|
|
172
|
+
var PRIVATE_KEY_FIELDS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
|
|
173
|
+
var REQUIRED_PUBLIC_FIELDS = {
|
|
174
|
+
EC: ["crv", "x", "y"],
|
|
175
|
+
OKP: ["crv", "x"],
|
|
176
|
+
RSA: ["n", "e"]
|
|
177
|
+
};
|
|
178
|
+
function validatePublicJwk(jwk) {
|
|
179
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
180
|
+
return { valid: false, error: "JWK must be a non-null object" };
|
|
181
|
+
}
|
|
182
|
+
const obj = jwk;
|
|
183
|
+
const kty = obj.kty;
|
|
184
|
+
if (typeof kty !== "string" || !VALID_KTY.has(kty)) {
|
|
185
|
+
return {
|
|
186
|
+
valid: false,
|
|
187
|
+
error: `Invalid or missing kty (must be one of: ${[...VALID_KTY].join(", ")})`
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
for (const field of PRIVATE_KEY_FIELDS) {
|
|
191
|
+
if (field in obj) {
|
|
192
|
+
return {
|
|
193
|
+
valid: false,
|
|
194
|
+
error: `JWK contains private key field "${field}" \u2014 only public keys are allowed`
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const required = REQUIRED_PUBLIC_FIELDS[kty];
|
|
199
|
+
if (required) {
|
|
200
|
+
for (const field of required) {
|
|
201
|
+
if (!(field in obj) || obj[field] === void 0 || obj[field] === null || obj[field] === "") {
|
|
202
|
+
return {
|
|
203
|
+
valid: false,
|
|
204
|
+
error: `Missing required public key field "${field}" for kty="${kty}"`
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { valid: true };
|
|
210
|
+
}
|
|
211
|
+
function canonicalizeJwkJson(jwk) {
|
|
212
|
+
const sorted = Object.keys(jwk).sort();
|
|
213
|
+
const obj = {};
|
|
214
|
+
for (const key of sorted) {
|
|
215
|
+
obj[key] = jwk[key];
|
|
216
|
+
}
|
|
217
|
+
return JSON.stringify(obj);
|
|
218
|
+
}
|
|
219
|
+
function jwkToDidJwk(jwk) {
|
|
220
|
+
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
221
|
+
const validation = validatePublicJwk(jwk);
|
|
222
|
+
if (!validation.valid) {
|
|
223
|
+
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
224
|
+
}
|
|
225
|
+
const canonical = canonicalizeJwkJson(jwk);
|
|
226
|
+
const encoded = base64url.encode(new TextEncoder().encode(canonical));
|
|
227
|
+
return `did:jwk:${encoded}`;
|
|
228
|
+
}
|
|
229
|
+
function didJwkToJwk(didJwk) {
|
|
230
|
+
if (typeof didJwk !== "string" || !didJwk.startsWith("did:jwk:")) {
|
|
231
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:jwk DID", { input: didJwk });
|
|
232
|
+
}
|
|
233
|
+
const parts = didJwk.split(":");
|
|
234
|
+
if (parts.length !== 3) {
|
|
235
|
+
throw new OmaTrustError("INVALID_DID", "did:jwk must have exactly 3 colon-separated parts", {
|
|
236
|
+
input: didJwk
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
const encoded = parts[2];
|
|
240
|
+
if (!encoded || encoded.length === 0) {
|
|
241
|
+
throw new OmaTrustError("INVALID_DID", "Missing base64url-encoded JWK identifier", {
|
|
242
|
+
input: didJwk
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
let decoded;
|
|
246
|
+
try {
|
|
247
|
+
const bytes = base64url.decode(encoded);
|
|
248
|
+
decoded = new TextDecoder().decode(bytes);
|
|
249
|
+
} catch {
|
|
250
|
+
throw new OmaTrustError("INVALID_DID", "Failed to base64url-decode did:jwk identifier", {
|
|
251
|
+
input: didJwk
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
let jwk;
|
|
255
|
+
try {
|
|
256
|
+
jwk = JSON.parse(decoded);
|
|
257
|
+
} catch {
|
|
258
|
+
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk identifier is not valid JSON", {
|
|
259
|
+
input: didJwk
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
263
|
+
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk must be a JSON object", {
|
|
264
|
+
input: didJwk
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
const validation = validatePublicJwk(jwk);
|
|
268
|
+
if (!validation.valid) {
|
|
269
|
+
throw new OmaTrustError("INVALID_DID", validation.error ?? "Invalid public JWK in did:jwk", {
|
|
270
|
+
input: didJwk
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
return jwk;
|
|
274
|
+
}
|
|
275
|
+
function extractPublicKeyFields(jwk) {
|
|
276
|
+
const result = {};
|
|
277
|
+
const metadataFields = /* @__PURE__ */ new Set(["kid", "use", "key_ops", "alg", "ext"]);
|
|
278
|
+
for (const [key, value] of Object.entries(jwk)) {
|
|
279
|
+
if (PRIVATE_KEY_FIELDS.has(key)) continue;
|
|
280
|
+
if (metadataFields.has(key)) continue;
|
|
281
|
+
result[key] = value;
|
|
282
|
+
}
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
function publicJwkEquals(a, b) {
|
|
286
|
+
assertObject(a, "a", "INVALID_JWK");
|
|
287
|
+
assertObject(b, "b", "INVALID_JWK");
|
|
288
|
+
const aObj = a;
|
|
289
|
+
const bObj = b;
|
|
290
|
+
for (const field of PRIVATE_KEY_FIELDS) {
|
|
291
|
+
if (field in aObj) {
|
|
292
|
+
throw new OmaTrustError(
|
|
293
|
+
"INVALID_JWK",
|
|
294
|
+
`First JWK contains private key field "${field}"`,
|
|
295
|
+
{ field }
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
if (field in bObj) {
|
|
299
|
+
throw new OmaTrustError(
|
|
300
|
+
"INVALID_JWK",
|
|
301
|
+
`Second JWK contains private key field "${field}"`,
|
|
302
|
+
{ field }
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const aPublic = extractPublicKeyFields(aObj);
|
|
307
|
+
const bPublic = extractPublicKeyFields(bObj);
|
|
308
|
+
return canonicalizeJwkJson(aPublic) === canonicalizeJwkJson(bPublic);
|
|
309
|
+
}
|
|
310
|
+
async function computeJwkThumbprint(jwk, digestAlgorithm = "sha256") {
|
|
311
|
+
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
312
|
+
const validation = validatePublicJwk(jwk);
|
|
313
|
+
if (!validation.valid) {
|
|
314
|
+
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
315
|
+
}
|
|
316
|
+
const alg = digestAlgorithm === "sha256" ? "sha256" : digestAlgorithm === "sha384" ? "sha384" : "sha512";
|
|
317
|
+
return calculateJwkThumbprint(jwk, alg);
|
|
318
|
+
}
|
|
319
|
+
async function formatJktValue(jwk) {
|
|
320
|
+
const thumbprint = await computeJwkThumbprint(jwk, "sha256");
|
|
321
|
+
return `jkt=S256:${thumbprint}`;
|
|
322
|
+
}
|
|
157
323
|
|
|
158
324
|
// src/identity/did.ts
|
|
159
325
|
var DID_REGEX = /^did:[a-z0-9]+:.+$/i;
|
|
@@ -229,7 +395,7 @@ function normalizeDidKey(input) {
|
|
|
229
395
|
}
|
|
230
396
|
function normalizeDid(input) {
|
|
231
397
|
assertString(input, "input", "INVALID_DID");
|
|
232
|
-
const trimmed = input.trim();
|
|
398
|
+
const trimmed = input.trim().split("#")[0];
|
|
233
399
|
if (!trimmed.startsWith("did:")) {
|
|
234
400
|
return normalizeDidWeb(trimmed);
|
|
235
401
|
}
|
|
@@ -418,6 +584,15 @@ function validateDidPkh(did) {
|
|
|
418
584
|
};
|
|
419
585
|
}
|
|
420
586
|
}
|
|
587
|
+
if (namespace === "solana") {
|
|
588
|
+
if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address)) {
|
|
589
|
+
return {
|
|
590
|
+
valid: false,
|
|
591
|
+
method: "pkh",
|
|
592
|
+
error: `Invalid Solana address "${address}" (must be 32-44 base58 characters)`
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
421
596
|
return { valid: true, method: "pkh" };
|
|
422
597
|
}
|
|
423
598
|
function validateDidJwk(did) {
|
|
@@ -471,6 +646,10 @@ function validateDidJwk(did) {
|
|
|
471
646
|
error: "DID must reference a public key \u2014 private key component (d) is not allowed"
|
|
472
647
|
};
|
|
473
648
|
}
|
|
649
|
+
const jwkValidation = validatePublicJwk(jwk);
|
|
650
|
+
if (!jwkValidation.valid) {
|
|
651
|
+
return { valid: false, method: "jwk", error: jwkValidation.error };
|
|
652
|
+
}
|
|
474
653
|
return { valid: true, method: "jwk" };
|
|
475
654
|
}
|
|
476
655
|
function normalizeDidJwk(input) {
|
|
@@ -537,158 +716,6 @@ function assertBareDid(input, paramName = "did") {
|
|
|
537
716
|
);
|
|
538
717
|
}
|
|
539
718
|
}
|
|
540
|
-
var VALID_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
|
|
541
|
-
var PRIVATE_KEY_FIELDS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
|
|
542
|
-
var REQUIRED_PUBLIC_FIELDS = {
|
|
543
|
-
EC: ["crv", "x", "y"],
|
|
544
|
-
OKP: ["crv", "x"],
|
|
545
|
-
RSA: ["n", "e"]
|
|
546
|
-
};
|
|
547
|
-
function validatePublicJwk(jwk) {
|
|
548
|
-
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
549
|
-
return { valid: false, error: "JWK must be a non-null object" };
|
|
550
|
-
}
|
|
551
|
-
const obj = jwk;
|
|
552
|
-
const kty = obj.kty;
|
|
553
|
-
if (typeof kty !== "string" || !VALID_KTY.has(kty)) {
|
|
554
|
-
return {
|
|
555
|
-
valid: false,
|
|
556
|
-
error: `Invalid or missing kty (must be one of: ${[...VALID_KTY].join(", ")})`
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
|
-
for (const field of PRIVATE_KEY_FIELDS) {
|
|
560
|
-
if (field in obj) {
|
|
561
|
-
return {
|
|
562
|
-
valid: false,
|
|
563
|
-
error: `JWK contains private key field "${field}" \u2014 only public keys are allowed`
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
const required = REQUIRED_PUBLIC_FIELDS[kty];
|
|
568
|
-
if (required) {
|
|
569
|
-
for (const field of required) {
|
|
570
|
-
if (!(field in obj) || obj[field] === void 0 || obj[field] === null || obj[field] === "") {
|
|
571
|
-
return {
|
|
572
|
-
valid: false,
|
|
573
|
-
error: `Missing required public key field "${field}" for kty="${kty}"`
|
|
574
|
-
};
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
return { valid: true };
|
|
579
|
-
}
|
|
580
|
-
function canonicalizeJwkJson(jwk) {
|
|
581
|
-
const sorted = Object.keys(jwk).sort();
|
|
582
|
-
const obj = {};
|
|
583
|
-
for (const key of sorted) {
|
|
584
|
-
obj[key] = jwk[key];
|
|
585
|
-
}
|
|
586
|
-
return JSON.stringify(obj);
|
|
587
|
-
}
|
|
588
|
-
function jwkToDidJwk(jwk) {
|
|
589
|
-
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
590
|
-
const validation = validatePublicJwk(jwk);
|
|
591
|
-
if (!validation.valid) {
|
|
592
|
-
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
593
|
-
}
|
|
594
|
-
const canonical = canonicalizeJwkJson(jwk);
|
|
595
|
-
const encoded = base64url.encode(new TextEncoder().encode(canonical));
|
|
596
|
-
return `did:jwk:${encoded}`;
|
|
597
|
-
}
|
|
598
|
-
function didJwkToJwk(didJwk) {
|
|
599
|
-
if (typeof didJwk !== "string" || !didJwk.startsWith("did:jwk:")) {
|
|
600
|
-
throw new OmaTrustError("INVALID_DID", "Expected a did:jwk DID", { input: didJwk });
|
|
601
|
-
}
|
|
602
|
-
const parts = didJwk.split(":");
|
|
603
|
-
if (parts.length !== 3) {
|
|
604
|
-
throw new OmaTrustError("INVALID_DID", "did:jwk must have exactly 3 colon-separated parts", {
|
|
605
|
-
input: didJwk
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
const encoded = parts[2];
|
|
609
|
-
if (!encoded || encoded.length === 0) {
|
|
610
|
-
throw new OmaTrustError("INVALID_DID", "Missing base64url-encoded JWK identifier", {
|
|
611
|
-
input: didJwk
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
let decoded;
|
|
615
|
-
try {
|
|
616
|
-
const bytes = base64url.decode(encoded);
|
|
617
|
-
decoded = new TextDecoder().decode(bytes);
|
|
618
|
-
} catch {
|
|
619
|
-
throw new OmaTrustError("INVALID_DID", "Failed to base64url-decode did:jwk identifier", {
|
|
620
|
-
input: didJwk
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
let jwk;
|
|
624
|
-
try {
|
|
625
|
-
jwk = JSON.parse(decoded);
|
|
626
|
-
} catch {
|
|
627
|
-
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk identifier is not valid JSON", {
|
|
628
|
-
input: didJwk
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
632
|
-
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk must be a JSON object", {
|
|
633
|
-
input: didJwk
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
const validation = validatePublicJwk(jwk);
|
|
637
|
-
if (!validation.valid) {
|
|
638
|
-
throw new OmaTrustError("INVALID_DID", validation.error ?? "Invalid public JWK in did:jwk", {
|
|
639
|
-
input: didJwk
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
return jwk;
|
|
643
|
-
}
|
|
644
|
-
function extractPublicKeyFields(jwk) {
|
|
645
|
-
const result = {};
|
|
646
|
-
const metadataFields = /* @__PURE__ */ new Set(["kid", "use", "key_ops", "alg", "ext"]);
|
|
647
|
-
for (const [key, value] of Object.entries(jwk)) {
|
|
648
|
-
if (PRIVATE_KEY_FIELDS.has(key)) continue;
|
|
649
|
-
if (metadataFields.has(key)) continue;
|
|
650
|
-
result[key] = value;
|
|
651
|
-
}
|
|
652
|
-
return result;
|
|
653
|
-
}
|
|
654
|
-
function publicJwkEquals(a, b) {
|
|
655
|
-
assertObject(a, "a", "INVALID_JWK");
|
|
656
|
-
assertObject(b, "b", "INVALID_JWK");
|
|
657
|
-
const aObj = a;
|
|
658
|
-
const bObj = b;
|
|
659
|
-
for (const field of PRIVATE_KEY_FIELDS) {
|
|
660
|
-
if (field in aObj) {
|
|
661
|
-
throw new OmaTrustError(
|
|
662
|
-
"INVALID_JWK",
|
|
663
|
-
`First JWK contains private key field "${field}"`,
|
|
664
|
-
{ field }
|
|
665
|
-
);
|
|
666
|
-
}
|
|
667
|
-
if (field in bObj) {
|
|
668
|
-
throw new OmaTrustError(
|
|
669
|
-
"INVALID_JWK",
|
|
670
|
-
`Second JWK contains private key field "${field}"`,
|
|
671
|
-
{ field }
|
|
672
|
-
);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
const aPublic = extractPublicKeyFields(aObj);
|
|
676
|
-
const bPublic = extractPublicKeyFields(bObj);
|
|
677
|
-
return canonicalizeJwkJson(aPublic) === canonicalizeJwkJson(bPublic);
|
|
678
|
-
}
|
|
679
|
-
async function computeJwkThumbprint(jwk, digestAlgorithm = "sha256") {
|
|
680
|
-
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
681
|
-
const validation = validatePublicJwk(jwk);
|
|
682
|
-
if (!validation.valid) {
|
|
683
|
-
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
684
|
-
}
|
|
685
|
-
const alg = digestAlgorithm === "sha256" ? "sha256" : digestAlgorithm === "sha384" ? "sha384" : "sha512";
|
|
686
|
-
return calculateJwkThumbprint(jwk, alg);
|
|
687
|
-
}
|
|
688
|
-
async function formatJktValue(jwk) {
|
|
689
|
-
const thumbprint = await computeJwkThumbprint(jwk, "sha256");
|
|
690
|
-
return `jkt=S256:${thumbprint}`;
|
|
691
|
-
}
|
|
692
719
|
|
|
693
720
|
// src/shared/did-document.ts
|
|
694
721
|
async function fetchDidDocument(domain) {
|
|
@@ -851,7 +878,7 @@ function extractControllerEvmAddress(controllerDid) {
|
|
|
851
878
|
function extractAuthorizationMetadata(result) {
|
|
852
879
|
const payload = result.payload;
|
|
853
880
|
const resourceUrl = typeof payload.resourceUrl === "string" ? payload.resourceUrl : null;
|
|
854
|
-
const issuedAt = typeof payload.issuedAt === "string" ? payload.issuedAt : null;
|
|
881
|
+
const issuedAt = typeof payload.issuedAt === "string" ? payload.issuedAt : typeof payload.issuedAt === "number" ? payload.issuedAt : null;
|
|
855
882
|
let subjectDid = null;
|
|
856
883
|
if (resourceUrl) {
|
|
857
884
|
try {
|
|
@@ -860,33 +887,466 @@ function extractAuthorizationMetadata(result) {
|
|
|
860
887
|
} catch {
|
|
861
888
|
}
|
|
862
889
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
890
|
+
if ("publicKeyDid" in result) {
|
|
891
|
+
const jwsResult = result;
|
|
892
|
+
return {
|
|
893
|
+
controllerDid: jwsResult.publicKeyDid,
|
|
894
|
+
subjectDid,
|
|
895
|
+
resourceUrl,
|
|
896
|
+
issuedAt,
|
|
897
|
+
kid: jwsResult.kid,
|
|
898
|
+
publicKeyJwk: jwsResult.publicKeyJwk,
|
|
899
|
+
signer: null
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
const eip712Result = result;
|
|
903
|
+
const signerAddress = eip712Result.signer.toLowerCase();
|
|
904
|
+
return {
|
|
905
|
+
controllerDid: `did:pkh:eip155:1:${signerAddress}`,
|
|
906
|
+
subjectDid,
|
|
907
|
+
resourceUrl,
|
|
908
|
+
issuedAt,
|
|
909
|
+
kid: null,
|
|
910
|
+
publicKeyJwk: null,
|
|
911
|
+
signer: eip712Result.signer
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
var VALID_ALGORITHMS = /* @__PURE__ */ new Set(["keccak256", "sha256"]);
|
|
915
|
+
var MAX_JSON_DEPTH = 32;
|
|
916
|
+
function assertDepthLimit(depth, context) {
|
|
917
|
+
if (depth > MAX_JSON_DEPTH) {
|
|
918
|
+
const msg = context ? `JSON nesting depth exceeds maximum of ${MAX_JSON_DEPTH} at ${context}` : `JSON nesting depth exceeds maximum of ${MAX_JSON_DEPTH}`;
|
|
919
|
+
throw new OmaTrustError("INVALID_INPUT", msg);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function parseJsonStrict(input) {
|
|
923
|
+
if (typeof input !== "string") {
|
|
924
|
+
throw new OmaTrustError("INVALID_INPUT", "Input must be a string");
|
|
925
|
+
}
|
|
926
|
+
const duplicateKeys = detectDuplicateKeys(input);
|
|
927
|
+
if (duplicateKeys.length > 0) {
|
|
928
|
+
throw new OmaTrustError(
|
|
929
|
+
"INVALID_INPUT",
|
|
930
|
+
`Duplicate JSON key${duplicateKeys.length > 1 ? "s" : ""} detected: ${duplicateKeys.map((k) => `"${k}"`).join(", ")}`,
|
|
931
|
+
{ duplicateKeys }
|
|
932
|
+
);
|
|
933
|
+
}
|
|
934
|
+
try {
|
|
935
|
+
return JSON.parse(input);
|
|
936
|
+
} catch {
|
|
937
|
+
throw new OmaTrustError("INVALID_INPUT", "Input is not valid JSON");
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
function detectDuplicateKeys(input) {
|
|
941
|
+
const duplicates = [];
|
|
942
|
+
const objectKeyStack = [];
|
|
943
|
+
let inString = false;
|
|
944
|
+
let escaped = false;
|
|
945
|
+
let currentKey = "";
|
|
946
|
+
let collectingKey = false;
|
|
947
|
+
let afterColon = false;
|
|
948
|
+
let i = 0;
|
|
949
|
+
while (i < input.length) {
|
|
950
|
+
const ch = input[i];
|
|
951
|
+
if (escaped) {
|
|
952
|
+
if (collectingKey) currentKey += ch;
|
|
953
|
+
escaped = false;
|
|
954
|
+
i++;
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
if (ch === "\\") {
|
|
958
|
+
escaped = true;
|
|
959
|
+
if (collectingKey) currentKey += ch;
|
|
960
|
+
i++;
|
|
961
|
+
continue;
|
|
962
|
+
}
|
|
963
|
+
if (ch === '"') {
|
|
964
|
+
if (!inString) {
|
|
965
|
+
inString = true;
|
|
966
|
+
if (objectKeyStack.length > 0 && !afterColon) {
|
|
967
|
+
collectingKey = true;
|
|
968
|
+
currentKey = "";
|
|
969
|
+
}
|
|
970
|
+
} else {
|
|
971
|
+
inString = false;
|
|
972
|
+
if (collectingKey) {
|
|
973
|
+
collectingKey = false;
|
|
974
|
+
const keySet = objectKeyStack[objectKeyStack.length - 1];
|
|
975
|
+
if (keySet.has(currentKey)) {
|
|
976
|
+
if (!duplicates.includes(currentKey)) {
|
|
977
|
+
duplicates.push(currentKey);
|
|
978
|
+
}
|
|
979
|
+
} else {
|
|
980
|
+
keySet.add(currentKey);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
i++;
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
if (inString) {
|
|
988
|
+
if (collectingKey) currentKey += ch;
|
|
989
|
+
i++;
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
if (ch === "{") {
|
|
993
|
+
objectKeyStack.push(/* @__PURE__ */ new Set());
|
|
994
|
+
assertDepthLimit(objectKeyStack.length);
|
|
995
|
+
afterColon = false;
|
|
996
|
+
} else if (ch === "}") {
|
|
997
|
+
objectKeyStack.pop();
|
|
998
|
+
afterColon = objectKeyStack.length > 0;
|
|
999
|
+
} else if (ch === "[") {
|
|
1000
|
+
objectKeyStack.push(/* @__PURE__ */ new Set(["__array__"]));
|
|
1001
|
+
assertDepthLimit(objectKeyStack.length);
|
|
1002
|
+
afterColon = false;
|
|
1003
|
+
} else if (ch === "]") {
|
|
1004
|
+
objectKeyStack.pop();
|
|
1005
|
+
afterColon = objectKeyStack.length > 0;
|
|
1006
|
+
} else if (ch === ":") {
|
|
1007
|
+
afterColon = true;
|
|
1008
|
+
} else if (ch === ",") {
|
|
1009
|
+
afterColon = false;
|
|
1010
|
+
}
|
|
1011
|
+
i++;
|
|
1012
|
+
}
|
|
1013
|
+
return duplicates;
|
|
1014
|
+
}
|
|
1015
|
+
function assertJsonSafe(value, path = "$", depth = 0) {
|
|
1016
|
+
assertDepthLimit(depth, path);
|
|
1017
|
+
if (value === void 0) {
|
|
1018
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: undefined`);
|
|
1019
|
+
}
|
|
1020
|
+
if (value === null) return;
|
|
1021
|
+
switch (typeof value) {
|
|
1022
|
+
case "string":
|
|
1023
|
+
case "boolean":
|
|
1024
|
+
return;
|
|
1025
|
+
case "number":
|
|
1026
|
+
if (!Number.isFinite(value)) {
|
|
1027
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: ${value} (must be finite number)`);
|
|
1028
|
+
}
|
|
1029
|
+
return;
|
|
1030
|
+
case "bigint":
|
|
1031
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: BigInt (use number or string)`);
|
|
1032
|
+
case "function":
|
|
1033
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: function`);
|
|
1034
|
+
case "symbol":
|
|
1035
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: Symbol`);
|
|
1036
|
+
case "object":
|
|
1037
|
+
if (value instanceof Date) {
|
|
1038
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: Date (use ISO string or timestamp)`);
|
|
1039
|
+
}
|
|
1040
|
+
if (value instanceof RegExp) {
|
|
1041
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: RegExp`);
|
|
1042
|
+
}
|
|
1043
|
+
if (Array.isArray(value)) {
|
|
1044
|
+
for (let i = 0; i < value.length; i++) {
|
|
1045
|
+
assertJsonSafe(value[i], `${path}[${i}]`, depth + 1);
|
|
1046
|
+
}
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
for (const [key, val] of Object.entries(value)) {
|
|
1050
|
+
assertJsonSafe(val, `${path}.${key}`, depth + 1);
|
|
1051
|
+
}
|
|
1052
|
+
return;
|
|
1053
|
+
default:
|
|
1054
|
+
throw new OmaTrustError("INVALID_INPUT", `Non-JSON-safe value at ${path}: unknown type "${typeof value}"`);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
function canonicalizeJson(obj) {
|
|
1058
|
+
assertJsonSafe(obj);
|
|
1059
|
+
const jcs = canonicalize(obj);
|
|
1060
|
+
if (!jcs) {
|
|
1061
|
+
throw new OmaTrustError("INVALID_INPUT", "Object cannot be canonicalized", { obj });
|
|
1062
|
+
}
|
|
1063
|
+
return jcs;
|
|
1064
|
+
}
|
|
1065
|
+
function canonicalizeAndKeccak256(obj) {
|
|
1066
|
+
const jcsJson = canonicalizeJson(obj);
|
|
1067
|
+
return {
|
|
1068
|
+
jcsJson,
|
|
1069
|
+
hash: keccak256(toUtf8Bytes(jcsJson))
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
function canonicalizeForHash(obj) {
|
|
1073
|
+
return canonicalizeAndKeccak256(obj);
|
|
1074
|
+
}
|
|
1075
|
+
function hashCanonicalizedJson(obj, algorithm) {
|
|
1076
|
+
if (!VALID_ALGORITHMS.has(algorithm)) {
|
|
1077
|
+
throw new OmaTrustError("INVALID_INPUT", `Unsupported hash algorithm: "${algorithm}". Must be "keccak256" or "sha256".`, { algorithm });
|
|
1078
|
+
}
|
|
1079
|
+
const jcs = canonicalizeJson(obj);
|
|
1080
|
+
const bytes = toUtf8Bytes(jcs);
|
|
1081
|
+
return algorithm === "keccak256" ? keccak256(bytes) : sha256(bytes);
|
|
1082
|
+
}
|
|
1083
|
+
var DID_ARTIFACT_PREFIX = "did:artifact:";
|
|
1084
|
+
var CID_VERSION = 1;
|
|
1085
|
+
var RAW_CODEC = raw.code;
|
|
1086
|
+
var SHA2_256_CODE = 18;
|
|
1087
|
+
var SHA2_256_DIGEST_LENGTH = 32;
|
|
1088
|
+
async function artifactDidFromBytes(bytes) {
|
|
1089
|
+
if (!(bytes instanceof Uint8Array) || bytes.length === 0) {
|
|
1090
|
+
throw new OmaTrustError(
|
|
1091
|
+
"INVALID_INPUT",
|
|
1092
|
+
"bytes must be a non-empty Uint8Array"
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
const digest = await sha256$1.digest(bytes);
|
|
1096
|
+
const cid = CID.createV1(RAW_CODEC, digest);
|
|
1097
|
+
return `${DID_ARTIFACT_PREFIX}${cid.toString(base32)}`;
|
|
1098
|
+
}
|
|
1099
|
+
async function artifactDidFromJson(input) {
|
|
1100
|
+
const value = typeof input === "string" ? parseJsonStrict(input) : input;
|
|
1101
|
+
const jcs = canonicalizeJson(value);
|
|
1102
|
+
const bytes = new TextEncoder().encode(jcs);
|
|
1103
|
+
const digest = await sha256$1.digest(bytes);
|
|
1104
|
+
const cid = CID.createV1(RAW_CODEC, digest);
|
|
1105
|
+
return `${DID_ARTIFACT_PREFIX}${cid.toString(base32)}`;
|
|
1106
|
+
}
|
|
1107
|
+
function parseArtifactDid(did) {
|
|
1108
|
+
if (typeof did !== "string" || !did.startsWith(DID_ARTIFACT_PREFIX)) {
|
|
1109
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:artifact DID", { did });
|
|
1110
|
+
}
|
|
1111
|
+
const identifier = did.slice(DID_ARTIFACT_PREFIX.length);
|
|
1112
|
+
if (!identifier || identifier.length === 0) {
|
|
1113
|
+
throw new OmaTrustError("INVALID_DID", "Missing method-specific identifier", { did });
|
|
1114
|
+
}
|
|
1115
|
+
if (identifier[0] !== "b") {
|
|
1116
|
+
throw new OmaTrustError(
|
|
1117
|
+
"INVALID_DID",
|
|
1118
|
+
`Invalid multibase prefix "${identifier[0]}", expected "b" (base32lower)`,
|
|
1119
|
+
{ did }
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
let cid;
|
|
1123
|
+
try {
|
|
1124
|
+
cid = CID.parse(identifier, base32);
|
|
1125
|
+
} catch (err) {
|
|
1126
|
+
throw new OmaTrustError(
|
|
1127
|
+
"INVALID_DID",
|
|
1128
|
+
"Failed to decode base32 CID from did:artifact identifier",
|
|
1129
|
+
{ did, cause: err }
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
if (cid.version !== CID_VERSION) {
|
|
1133
|
+
throw new OmaTrustError(
|
|
1134
|
+
"INVALID_DID",
|
|
1135
|
+
`CID version must be 1, got ${cid.version}`,
|
|
1136
|
+
{ did }
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1139
|
+
if (cid.code !== RAW_CODEC) {
|
|
1140
|
+
throw new OmaTrustError(
|
|
1141
|
+
"INVALID_DID",
|
|
1142
|
+
`Multicodec must be raw (0x55), got 0x${cid.code.toString(16)}`,
|
|
1143
|
+
{ did }
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
if (cid.multihash.code !== SHA2_256_CODE) {
|
|
1147
|
+
throw new OmaTrustError(
|
|
1148
|
+
"INVALID_DID",
|
|
1149
|
+
`Multihash function must be sha2-256 (0x12), got 0x${cid.multihash.code.toString(16)}`,
|
|
1150
|
+
{ did }
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
if (cid.multihash.digest.length !== SHA2_256_DIGEST_LENGTH) {
|
|
1154
|
+
throw new OmaTrustError(
|
|
1155
|
+
"INVALID_DID",
|
|
1156
|
+
`SHA-256 digest must be 32 bytes, got ${cid.multihash.digest.length}`,
|
|
1157
|
+
{ did }
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
const digest = cid.multihash.digest;
|
|
1161
|
+
const digestHex = Array.from(digest).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1162
|
+
return { did, identifier, digest, digestHex };
|
|
1163
|
+
}
|
|
1164
|
+
async function verifyDidArtifact(did, content) {
|
|
1165
|
+
let parsed;
|
|
1166
|
+
try {
|
|
1167
|
+
parsed = parseArtifactDid(did);
|
|
1168
|
+
} catch (err) {
|
|
1169
|
+
return {
|
|
1170
|
+
valid: false,
|
|
1171
|
+
reason: err instanceof OmaTrustError ? err.message : "Invalid did:artifact DID"
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
const expectedHex = parsed.digestHex;
|
|
1175
|
+
if (typeof content === "string" || typeof content === "object" && content !== null && !(content instanceof Uint8Array)) {
|
|
1176
|
+
try {
|
|
1177
|
+
const value = typeof content === "string" ? parseJsonStrict(content) : content;
|
|
1178
|
+
const jcs = canonicalizeJson(value);
|
|
1179
|
+
const jcsBytes = new TextEncoder().encode(jcs);
|
|
1180
|
+
const digest2 = await sha256$1.digest(jcsBytes);
|
|
1181
|
+
const digestHex2 = Array.from(digest2.digest).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1182
|
+
if (digestHex2 === expectedHex) {
|
|
1183
|
+
return { valid: true, matchedAs: "json" };
|
|
1184
|
+
}
|
|
1185
|
+
} catch {
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
let rawBytes;
|
|
1189
|
+
if (content instanceof Uint8Array) {
|
|
1190
|
+
rawBytes = content;
|
|
1191
|
+
} else if (typeof content === "string") {
|
|
1192
|
+
rawBytes = new TextEncoder().encode(content);
|
|
1193
|
+
} else {
|
|
1194
|
+
return {
|
|
1195
|
+
valid: false,
|
|
1196
|
+
reason: "Content did not match as canonical JSON and is not raw bytes"
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
const digest = await sha256$1.digest(rawBytes);
|
|
1200
|
+
const digestHex = Array.from(digest.digest).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1201
|
+
if (digestHex === expectedHex) {
|
|
1202
|
+
return { valid: true, matchedAs: "binary" };
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
valid: false,
|
|
1206
|
+
reason: "Content does not match the did:artifact identifier (neither as canonical JSON nor as raw bytes)"
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
function didEthrToDidPkh(did) {
|
|
1210
|
+
if (typeof did !== "string" || !did.startsWith("did:ethr:")) {
|
|
1211
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:ethr DID", { did });
|
|
1212
|
+
}
|
|
1213
|
+
const remainder = did.slice("did:ethr:".length);
|
|
1214
|
+
if (!remainder) {
|
|
1215
|
+
throw new OmaTrustError("INVALID_DID", "Missing identifier in did:ethr DID", { did });
|
|
1216
|
+
}
|
|
1217
|
+
let chainId;
|
|
1218
|
+
let address;
|
|
1219
|
+
const parts = remainder.split(":");
|
|
1220
|
+
if (parts.length === 1) {
|
|
1221
|
+
chainId = "1";
|
|
1222
|
+
address = parts[0];
|
|
1223
|
+
} else if (parts.length === 2) {
|
|
1224
|
+
const rawChainId = parts[0];
|
|
1225
|
+
address = parts[1];
|
|
1226
|
+
if (rawChainId.startsWith("0x")) {
|
|
1227
|
+
chainId = String(parseInt(rawChainId, 16));
|
|
1228
|
+
} else if (/^\d+$/.test(rawChainId)) {
|
|
1229
|
+
chainId = rawChainId;
|
|
1230
|
+
} else {
|
|
1231
|
+
const networkMap = {
|
|
1232
|
+
mainnet: "1",
|
|
1233
|
+
goerli: "5",
|
|
1234
|
+
sepolia: "11155111",
|
|
1235
|
+
polygon: "137",
|
|
1236
|
+
arbitrum: "42161",
|
|
1237
|
+
optimism: "10",
|
|
1238
|
+
base: "8453"
|
|
1239
|
+
};
|
|
1240
|
+
const mapped = networkMap[rawChainId.toLowerCase()];
|
|
1241
|
+
if (!mapped) {
|
|
1242
|
+
throw new OmaTrustError(
|
|
1243
|
+
"INVALID_DID",
|
|
1244
|
+
`Unknown did:ethr network "${rawChainId}"`,
|
|
1245
|
+
{ did, network: rawChainId }
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1248
|
+
chainId = mapped;
|
|
1249
|
+
}
|
|
1250
|
+
} else {
|
|
1251
|
+
throw new OmaTrustError("INVALID_DID", "Invalid did:ethr format", { did });
|
|
1252
|
+
}
|
|
1253
|
+
if (!isAddress(address)) {
|
|
1254
|
+
throw new OmaTrustError("INVALID_DID", "Invalid Ethereum address in did:ethr DID", {
|
|
1255
|
+
did,
|
|
1256
|
+
address
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
const checksummed = getAddress(address);
|
|
1260
|
+
return `did:pkh:eip155:${chainId}:${checksummed.toLowerCase()}`;
|
|
1261
|
+
}
|
|
1262
|
+
var MULTICODEC_KEY_TYPES = {
|
|
1263
|
+
// Ed25519 public key: 0xed (varint encoded as [0xed, 0x01])
|
|
1264
|
+
237: { kty: "OKP", crv: "Ed25519" },
|
|
1265
|
+
// X25519 public key: 0xec (varint encoded as [0xec, 0x01])
|
|
1266
|
+
236: { kty: "OKP", crv: "X25519" },
|
|
1267
|
+
// secp256k1 public key (compressed): 0xe7 (varint encoded as [0xe7, 0x01])
|
|
1268
|
+
231: { kty: "EC", crv: "secp256k1", coordSize: 33 },
|
|
1269
|
+
// P-256 public key (compressed): 0x80 0x24 (varint 0x1200)
|
|
1270
|
+
4608: { kty: "EC", crv: "P-256", coordSize: 33 },
|
|
1271
|
+
// P-384 public key (compressed): 0x81 0x24 (varint 0x1201)
|
|
1272
|
+
4609: { kty: "EC", crv: "P-384", coordSize: 49 }
|
|
1273
|
+
};
|
|
1274
|
+
function readVarint(bytes, offset) {
|
|
1275
|
+
let value = 0;
|
|
1276
|
+
let shift = 0;
|
|
1277
|
+
let bytesRead = 0;
|
|
1278
|
+
while (offset + bytesRead < bytes.length) {
|
|
1279
|
+
const byte = bytes[offset + bytesRead];
|
|
1280
|
+
value |= (byte & 127) << shift;
|
|
1281
|
+
bytesRead++;
|
|
1282
|
+
if ((byte & 128) === 0) {
|
|
1283
|
+
return { value, bytesRead };
|
|
1284
|
+
}
|
|
1285
|
+
shift += 7;
|
|
1286
|
+
if (shift > 28) {
|
|
1287
|
+
throw new OmaTrustError("INVALID_DID", "Varint too long in did:key multicodec prefix");
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
throw new OmaTrustError("INVALID_DID", "Truncated varint in did:key multicodec prefix");
|
|
1291
|
+
}
|
|
1292
|
+
function decompressEcKey(compressedKey, crv) {
|
|
1293
|
+
throw new OmaTrustError(
|
|
1294
|
+
"UNSUPPORTED_KEY_TYPE",
|
|
1295
|
+
`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.`,
|
|
1296
|
+
{ crv, keyLength: compressedKey.length }
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
function didKeyToDidJwk(did) {
|
|
1300
|
+
if (typeof did !== "string" || !did.startsWith("did:key:")) {
|
|
1301
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:key DID", { did });
|
|
1302
|
+
}
|
|
1303
|
+
const identifier = did.slice("did:key:".length);
|
|
1304
|
+
if (!identifier || !identifier.startsWith("z")) {
|
|
1305
|
+
throw new OmaTrustError(
|
|
1306
|
+
"INVALID_DID",
|
|
1307
|
+
"did:key identifier must start with 'z' (base58btc multibase prefix)",
|
|
1308
|
+
{ did }
|
|
1309
|
+
);
|
|
1310
|
+
}
|
|
1311
|
+
let decoded;
|
|
1312
|
+
try {
|
|
1313
|
+
decoded = base58btc.decode(identifier);
|
|
1314
|
+
} catch (err) {
|
|
1315
|
+
throw new OmaTrustError(
|
|
1316
|
+
"INVALID_DID",
|
|
1317
|
+
"Failed to decode base58btc from did:key identifier",
|
|
1318
|
+
{ did, cause: err }
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
if (decoded.length < 3) {
|
|
1322
|
+
throw new OmaTrustError("INVALID_DID", "did:key decoded bytes too short", { did });
|
|
1323
|
+
}
|
|
1324
|
+
const { value: codecValue, bytesRead } = readVarint(decoded, 0);
|
|
1325
|
+
const keyType = MULTICODEC_KEY_TYPES[codecValue];
|
|
1326
|
+
if (!keyType) {
|
|
1327
|
+
throw new OmaTrustError(
|
|
1328
|
+
"UNSUPPORTED_KEY_TYPE",
|
|
1329
|
+
`Unsupported multicodec key type 0x${codecValue.toString(16)} in did:key`,
|
|
1330
|
+
{ did, codec: `0x${codecValue.toString(16)}` }
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
const keyBytes = decoded.slice(bytesRead);
|
|
1334
|
+
if (keyType.kty === "OKP") {
|
|
1335
|
+
if (keyBytes.length !== 32) {
|
|
1336
|
+
throw new OmaTrustError(
|
|
1337
|
+
"INVALID_DID",
|
|
1338
|
+
`Expected 32-byte ${keyType.crv} key, got ${keyBytes.length} bytes`,
|
|
1339
|
+
{ did, crv: keyType.crv }
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
const jwk = {
|
|
1343
|
+
kty: keyType.kty,
|
|
1344
|
+
crv: keyType.crv,
|
|
1345
|
+
x: base64url.encode(keyBytes)
|
|
1346
|
+
};
|
|
1347
|
+
return jwkToDidJwk(jwk);
|
|
876
1348
|
}
|
|
877
|
-
return
|
|
878
|
-
}
|
|
879
|
-
function canonicalizeForHash(obj) {
|
|
880
|
-
const jcsJson = canonicalizeJson(obj);
|
|
881
|
-
return {
|
|
882
|
-
jcsJson,
|
|
883
|
-
hash: keccak256(toUtf8Bytes(jcsJson))
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
function hashCanonicalizedJson(obj, algorithm) {
|
|
887
|
-
const jcs = canonicalizeJson(obj);
|
|
888
|
-
const bytes = toUtf8Bytes(jcs);
|
|
889
|
-
return algorithm === "keccak256" ? keccak256(bytes) : sha256(bytes);
|
|
1349
|
+
return decompressEcKey(keyBytes, keyType.crv).x.toString();
|
|
890
1350
|
}
|
|
891
1351
|
|
|
892
1352
|
// src/reputation/index.ts
|
|
@@ -933,7 +1393,9 @@ __export(reputation_exports, {
|
|
|
933
1393
|
getOmaTrustProofEip712Types: () => getOmaTrustProofEip712Types,
|
|
934
1394
|
getSchemaDetails: () => getSchemaDetails,
|
|
935
1395
|
getSupportedChainIds: () => getSupportedChainIds,
|
|
1396
|
+
getVerifiedArtifactAttestations: () => getVerifiedArtifactAttestations,
|
|
936
1397
|
hashSeed: () => hashSeed,
|
|
1398
|
+
isArtifactClaimedBy: () => isArtifactClaimedBy,
|
|
937
1399
|
isChainSupported: () => isChainSupported,
|
|
938
1400
|
listAttestations: () => listAttestations,
|
|
939
1401
|
normalizeSchema: () => normalizeSchema,
|
|
@@ -954,10 +1416,14 @@ __export(reputation_exports, {
|
|
|
954
1416
|
verifyDidWebOwnership: () => verifyDidWebOwnership,
|
|
955
1417
|
verifyDnsTxtControllerDid: () => verifyDnsTxtControllerDid2,
|
|
956
1418
|
verifyEip712Signature: () => verifyEip712Signature,
|
|
1419
|
+
verifyKeyBindingProofs: () => verifyKeyBindingProofs,
|
|
1420
|
+
verifyLinkedIdentifierProofs: () => verifyLinkedIdentifierProofs,
|
|
957
1421
|
verifyProof: () => verifyProof,
|
|
1422
|
+
verifyResponsibilityClaim: () => verifyResponsibilityClaim,
|
|
958
1423
|
verifySchemaExists: () => verifySchemaExists,
|
|
959
1424
|
verifySubjectOwnership: () => verifySubjectOwnership,
|
|
960
1425
|
verifyTransferProof: () => verifyTransferProof,
|
|
1426
|
+
verifyX402Artifact: () => verifyX402Artifact,
|
|
961
1427
|
verifyX402Eip712Artifact: () => verifyX402Eip712Artifact,
|
|
962
1428
|
verifyX402Eip712Offer: () => verifyX402Eip712Offer,
|
|
963
1429
|
verifyX402Eip712Receipt: () => verifyX402Eip712Receipt,
|
|
@@ -1970,10 +2436,10 @@ function validateReceiptPayload(payload) {
|
|
|
1970
2436
|
}
|
|
1971
2437
|
return { valid: true };
|
|
1972
2438
|
}
|
|
1973
|
-
function failure(
|
|
2439
|
+
function failure(code2, message, partial) {
|
|
1974
2440
|
return {
|
|
1975
2441
|
valid: false,
|
|
1976
|
-
error: { code, message },
|
|
2442
|
+
error: { code: code2, message },
|
|
1977
2443
|
...partial
|
|
1978
2444
|
};
|
|
1979
2445
|
}
|
|
@@ -2171,10 +2637,10 @@ function validateReceiptPayload2(payload) {
|
|
|
2171
2637
|
}
|
|
2172
2638
|
return { valid: true };
|
|
2173
2639
|
}
|
|
2174
|
-
function failure2(
|
|
2640
|
+
function failure2(code2, message, partial) {
|
|
2175
2641
|
return {
|
|
2176
2642
|
valid: false,
|
|
2177
|
-
error: { code, message },
|
|
2643
|
+
error: { code: code2, message },
|
|
2178
2644
|
...partial
|
|
2179
2645
|
};
|
|
2180
2646
|
}
|
|
@@ -2692,8 +3158,8 @@ async function readOwnerFromContract(provider, contractAddress, signature, metho
|
|
|
2692
3158
|
}
|
|
2693
3159
|
async function discoverContractOwner(provider, contractAddress) {
|
|
2694
3160
|
try {
|
|
2695
|
-
const
|
|
2696
|
-
if (
|
|
3161
|
+
const code2 = await provider.getCode(contractAddress);
|
|
3162
|
+
if (code2 === "0x" || code2 === "0x0") {
|
|
2697
3163
|
return null;
|
|
2698
3164
|
}
|
|
2699
3165
|
} catch {
|
|
@@ -3201,6 +3667,42 @@ function createX402OfferProof(offer) {
|
|
|
3201
3667
|
};
|
|
3202
3668
|
}
|
|
3203
3669
|
|
|
3670
|
+
// src/reputation/proof/x402-verify.ts
|
|
3671
|
+
async function verifyX402Artifact(artifact, options) {
|
|
3672
|
+
if (!artifact || typeof artifact !== "object") {
|
|
3673
|
+
return {
|
|
3674
|
+
valid: false,
|
|
3675
|
+
error: { code: "INVALID_ARTIFACT", message: "Artifact must be a non-null object" }
|
|
3676
|
+
};
|
|
3677
|
+
}
|
|
3678
|
+
const format = artifact.format;
|
|
3679
|
+
switch (format) {
|
|
3680
|
+
case "jws": {
|
|
3681
|
+
const jwsArtifact = artifact;
|
|
3682
|
+
const jwsOptions = options.resolveOptions ? { resolveOptions: options.resolveOptions } : void 0;
|
|
3683
|
+
if (options.artifactType === "offer") {
|
|
3684
|
+
return verifyX402JwsOffer(jwsArtifact, jwsOptions);
|
|
3685
|
+
}
|
|
3686
|
+
return verifyX402JwsReceipt(jwsArtifact, jwsOptions);
|
|
3687
|
+
}
|
|
3688
|
+
case "eip712": {
|
|
3689
|
+
const eip712Artifact = artifact;
|
|
3690
|
+
if (options.artifactType === "offer") {
|
|
3691
|
+
return verifyX402Eip712Offer(eip712Artifact);
|
|
3692
|
+
}
|
|
3693
|
+
return verifyX402Eip712Receipt(eip712Artifact);
|
|
3694
|
+
}
|
|
3695
|
+
default:
|
|
3696
|
+
return {
|
|
3697
|
+
valid: false,
|
|
3698
|
+
error: {
|
|
3699
|
+
code: "UNSUPPORTED_FORMAT",
|
|
3700
|
+
message: `Unsupported x402 artifact format: "${format}"`
|
|
3701
|
+
}
|
|
3702
|
+
};
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
|
|
3204
3706
|
// src/reputation/proof/evidence-pointer.ts
|
|
3205
3707
|
function createEvidencePointerProof(url) {
|
|
3206
3708
|
if (!url || typeof url !== "string") {
|
|
@@ -3309,8 +3811,8 @@ async function verifyDidPkhOwnership(params) {
|
|
|
3309
3811
|
subjectDid: params.subjectDid
|
|
3310
3812
|
});
|
|
3311
3813
|
}
|
|
3312
|
-
const
|
|
3313
|
-
const isContract =
|
|
3814
|
+
const code2 = await params.provider.getCode(subjectAddress);
|
|
3815
|
+
const isContract = code2 !== "0x" && code2 !== "0x0";
|
|
3314
3816
|
if (!isContract) {
|
|
3315
3817
|
if (getAddress(subjectAddress) === getAddress(connectedWalletAddress)) {
|
|
3316
3818
|
return {
|
|
@@ -3486,6 +3988,596 @@ async function verifySubjectOwnership(params) {
|
|
|
3486
3988
|
subjectDid
|
|
3487
3989
|
});
|
|
3488
3990
|
}
|
|
3991
|
+
function extractEip712Signer(proof) {
|
|
3992
|
+
const { domain, message, signature } = proof.proofObject;
|
|
3993
|
+
const typedData = {
|
|
3994
|
+
domain,
|
|
3995
|
+
types: {
|
|
3996
|
+
OmaTrustProof: [
|
|
3997
|
+
{ name: "signer", type: "address" },
|
|
3998
|
+
{ name: "authorizedEntity", type: "string" },
|
|
3999
|
+
{ name: "signingPurpose", type: "string" },
|
|
4000
|
+
{ name: "creationTimestamp", type: "uint256" },
|
|
4001
|
+
{ name: "expirationTimestamp", type: "uint256" },
|
|
4002
|
+
{ name: "randomValue", type: "bytes32" },
|
|
4003
|
+
{ name: "statement", type: "string" }
|
|
4004
|
+
]
|
|
4005
|
+
},
|
|
4006
|
+
message
|
|
4007
|
+
};
|
|
4008
|
+
try {
|
|
4009
|
+
const result = verifyEip712Signature(typedData, signature);
|
|
4010
|
+
return result.valid && result.signer ? result.signer : null;
|
|
4011
|
+
} catch (err) {
|
|
4012
|
+
console.warn("[omatrust] EIP-712 signer extraction failed:", err);
|
|
4013
|
+
return null;
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
function extractJwsHeaderJwk(proof) {
|
|
4017
|
+
const jws = proof.proofObject;
|
|
4018
|
+
if (typeof jws !== "string") return null;
|
|
4019
|
+
const parts = jws.split(".");
|
|
4020
|
+
if (parts.length !== 3) return null;
|
|
4021
|
+
try {
|
|
4022
|
+
const headerB64 = parts[0].replace(/-/g, "+").replace(/_/g, "/");
|
|
4023
|
+
const padded = headerB64.padEnd(
|
|
4024
|
+
headerB64.length + (4 - headerB64.length % 4) % 4,
|
|
4025
|
+
"="
|
|
4026
|
+
);
|
|
4027
|
+
let headerJson;
|
|
4028
|
+
if (typeof atob === "function") {
|
|
4029
|
+
headerJson = decodeURIComponent(
|
|
4030
|
+
Array.from(atob(padded)).map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
|
|
4031
|
+
);
|
|
4032
|
+
} else {
|
|
4033
|
+
headerJson = Buffer.from(padded, "base64").toString("utf8");
|
|
4034
|
+
}
|
|
4035
|
+
const header = JSON.parse(headerJson);
|
|
4036
|
+
return header.jwk ?? null;
|
|
4037
|
+
} catch {
|
|
4038
|
+
return null;
|
|
4039
|
+
}
|
|
4040
|
+
}
|
|
4041
|
+
function extractJwsPayload(proof) {
|
|
4042
|
+
const jws = proof.proofObject;
|
|
4043
|
+
if (typeof jws !== "string") return null;
|
|
4044
|
+
const parts = jws.split(".");
|
|
4045
|
+
if (parts.length !== 3) return null;
|
|
4046
|
+
try {
|
|
4047
|
+
const payloadB64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
4048
|
+
const padded = payloadB64.padEnd(
|
|
4049
|
+
payloadB64.length + (4 - payloadB64.length % 4) % 4,
|
|
4050
|
+
"="
|
|
4051
|
+
);
|
|
4052
|
+
let payloadJson;
|
|
4053
|
+
if (typeof atob === "function") {
|
|
4054
|
+
payloadJson = decodeURIComponent(
|
|
4055
|
+
Array.from(atob(padded)).map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
|
|
4056
|
+
);
|
|
4057
|
+
} else {
|
|
4058
|
+
payloadJson = Buffer.from(padded, "base64").toString("utf8");
|
|
4059
|
+
}
|
|
4060
|
+
return JSON.parse(payloadJson);
|
|
4061
|
+
} catch {
|
|
4062
|
+
return null;
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
function signerMatchesDid(signerAddress, did) {
|
|
4066
|
+
try {
|
|
4067
|
+
const didAddress = extractAddressFromDid(did);
|
|
4068
|
+
return getAddress(signerAddress).toLowerCase() === getAddress(didAddress).toLowerCase();
|
|
4069
|
+
} catch {
|
|
4070
|
+
return false;
|
|
4071
|
+
}
|
|
4072
|
+
}
|
|
4073
|
+
function jwkMatchesDid(jwk, did) {
|
|
4074
|
+
const method = extractDidMethod(did);
|
|
4075
|
+
if (method === "jwk") {
|
|
4076
|
+
try {
|
|
4077
|
+
const didJwk = didJwkToJwk(did);
|
|
4078
|
+
return publicJwkEquals(jwk, didJwk);
|
|
4079
|
+
} catch {
|
|
4080
|
+
return false;
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
return false;
|
|
4084
|
+
}
|
|
4085
|
+
function proofSignerMatchesDid(proof, did) {
|
|
4086
|
+
switch (proof.proofType) {
|
|
4087
|
+
case "pop-eip712": {
|
|
4088
|
+
const signer = extractEip712Signer(proof);
|
|
4089
|
+
if (!signer) return false;
|
|
4090
|
+
return signerMatchesDid(signer, did);
|
|
4091
|
+
}
|
|
4092
|
+
case "pop-jws": {
|
|
4093
|
+
const jwsProof = proof;
|
|
4094
|
+
const jwk = extractJwsHeaderJwk(jwsProof);
|
|
4095
|
+
if (jwk && jwkMatchesDid(jwk, did)) return true;
|
|
4096
|
+
const payload = extractJwsPayload(jwsProof);
|
|
4097
|
+
if (payload && typeof payload.iss === "string") {
|
|
4098
|
+
if (payload.iss === did) return true;
|
|
4099
|
+
}
|
|
4100
|
+
return false;
|
|
4101
|
+
}
|
|
4102
|
+
case "tx-encoded-value":
|
|
4103
|
+
case "tx-interaction":
|
|
4104
|
+
return false;
|
|
4105
|
+
case "evidence-pointer":
|
|
4106
|
+
return false;
|
|
4107
|
+
default:
|
|
4108
|
+
return false;
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
4111
|
+
function proofAuthorizedEntityMatchesDid(proof, did) {
|
|
4112
|
+
switch (proof.proofType) {
|
|
4113
|
+
case "pop-eip712": {
|
|
4114
|
+
const eip712 = proof;
|
|
4115
|
+
const authorizedEntity = eip712.proofObject.message.authorizedEntity;
|
|
4116
|
+
return typeof authorizedEntity === "string" && authorizedEntity === did;
|
|
4117
|
+
}
|
|
4118
|
+
case "pop-jws": {
|
|
4119
|
+
const payload = extractJwsPayload(proof);
|
|
4120
|
+
if (!payload) return false;
|
|
4121
|
+
return typeof payload.aud === "string" && payload.aud === did;
|
|
4122
|
+
}
|
|
4123
|
+
default:
|
|
4124
|
+
return false;
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
function verifyLinkedIdentifierProofs(data) {
|
|
4128
|
+
if (!data.subject || !data.linkedId) {
|
|
4129
|
+
return {
|
|
4130
|
+
valid: false,
|
|
4131
|
+
checks: [],
|
|
4132
|
+
reasons: ["subject and linkedId are required"]
|
|
4133
|
+
};
|
|
4134
|
+
}
|
|
4135
|
+
if (!Array.isArray(data.proofs) || data.proofs.length === 0) {
|
|
4136
|
+
return {
|
|
4137
|
+
valid: false,
|
|
4138
|
+
checks: [],
|
|
4139
|
+
reasons: ["At least one proof is required"]
|
|
4140
|
+
};
|
|
4141
|
+
}
|
|
4142
|
+
const checks = [];
|
|
4143
|
+
let subjectProved = false;
|
|
4144
|
+
let linkedIdProved = false;
|
|
4145
|
+
for (let i = 0; i < data.proofs.length; i++) {
|
|
4146
|
+
const proof = data.proofs[i];
|
|
4147
|
+
if (proofSignerMatchesDid(proof, data.subject)) {
|
|
4148
|
+
checks.push({
|
|
4149
|
+
proofIndex: i,
|
|
4150
|
+
proofType: proof.proofType,
|
|
4151
|
+
checkType: "signer-is-subject",
|
|
4152
|
+
valid: true
|
|
4153
|
+
});
|
|
4154
|
+
subjectProved = true;
|
|
4155
|
+
if (!proofAuthorizedEntityMatchesDid(proof, data.linkedId)) {
|
|
4156
|
+
checks.push({
|
|
4157
|
+
proofIndex: i,
|
|
4158
|
+
proofType: proof.proofType,
|
|
4159
|
+
checkType: "signer-is-subject",
|
|
4160
|
+
valid: false,
|
|
4161
|
+
reason: "Proof from subject does not authorize linkedId (aud mismatch)"
|
|
4162
|
+
});
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
if (proofSignerMatchesDid(proof, data.linkedId)) {
|
|
4166
|
+
checks.push({
|
|
4167
|
+
proofIndex: i,
|
|
4168
|
+
proofType: proof.proofType,
|
|
4169
|
+
checkType: "signer-is-linkedId",
|
|
4170
|
+
valid: true
|
|
4171
|
+
});
|
|
4172
|
+
linkedIdProved = true;
|
|
4173
|
+
if (!proofAuthorizedEntityMatchesDid(proof, data.subject)) {
|
|
4174
|
+
checks.push({
|
|
4175
|
+
proofIndex: i,
|
|
4176
|
+
proofType: proof.proofType,
|
|
4177
|
+
checkType: "signer-is-linkedId",
|
|
4178
|
+
valid: false,
|
|
4179
|
+
reason: "Proof from linkedId does not authorize subject (aud mismatch)"
|
|
4180
|
+
});
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
if (proof.proofType === "evidence-pointer") {
|
|
4184
|
+
checks.push({
|
|
4185
|
+
proofIndex: i,
|
|
4186
|
+
proofType: proof.proofType,
|
|
4187
|
+
checkType: "signer-is-subject",
|
|
4188
|
+
valid: true,
|
|
4189
|
+
reason: "Evidence pointer accepted (requires URL fetch for full verification)"
|
|
4190
|
+
});
|
|
4191
|
+
subjectProved = true;
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
const reasons = [];
|
|
4195
|
+
if (!subjectProved) {
|
|
4196
|
+
reasons.push("No proof demonstrates control by subject");
|
|
4197
|
+
}
|
|
4198
|
+
if (!linkedIdProved) {
|
|
4199
|
+
reasons.push("No proof demonstrates control by linkedId");
|
|
4200
|
+
}
|
|
4201
|
+
return {
|
|
4202
|
+
valid: reasons.length === 0,
|
|
4203
|
+
checks,
|
|
4204
|
+
reasons
|
|
4205
|
+
};
|
|
4206
|
+
}
|
|
4207
|
+
function verifyKeyBindingProofs(data) {
|
|
4208
|
+
if (!data.subject || !data.keyId) {
|
|
4209
|
+
return {
|
|
4210
|
+
valid: false,
|
|
4211
|
+
checks: [],
|
|
4212
|
+
reasons: ["subject and keyId are required"]
|
|
4213
|
+
};
|
|
4214
|
+
}
|
|
4215
|
+
if (!Array.isArray(data.proofs) || data.proofs.length === 0) {
|
|
4216
|
+
return {
|
|
4217
|
+
valid: false,
|
|
4218
|
+
checks: [],
|
|
4219
|
+
reasons: ["At least one proof is required"]
|
|
4220
|
+
};
|
|
4221
|
+
}
|
|
4222
|
+
const checks = [];
|
|
4223
|
+
let subjectAuthorizedKey = false;
|
|
4224
|
+
for (let i = 0; i < data.proofs.length; i++) {
|
|
4225
|
+
const proof = data.proofs[i];
|
|
4226
|
+
if (proofSignerMatchesDid(proof, data.subject)) {
|
|
4227
|
+
const authorizesKey = proofAuthorizedEntityMatchesDid(proof, data.keyId);
|
|
4228
|
+
checks.push({
|
|
4229
|
+
proofIndex: i,
|
|
4230
|
+
proofType: proof.proofType,
|
|
4231
|
+
checkType: "signer-is-subject-for-key",
|
|
4232
|
+
valid: authorizesKey,
|
|
4233
|
+
reason: authorizesKey ? void 0 : "Proof signed by subject but does not authorize the keyId"
|
|
4234
|
+
});
|
|
4235
|
+
if (authorizesKey) {
|
|
4236
|
+
subjectAuthorizedKey = true;
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
if (proofSignerMatchesDid(proof, data.keyId)) {
|
|
4240
|
+
checks.push({
|
|
4241
|
+
proofIndex: i,
|
|
4242
|
+
proofType: proof.proofType,
|
|
4243
|
+
checkType: "signer-is-keyId",
|
|
4244
|
+
valid: true,
|
|
4245
|
+
reason: "Key proved possession (supplementary, not sufficient alone)"
|
|
4246
|
+
});
|
|
4247
|
+
}
|
|
4248
|
+
if (proof.proofType === "evidence-pointer") {
|
|
4249
|
+
checks.push({
|
|
4250
|
+
proofIndex: i,
|
|
4251
|
+
proofType: proof.proofType,
|
|
4252
|
+
checkType: "signer-is-subject-for-key",
|
|
4253
|
+
valid: true,
|
|
4254
|
+
reason: "Evidence pointer accepted (requires URL fetch for full verification)"
|
|
4255
|
+
});
|
|
4256
|
+
subjectAuthorizedKey = true;
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
if (data.publicKeyJwk && extractDidMethod(data.keyId) === "jwk") {
|
|
4260
|
+
try {
|
|
4261
|
+
const keyIdJwk = didJwkToJwk(data.keyId);
|
|
4262
|
+
const jwkConsistent = publicJwkEquals(data.publicKeyJwk, keyIdJwk);
|
|
4263
|
+
if (!jwkConsistent) {
|
|
4264
|
+
return {
|
|
4265
|
+
valid: false,
|
|
4266
|
+
checks,
|
|
4267
|
+
reasons: ["publicKeyJwk does not match the key material in keyId (did:jwk)"]
|
|
4268
|
+
};
|
|
4269
|
+
}
|
|
4270
|
+
} catch {
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
const reasons = [];
|
|
4274
|
+
if (!subjectAuthorizedKey) {
|
|
4275
|
+
reasons.push(
|
|
4276
|
+
"No proof demonstrates that subject authorized the key binding"
|
|
4277
|
+
);
|
|
4278
|
+
}
|
|
4279
|
+
return {
|
|
4280
|
+
valid: reasons.length === 0,
|
|
4281
|
+
checks,
|
|
4282
|
+
reasons
|
|
4283
|
+
};
|
|
4284
|
+
}
|
|
4285
|
+
|
|
4286
|
+
// src/reputation/artifact-verification.ts
|
|
4287
|
+
async function verifyResponsibilityClaim(params) {
|
|
4288
|
+
const {
|
|
4289
|
+
attestation,
|
|
4290
|
+
artifactDid,
|
|
4291
|
+
provider,
|
|
4292
|
+
easContractAddress,
|
|
4293
|
+
chain,
|
|
4294
|
+
chainId,
|
|
4295
|
+
responsibilityClaimSchemaString
|
|
4296
|
+
} = params;
|
|
4297
|
+
const reasons = [];
|
|
4298
|
+
const checks = {
|
|
4299
|
+
schemaValid: false,
|
|
4300
|
+
subjectMatches: false,
|
|
4301
|
+
notRevoked: false,
|
|
4302
|
+
currentlyEffective: false,
|
|
4303
|
+
controllerAuthorized: false,
|
|
4304
|
+
issuedDuringAuthorizationWindow: false
|
|
4305
|
+
};
|
|
4306
|
+
let decoded;
|
|
4307
|
+
try {
|
|
4308
|
+
if (attestation.raw) {
|
|
4309
|
+
decoded = decodeAttestationData(responsibilityClaimSchemaString, attestation.raw);
|
|
4310
|
+
} else if (attestation.data && typeof attestation.data === "object") {
|
|
4311
|
+
decoded = attestation.data;
|
|
4312
|
+
} else {
|
|
4313
|
+
reasons.push("No attestation data available to decode");
|
|
4314
|
+
return buildFailedResult(checks, reasons);
|
|
4315
|
+
}
|
|
4316
|
+
} catch (err) {
|
|
4317
|
+
reasons.push(
|
|
4318
|
+
`Failed to decode attestation data: ${err instanceof Error ? err.message : "unknown error"}`
|
|
4319
|
+
);
|
|
4320
|
+
return buildFailedResult(checks, reasons);
|
|
4321
|
+
}
|
|
4322
|
+
const responsibleParty = decoded.responsibleParty;
|
|
4323
|
+
const subject = decoded.subject;
|
|
4324
|
+
const responsibilityType = decoded.responsibilityType;
|
|
4325
|
+
const issuedAt = decoded.issuedAt;
|
|
4326
|
+
const effectiveAt = decoded.effectiveAt;
|
|
4327
|
+
const expiresAt = decoded.expiresAt;
|
|
4328
|
+
const subjectLabel = decoded.subjectLabel;
|
|
4329
|
+
if (!responsibleParty || !subject || !responsibilityType || !issuedAt) {
|
|
4330
|
+
if (!responsibleParty) reasons.push("Missing required field: responsibleParty");
|
|
4331
|
+
if (!subject) reasons.push("Missing required field: subject");
|
|
4332
|
+
if (!responsibilityType) reasons.push("Missing required field: responsibilityType");
|
|
4333
|
+
if (!issuedAt) reasons.push("Missing required field: issuedAt");
|
|
4334
|
+
return buildFailedResult(checks, reasons, {
|
|
4335
|
+
responsibleParty,
|
|
4336
|
+
subjectLabel,
|
|
4337
|
+
responsibilityType
|
|
4338
|
+
});
|
|
4339
|
+
}
|
|
4340
|
+
if (!Array.isArray(responsibilityType) || responsibilityType.length === 0) {
|
|
4341
|
+
reasons.push("responsibilityType must be a non-empty array");
|
|
4342
|
+
return buildFailedResult(checks, reasons, {
|
|
4343
|
+
responsibleParty,
|
|
4344
|
+
subjectLabel,
|
|
4345
|
+
responsibilityType
|
|
4346
|
+
});
|
|
4347
|
+
}
|
|
4348
|
+
checks.schemaValid = true;
|
|
4349
|
+
if (artifactDid) {
|
|
4350
|
+
checks.subjectMatches = subject.toLowerCase() === artifactDid.toLowerCase();
|
|
4351
|
+
if (!checks.subjectMatches) {
|
|
4352
|
+
reasons.push(`Subject "${subject}" does not match expected artifact "${artifactDid}"`);
|
|
4353
|
+
}
|
|
4354
|
+
} else {
|
|
4355
|
+
checks.subjectMatches = true;
|
|
4356
|
+
}
|
|
4357
|
+
checks.notRevoked = attestation.revocationTime === BigInt(0);
|
|
4358
|
+
if (!checks.notRevoked) {
|
|
4359
|
+
reasons.push("Attestation has been revoked");
|
|
4360
|
+
}
|
|
4361
|
+
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
4362
|
+
const effectiveTime = toBigInt(effectiveAt);
|
|
4363
|
+
const expirationTime = toBigInt(expiresAt);
|
|
4364
|
+
const isEffective = effectiveTime === BigInt(0) || effectiveTime <= now;
|
|
4365
|
+
const isNotExpired = expirationTime === BigInt(0) || expirationTime > now;
|
|
4366
|
+
checks.currentlyEffective = isEffective && isNotExpired;
|
|
4367
|
+
if (!isEffective) {
|
|
4368
|
+
reasons.push("Attestation is not yet effective");
|
|
4369
|
+
}
|
|
4370
|
+
if (!isNotExpired) {
|
|
4371
|
+
reasons.push("Attestation has expired");
|
|
4372
|
+
}
|
|
4373
|
+
const controllerDid = `did:pkh:eip155:${chainId}:${attestation.attester.toLowerCase()}`;
|
|
4374
|
+
let authorization = null;
|
|
4375
|
+
try {
|
|
4376
|
+
const resolvedChain = chain ?? `eip155:${chainId}`;
|
|
4377
|
+
authorization = await getControllerAuthorization({
|
|
4378
|
+
subjectDid: responsibleParty,
|
|
4379
|
+
controllerDid,
|
|
4380
|
+
provider,
|
|
4381
|
+
chain: resolvedChain,
|
|
4382
|
+
easContractAddress
|
|
4383
|
+
});
|
|
4384
|
+
checks.controllerAuthorized = authorization.authorized;
|
|
4385
|
+
if (!checks.controllerAuthorized) {
|
|
4386
|
+
reasons.push(`Controller ${controllerDid} is not authorized for ${responsibleParty}`);
|
|
4387
|
+
}
|
|
4388
|
+
if (authorization.authorized && authorization.anchoredFrom !== null) {
|
|
4389
|
+
const issuedAtBigInt = toBigInt(issuedAt);
|
|
4390
|
+
const afterStart = issuedAtBigInt >= authorization.anchoredFrom;
|
|
4391
|
+
const beforeEnd = authorization.until === null || issuedAtBigInt <= authorization.until;
|
|
4392
|
+
checks.issuedDuringAuthorizationWindow = afterStart && beforeEnd;
|
|
4393
|
+
if (!afterStart) {
|
|
4394
|
+
reasons.push("Attestation was issued before the authorization window started");
|
|
4395
|
+
}
|
|
4396
|
+
if (!beforeEnd) {
|
|
4397
|
+
reasons.push("Attestation was issued after the authorization window ended");
|
|
4398
|
+
}
|
|
4399
|
+
} else if (authorization.authorized && authorization.anchoredFrom === null) {
|
|
4400
|
+
checks.issuedDuringAuthorizationWindow = true;
|
|
4401
|
+
} else {
|
|
4402
|
+
checks.issuedDuringAuthorizationWindow = false;
|
|
4403
|
+
}
|
|
4404
|
+
} catch (err) {
|
|
4405
|
+
reasons.push(
|
|
4406
|
+
`Controller authorization check failed: ${err instanceof Error ? err.message : "unknown error"}`
|
|
4407
|
+
);
|
|
4408
|
+
checks.controllerAuthorized = false;
|
|
4409
|
+
checks.issuedDuringAuthorizationWindow = false;
|
|
4410
|
+
}
|
|
4411
|
+
const valid = Object.values(checks).every(Boolean);
|
|
4412
|
+
return {
|
|
4413
|
+
valid,
|
|
4414
|
+
responsibleParty,
|
|
4415
|
+
controllerDid,
|
|
4416
|
+
responsibilityTypes: responsibilityType,
|
|
4417
|
+
subjectLabel: subjectLabel || void 0,
|
|
4418
|
+
authorization,
|
|
4419
|
+
checks,
|
|
4420
|
+
reasons
|
|
4421
|
+
};
|
|
4422
|
+
}
|
|
4423
|
+
async function getVerifiedArtifactAttestations(params) {
|
|
4424
|
+
const {
|
|
4425
|
+
artifactDid,
|
|
4426
|
+
provider,
|
|
4427
|
+
easContractAddress,
|
|
4428
|
+
chain,
|
|
4429
|
+
chainId,
|
|
4430
|
+
schemaUids,
|
|
4431
|
+
responsibilityClaimSchemaUid,
|
|
4432
|
+
responsibilityClaimSchemaString,
|
|
4433
|
+
securityAssessmentSchemaUid,
|
|
4434
|
+
certificationSchemaUid,
|
|
4435
|
+
fromBlock,
|
|
4436
|
+
limit
|
|
4437
|
+
} = params;
|
|
4438
|
+
parseArtifactDid(artifactDid);
|
|
4439
|
+
if (schemaUids.length === 0) {
|
|
4440
|
+
return {
|
|
4441
|
+
artifactDid,
|
|
4442
|
+
responsibilityClaims: [],
|
|
4443
|
+
securityAssessments: [],
|
|
4444
|
+
certifications: [],
|
|
4445
|
+
otherAttestations: []
|
|
4446
|
+
};
|
|
4447
|
+
}
|
|
4448
|
+
const results = await listAttestations({
|
|
4449
|
+
subjectDid: artifactDid,
|
|
4450
|
+
provider,
|
|
4451
|
+
easContractAddress,
|
|
4452
|
+
schemas: schemaUids,
|
|
4453
|
+
limit: limit ?? 100,
|
|
4454
|
+
fromBlock
|
|
4455
|
+
});
|
|
4456
|
+
const responsibilityClaims = [];
|
|
4457
|
+
const securityAssessments = [];
|
|
4458
|
+
const certifications = [];
|
|
4459
|
+
const otherAttestations = [];
|
|
4460
|
+
for (const att of results) {
|
|
4461
|
+
const schemaUidLower = att.schema.toLowerCase();
|
|
4462
|
+
if (schemaUidLower === responsibilityClaimSchemaUid.toLowerCase()) {
|
|
4463
|
+
const verification = await verifyResponsibilityClaim({
|
|
4464
|
+
attestation: att,
|
|
4465
|
+
artifactDid,
|
|
4466
|
+
provider,
|
|
4467
|
+
easContractAddress,
|
|
4468
|
+
chain,
|
|
4469
|
+
chainId,
|
|
4470
|
+
responsibilityClaimSchemaString
|
|
4471
|
+
});
|
|
4472
|
+
responsibilityClaims.push({ attestation: att, verification });
|
|
4473
|
+
} else if (securityAssessmentSchemaUid && schemaUidLower === securityAssessmentSchemaUid.toLowerCase()) {
|
|
4474
|
+
const verification = await runStandardVerification(att, provider);
|
|
4475
|
+
securityAssessments.push({ attestation: att, verification });
|
|
4476
|
+
} else if (certificationSchemaUid && schemaUidLower === certificationSchemaUid.toLowerCase()) {
|
|
4477
|
+
const verification = await runStandardVerification(att, provider);
|
|
4478
|
+
certifications.push({ attestation: att, verification });
|
|
4479
|
+
} else {
|
|
4480
|
+
const verification = await runStandardVerification(att, provider);
|
|
4481
|
+
otherAttestations.push({ attestation: att, verification });
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
return {
|
|
4485
|
+
artifactDid,
|
|
4486
|
+
responsibilityClaims,
|
|
4487
|
+
securityAssessments,
|
|
4488
|
+
certifications,
|
|
4489
|
+
otherAttestations
|
|
4490
|
+
};
|
|
4491
|
+
}
|
|
4492
|
+
async function isArtifactClaimedBy(params) {
|
|
4493
|
+
const { artifactDid, responsibleParty, responsibilityTypes } = params;
|
|
4494
|
+
const result = await getVerifiedArtifactAttestations({
|
|
4495
|
+
artifactDid,
|
|
4496
|
+
provider: params.provider,
|
|
4497
|
+
easContractAddress: params.easContractAddress,
|
|
4498
|
+
chain: params.chain,
|
|
4499
|
+
chainId: params.chainId,
|
|
4500
|
+
schemaUids: params.schemaUids,
|
|
4501
|
+
responsibilityClaimSchemaUid: params.responsibilityClaimSchemaUid,
|
|
4502
|
+
responsibilityClaimSchemaString: params.responsibilityClaimSchemaString,
|
|
4503
|
+
securityAssessmentSchemaUid: params.securityAssessmentSchemaUid,
|
|
4504
|
+
certificationSchemaUid: params.certificationSchemaUid
|
|
4505
|
+
});
|
|
4506
|
+
const matchingClaims = result.responsibilityClaims.filter(
|
|
4507
|
+
(claim) => claim.verification.responsibleParty.toLowerCase() === responsibleParty.toLowerCase()
|
|
4508
|
+
);
|
|
4509
|
+
const validClaims = matchingClaims.filter((claim) => claim.verification.valid);
|
|
4510
|
+
let finalClaims = validClaims;
|
|
4511
|
+
let matchedTypes = [];
|
|
4512
|
+
if (responsibilityTypes && responsibilityTypes.length > 0) {
|
|
4513
|
+
finalClaims = validClaims.filter(
|
|
4514
|
+
(claim) => claim.verification.responsibilityTypes.some(
|
|
4515
|
+
(t) => responsibilityTypes.includes(t)
|
|
4516
|
+
)
|
|
4517
|
+
);
|
|
4518
|
+
matchedTypes = [
|
|
4519
|
+
...new Set(
|
|
4520
|
+
finalClaims.flatMap(
|
|
4521
|
+
(claim) => claim.verification.responsibilityTypes.filter(
|
|
4522
|
+
(t) => responsibilityTypes.includes(t)
|
|
4523
|
+
)
|
|
4524
|
+
)
|
|
4525
|
+
)
|
|
4526
|
+
];
|
|
4527
|
+
} else {
|
|
4528
|
+
matchedTypes = [
|
|
4529
|
+
...new Set(
|
|
4530
|
+
validClaims.flatMap((claim) => claim.verification.responsibilityTypes)
|
|
4531
|
+
)
|
|
4532
|
+
];
|
|
4533
|
+
}
|
|
4534
|
+
const reasons = [];
|
|
4535
|
+
if (finalClaims.length === 0) {
|
|
4536
|
+
if (matchingClaims.length === 0) {
|
|
4537
|
+
reasons.push(
|
|
4538
|
+
`No responsibility claims found from ${responsibleParty} for this artifact`
|
|
4539
|
+
);
|
|
4540
|
+
} else if (validClaims.length === 0) {
|
|
4541
|
+
reasons.push(
|
|
4542
|
+
`Claims from ${responsibleParty} exist but none passed verification`
|
|
4543
|
+
);
|
|
4544
|
+
} else if (responsibilityTypes) {
|
|
4545
|
+
reasons.push(
|
|
4546
|
+
`No claims matched the requested responsibility types: ${responsibilityTypes.join(", ")}`
|
|
4547
|
+
);
|
|
4548
|
+
}
|
|
4549
|
+
}
|
|
4550
|
+
return {
|
|
4551
|
+
claimed: finalClaims.length > 0,
|
|
4552
|
+
claims: finalClaims,
|
|
4553
|
+
matchedResponsibilityTypes: matchedTypes,
|
|
4554
|
+
reasons
|
|
4555
|
+
};
|
|
4556
|
+
}
|
|
4557
|
+
function toBigInt(value) {
|
|
4558
|
+
if (value === void 0 || value === null) return BigInt(0);
|
|
4559
|
+
if (typeof value === "bigint") return value;
|
|
4560
|
+
return BigInt(value);
|
|
4561
|
+
}
|
|
4562
|
+
function buildFailedResult(checks, reasons, decoded) {
|
|
4563
|
+
return {
|
|
4564
|
+
valid: false,
|
|
4565
|
+
responsibleParty: decoded?.responsibleParty ?? "",
|
|
4566
|
+
controllerDid: "",
|
|
4567
|
+
responsibilityTypes: decoded?.responsibilityType ?? [],
|
|
4568
|
+
subjectLabel: decoded?.subjectLabel || void 0,
|
|
4569
|
+
authorization: null,
|
|
4570
|
+
checks,
|
|
4571
|
+
reasons
|
|
4572
|
+
};
|
|
4573
|
+
}
|
|
4574
|
+
async function runStandardVerification(attestation, provider) {
|
|
4575
|
+
try {
|
|
4576
|
+
return await verifyAttestation({ attestation, provider });
|
|
4577
|
+
} catch {
|
|
4578
|
+
return void 0;
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
3489
4581
|
|
|
3490
4582
|
// src/app-registry/index.ts
|
|
3491
4583
|
var app_registry_exports = {};
|
|
@@ -3573,8 +4665,8 @@ function getInterfaceTypes(bitmap) {
|
|
|
3573
4665
|
}
|
|
3574
4666
|
|
|
3575
4667
|
// src/app-registry/status.ts
|
|
3576
|
-
function registryCodeToStatus(
|
|
3577
|
-
switch (
|
|
4668
|
+
function registryCodeToStatus(code2) {
|
|
4669
|
+
switch (code2) {
|
|
3578
4670
|
case 0:
|
|
3579
4671
|
return "Active";
|
|
3580
4672
|
case 1:
|
|
@@ -3582,7 +4674,7 @@ function registryCodeToStatus(code) {
|
|
|
3582
4674
|
case 2:
|
|
3583
4675
|
return "Replaced";
|
|
3584
4676
|
default:
|
|
3585
|
-
throw new OmaTrustError("INVALID_INPUT", "Invalid registry status code", { code });
|
|
4677
|
+
throw new OmaTrustError("INVALID_INPUT", "Invalid registry status code", { code: code2 });
|
|
3586
4678
|
}
|
|
3587
4679
|
}
|
|
3588
4680
|
function registryStatusToCode(status) {
|
|
@@ -3684,6 +4776,9 @@ async function computeDataHashFromUrl(url, algorithm) {
|
|
|
3684
4776
|
if (!url || typeof url !== "string") {
|
|
3685
4777
|
throw new OmaTrustError("INVALID_INPUT", "url must be a non-empty string", { url });
|
|
3686
4778
|
}
|
|
4779
|
+
if (algorithm !== "keccak256" && algorithm !== "sha256") {
|
|
4780
|
+
throw new OmaTrustError("INVALID_INPUT", `Unsupported hash algorithm: "${algorithm}". Must be "keccak256" or "sha256".`, { algorithm });
|
|
4781
|
+
}
|
|
3687
4782
|
const json = await fetchJson(url);
|
|
3688
4783
|
const jcsJson = canonicalizeJson(json);
|
|
3689
4784
|
return hashJcs(jcsJson, algorithm);
|