@oma3/omatrust 0.1.0-alpha.10 → 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 +1028 -6
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.d.cts +2 -1
- package/dist/identity/index.d.ts +2 -1
- package/dist/identity/index.js +984 -7
- package/dist/identity/index.js.map +1 -1
- package/dist/index-B5OC9_8B.d.cts +480 -0
- package/dist/index-Bu-xxcv9.d.ts +407 -0
- package/dist/index-C6WNgPRx.d.ts +480 -0
- package/dist/index-C7odEbp6.d.cts +407 -0
- package/dist/index.cjs +2498 -373
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2342 -236
- package/dist/index.js.map +1 -1
- package/dist/reputation/index.browser.cjs +949 -67
- package/dist/reputation/index.browser.cjs.map +1 -1
- package/dist/reputation/index.browser.d.cts +2 -2
- package/dist/reputation/index.browser.d.ts +2 -2
- package/dist/reputation/index.browser.js +947 -67
- package/dist/reputation/index.browser.js.map +1 -1
- package/dist/reputation/index.cjs +1745 -232
- package/dist/reputation/index.cjs.map +1 -1
- package/dist/reputation/index.d.cts +3 -2
- package/dist/reputation/index.d.ts +3 -2
- package/dist/reputation/index.js +1727 -232
- package/dist/reputation/index.js.map +1 -1
- package/dist/{subject-ownership-CXvzEjpH.d.cts → subject-ownership-B7cFlm8c.d.cts} +256 -26
- package/dist/{subject-ownership-CXvzEjpH.d.ts → subject-ownership-B7cFlm8c.d.ts} +256 -26
- package/dist/types-Dn0OwaNj.d.cts +307 -0
- package/dist/types-Dn0OwaNj.d.ts +307 -0
- package/dist/widgets/index.cjs +70 -27
- package/dist/widgets/index.cjs.map +1 -1
- package/dist/widgets/index.d.cts +45 -18
- package/dist/widgets/index.d.ts +45 -18
- package/dist/widgets/index.js +67 -26
- package/dist/widgets/index.js.map +1 -1
- package/package.json +5 -2
- package/dist/index-B9KW02US.d.cts +0 -119
- package/dist/index-DXrwBex9.d.ts +0 -119
- package/dist/index-QZDExA4I.d.cts +0 -90
- package/dist/index-QZDExA4I.d.ts +0 -90
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var jose = require('jose');
|
|
3
4
|
var ethers = require('ethers');
|
|
4
5
|
var easSdk = require('@ethereum-attestation-service/eas-sdk');
|
|
5
6
|
var canonicalize = require('canonicalize');
|
|
@@ -41,6 +42,11 @@ function assertString(value, name, code = "INVALID_INPUT") {
|
|
|
41
42
|
throw new OmaTrustError(code, `${name} must be a non-empty string`, { value });
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
function assertObject(value, name, code = "INVALID_INPUT") {
|
|
46
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
47
|
+
throw new OmaTrustError(code, `${name} must be an object`, { value });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
44
50
|
var init_assert = __esm({
|
|
45
51
|
"src/shared/assert.ts"() {
|
|
46
52
|
init_errors();
|
|
@@ -71,6 +77,152 @@ var init_caip = __esm({
|
|
|
71
77
|
CAIP_10_REGEX = /^(?<namespace>[a-z0-9-]+):(?<reference>[a-zA-Z0-9-]+):(?<address>.+)$/;
|
|
72
78
|
}
|
|
73
79
|
});
|
|
80
|
+
function validatePublicJwk(jwk) {
|
|
81
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
82
|
+
return { valid: false, error: "JWK must be a non-null object" };
|
|
83
|
+
}
|
|
84
|
+
const obj = jwk;
|
|
85
|
+
const kty = obj.kty;
|
|
86
|
+
if (typeof kty !== "string" || !VALID_KTY.has(kty)) {
|
|
87
|
+
return {
|
|
88
|
+
valid: false,
|
|
89
|
+
error: `Invalid or missing kty (must be one of: ${[...VALID_KTY].join(", ")})`
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
for (const field of PRIVATE_KEY_FIELDS) {
|
|
93
|
+
if (field in obj) {
|
|
94
|
+
return {
|
|
95
|
+
valid: false,
|
|
96
|
+
error: `JWK contains private key field "${field}" \u2014 only public keys are allowed`
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const required = REQUIRED_PUBLIC_FIELDS[kty];
|
|
101
|
+
if (required) {
|
|
102
|
+
for (const field of required) {
|
|
103
|
+
if (!(field in obj) || obj[field] === void 0 || obj[field] === null || obj[field] === "") {
|
|
104
|
+
return {
|
|
105
|
+
valid: false,
|
|
106
|
+
error: `Missing required public key field "${field}" for kty="${kty}"`
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { valid: true };
|
|
112
|
+
}
|
|
113
|
+
function canonicalizeJwkJson(jwk) {
|
|
114
|
+
const sorted = Object.keys(jwk).sort();
|
|
115
|
+
const obj = {};
|
|
116
|
+
for (const key of sorted) {
|
|
117
|
+
obj[key] = jwk[key];
|
|
118
|
+
}
|
|
119
|
+
return JSON.stringify(obj);
|
|
120
|
+
}
|
|
121
|
+
function jwkToDidJwk(jwk) {
|
|
122
|
+
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
123
|
+
const validation = validatePublicJwk(jwk);
|
|
124
|
+
if (!validation.valid) {
|
|
125
|
+
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
126
|
+
}
|
|
127
|
+
const canonical = canonicalizeJwkJson(jwk);
|
|
128
|
+
const encoded = jose.base64url.encode(new TextEncoder().encode(canonical));
|
|
129
|
+
return `did:jwk:${encoded}`;
|
|
130
|
+
}
|
|
131
|
+
function didJwkToJwk(didJwk) {
|
|
132
|
+
if (typeof didJwk !== "string" || !didJwk.startsWith("did:jwk:")) {
|
|
133
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:jwk DID", { input: didJwk });
|
|
134
|
+
}
|
|
135
|
+
const parts = didJwk.split(":");
|
|
136
|
+
if (parts.length !== 3) {
|
|
137
|
+
throw new OmaTrustError("INVALID_DID", "did:jwk must have exactly 3 colon-separated parts", {
|
|
138
|
+
input: didJwk
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const encoded = parts[2];
|
|
142
|
+
if (!encoded || encoded.length === 0) {
|
|
143
|
+
throw new OmaTrustError("INVALID_DID", "Missing base64url-encoded JWK identifier", {
|
|
144
|
+
input: didJwk
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
let decoded;
|
|
148
|
+
try {
|
|
149
|
+
const bytes = jose.base64url.decode(encoded);
|
|
150
|
+
decoded = new TextDecoder().decode(bytes);
|
|
151
|
+
} catch {
|
|
152
|
+
throw new OmaTrustError("INVALID_DID", "Failed to base64url-decode did:jwk identifier", {
|
|
153
|
+
input: didJwk
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
let jwk;
|
|
157
|
+
try {
|
|
158
|
+
jwk = JSON.parse(decoded);
|
|
159
|
+
} catch {
|
|
160
|
+
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk identifier is not valid JSON", {
|
|
161
|
+
input: didJwk
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
165
|
+
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk must be a JSON object", {
|
|
166
|
+
input: didJwk
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const validation = validatePublicJwk(jwk);
|
|
170
|
+
if (!validation.valid) {
|
|
171
|
+
throw new OmaTrustError("INVALID_DID", validation.error ?? "Invalid public JWK in did:jwk", {
|
|
172
|
+
input: didJwk
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return jwk;
|
|
176
|
+
}
|
|
177
|
+
function extractPublicKeyFields(jwk) {
|
|
178
|
+
const result = {};
|
|
179
|
+
const metadataFields = /* @__PURE__ */ new Set(["kid", "use", "key_ops", "alg", "ext"]);
|
|
180
|
+
for (const [key, value] of Object.entries(jwk)) {
|
|
181
|
+
if (PRIVATE_KEY_FIELDS.has(key)) continue;
|
|
182
|
+
if (metadataFields.has(key)) continue;
|
|
183
|
+
result[key] = value;
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
function publicJwkEquals(a, b) {
|
|
188
|
+
assertObject(a, "a", "INVALID_JWK");
|
|
189
|
+
assertObject(b, "b", "INVALID_JWK");
|
|
190
|
+
const aObj = a;
|
|
191
|
+
const bObj = b;
|
|
192
|
+
for (const field of PRIVATE_KEY_FIELDS) {
|
|
193
|
+
if (field in aObj) {
|
|
194
|
+
throw new OmaTrustError(
|
|
195
|
+
"INVALID_JWK",
|
|
196
|
+
`First JWK contains private key field "${field}"`,
|
|
197
|
+
{ field }
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
if (field in bObj) {
|
|
201
|
+
throw new OmaTrustError(
|
|
202
|
+
"INVALID_JWK",
|
|
203
|
+
`Second JWK contains private key field "${field}"`,
|
|
204
|
+
{ field }
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const aPublic = extractPublicKeyFields(aObj);
|
|
209
|
+
const bPublic = extractPublicKeyFields(bObj);
|
|
210
|
+
return canonicalizeJwkJson(aPublic) === canonicalizeJwkJson(bPublic);
|
|
211
|
+
}
|
|
212
|
+
var VALID_KTY, PRIVATE_KEY_FIELDS, REQUIRED_PUBLIC_FIELDS;
|
|
213
|
+
var init_jwk = __esm({
|
|
214
|
+
"src/identity/jwk.ts"() {
|
|
215
|
+
init_errors();
|
|
216
|
+
init_assert();
|
|
217
|
+
VALID_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
|
|
218
|
+
PRIVATE_KEY_FIELDS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
|
|
219
|
+
REQUIRED_PUBLIC_FIELDS = {
|
|
220
|
+
EC: ["crv", "x", "y"],
|
|
221
|
+
OKP: ["crv", "x"],
|
|
222
|
+
RSA: ["n", "e"]
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
});
|
|
74
226
|
function isValidDid(did) {
|
|
75
227
|
return DID_REGEX.test(did);
|
|
76
228
|
}
|
|
@@ -139,7 +291,7 @@ function normalizeDidKey(input) {
|
|
|
139
291
|
}
|
|
140
292
|
function normalizeDid(input) {
|
|
141
293
|
assertString(input, "input", "INVALID_DID");
|
|
142
|
-
const trimmed = input.trim();
|
|
294
|
+
const trimmed = input.trim().split("#")[0];
|
|
143
295
|
if (!trimmed.startsWith("did:")) {
|
|
144
296
|
return normalizeDidWeb(trimmed);
|
|
145
297
|
}
|
|
@@ -156,6 +308,8 @@ function normalizeDid(input) {
|
|
|
156
308
|
return normalizeDidHandle(trimmed);
|
|
157
309
|
case "key":
|
|
158
310
|
return normalizeDidKey(trimmed);
|
|
311
|
+
case "jwk":
|
|
312
|
+
return normalizeDidJwk(trimmed);
|
|
159
313
|
default:
|
|
160
314
|
return trimmed;
|
|
161
315
|
}
|
|
@@ -245,13 +399,85 @@ function extractAddressFromDid(identifier) {
|
|
|
245
399
|
}
|
|
246
400
|
throw new OmaTrustError("INVALID_DID", "Unsupported identifier format", { identifier });
|
|
247
401
|
}
|
|
248
|
-
|
|
402
|
+
function validateDidJwk(did) {
|
|
403
|
+
const parts = did.split(":");
|
|
404
|
+
if (parts.length !== 3) {
|
|
405
|
+
return {
|
|
406
|
+
valid: false,
|
|
407
|
+
method: "jwk",
|
|
408
|
+
error: `did:jwk must have exactly 3 colon-separated parts, got ${parts.length}`
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
const [, , encoded] = parts;
|
|
412
|
+
if (!encoded || encoded.length === 0) {
|
|
413
|
+
return { valid: false, method: "jwk", error: "Missing base64url-encoded JWK identifier" };
|
|
414
|
+
}
|
|
415
|
+
if (!BASE64URL_REGEX.test(encoded)) {
|
|
416
|
+
return {
|
|
417
|
+
valid: false,
|
|
418
|
+
method: "jwk",
|
|
419
|
+
error: "Identifier contains invalid base64url characters"
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
let decoded;
|
|
423
|
+
try {
|
|
424
|
+
const bytes = jose.base64url.decode(encoded);
|
|
425
|
+
decoded = new TextDecoder().decode(bytes);
|
|
426
|
+
} catch {
|
|
427
|
+
return { valid: false, method: "jwk", error: "Failed to base64url-decode identifier" };
|
|
428
|
+
}
|
|
429
|
+
let jwk;
|
|
430
|
+
try {
|
|
431
|
+
jwk = JSON.parse(decoded);
|
|
432
|
+
} catch {
|
|
433
|
+
return { valid: false, method: "jwk", error: "Decoded identifier is not valid JSON" };
|
|
434
|
+
}
|
|
435
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
436
|
+
return { valid: false, method: "jwk", error: "Decoded JWK must be a JSON object" };
|
|
437
|
+
}
|
|
438
|
+
const kty = jwk.kty;
|
|
439
|
+
if (typeof kty !== "string" || !VALID_JWK_KTY.has(kty)) {
|
|
440
|
+
return {
|
|
441
|
+
valid: false,
|
|
442
|
+
method: "jwk",
|
|
443
|
+
error: `Invalid or missing kty field (must be one of: EC, OKP, RSA)`
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
if ("d" in jwk) {
|
|
447
|
+
return {
|
|
448
|
+
valid: false,
|
|
449
|
+
method: "jwk",
|
|
450
|
+
error: "DID must reference a public key \u2014 private key component (d) is not allowed"
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const jwkValidation = validatePublicJwk(jwk);
|
|
454
|
+
if (!jwkValidation.valid) {
|
|
455
|
+
return { valid: false, method: "jwk", error: jwkValidation.error };
|
|
456
|
+
}
|
|
457
|
+
return { valid: true, method: "jwk" };
|
|
458
|
+
}
|
|
459
|
+
function normalizeDidJwk(input) {
|
|
460
|
+
assertString(input, "input", "INVALID_DID");
|
|
461
|
+
const trimmed = input.trim();
|
|
462
|
+
if (!trimmed.startsWith("did:jwk:")) {
|
|
463
|
+
throw new OmaTrustError("INVALID_DID", "Expected did:jwk DID", { input });
|
|
464
|
+
}
|
|
465
|
+
const result = validateDidJwk(trimmed);
|
|
466
|
+
if (!result.valid) {
|
|
467
|
+
throw new OmaTrustError("INVALID_DID", result.error ?? "Invalid did:jwk", { input });
|
|
468
|
+
}
|
|
469
|
+
return trimmed;
|
|
470
|
+
}
|
|
471
|
+
var DID_REGEX, BASE64URL_REGEX, VALID_JWK_KTY;
|
|
249
472
|
var init_did = __esm({
|
|
250
473
|
"src/identity/did.ts"() {
|
|
251
474
|
init_errors();
|
|
252
475
|
init_assert();
|
|
253
476
|
init_caip();
|
|
477
|
+
init_jwk();
|
|
254
478
|
DID_REGEX = /^did:[a-z0-9]+:.+$/i;
|
|
479
|
+
BASE64URL_REGEX = /^[A-Za-z0-9_-]+$/;
|
|
480
|
+
VALID_JWK_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
|
|
255
481
|
}
|
|
256
482
|
});
|
|
257
483
|
|
|
@@ -262,21 +488,23 @@ function parseDnsTxtRecord(record) {
|
|
|
262
488
|
}
|
|
263
489
|
const entries = record.split(/[;\s]+/).map((entry) => entry.trim()).filter(Boolean);
|
|
264
490
|
const parsed = {};
|
|
491
|
+
const controllers = [];
|
|
265
492
|
for (const entry of entries) {
|
|
266
|
-
const
|
|
267
|
-
if (
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (
|
|
272
|
-
|
|
493
|
+
const eqIndex = entry.indexOf("=");
|
|
494
|
+
if (eqIndex === -1) continue;
|
|
495
|
+
const key = entry.slice(0, eqIndex).trim();
|
|
496
|
+
const value = entry.slice(eqIndex + 1).trim();
|
|
497
|
+
if (!key || !value) continue;
|
|
498
|
+
if (key === "controller") {
|
|
499
|
+
controllers.push(value);
|
|
500
|
+
} else {
|
|
501
|
+
parsed[key] = value;
|
|
273
502
|
}
|
|
274
|
-
parsed[key.trim()] = value.trim();
|
|
275
503
|
}
|
|
276
504
|
return {
|
|
277
505
|
version: parsed.v,
|
|
278
|
-
controller:
|
|
279
|
-
|
|
506
|
+
controller: controllers[0],
|
|
507
|
+
controllers
|
|
280
508
|
};
|
|
281
509
|
}
|
|
282
510
|
function buildDnsTxtRecord(controllerDid) {
|
|
@@ -290,6 +518,56 @@ var init_dns_txt_record = __esm({
|
|
|
290
518
|
}
|
|
291
519
|
});
|
|
292
520
|
|
|
521
|
+
// src/identity/controller-id.ts
|
|
522
|
+
function isSameControllerId(a, b) {
|
|
523
|
+
let normalizedA = null;
|
|
524
|
+
let normalizedB = null;
|
|
525
|
+
try {
|
|
526
|
+
normalizedA = normalizeDid(a);
|
|
527
|
+
} catch {
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
normalizedB = normalizeDid(b);
|
|
531
|
+
} catch {
|
|
532
|
+
}
|
|
533
|
+
if (normalizedA && normalizedB && normalizedA === normalizedB) {
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
const evmA = extractControllerEvmAddress(a);
|
|
537
|
+
const evmB = extractControllerEvmAddress(b);
|
|
538
|
+
if (evmA && evmB && evmA.toLowerCase() === evmB.toLowerCase()) {
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
const methodA = extractDidMethod(a);
|
|
542
|
+
const methodB = extractDidMethod(b);
|
|
543
|
+
if (methodA === "jwk" && methodB === "jwk") {
|
|
544
|
+
try {
|
|
545
|
+
const jwkA = didJwkToJwk(a);
|
|
546
|
+
const jwkB = didJwkToJwk(b);
|
|
547
|
+
return publicJwkEquals(jwkA, jwkB);
|
|
548
|
+
} catch {
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
function extractControllerEvmAddress(controllerDid) {
|
|
555
|
+
try {
|
|
556
|
+
const method = extractDidMethod(controllerDid);
|
|
557
|
+
if (method === "pkh" && controllerDid.includes("eip155")) {
|
|
558
|
+
return extractAddressFromDid(controllerDid);
|
|
559
|
+
}
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
var init_controller_id = __esm({
|
|
565
|
+
"src/identity/controller-id.ts"() {
|
|
566
|
+
init_did();
|
|
567
|
+
init_jwk();
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
|
|
293
571
|
// src/reputation/proof/dns-txt-shared.ts
|
|
294
572
|
var dns_txt_shared_exports = {};
|
|
295
573
|
__export(dns_txt_shared_exports, {
|
|
@@ -302,7 +580,6 @@ async function verifyDnsTxtControllerDid(domain, expectedControllerDid, options
|
|
|
302
580
|
if (!options.resolveTxt) {
|
|
303
581
|
throw new OmaTrustError("NETWORK_ERROR", "No DNS TXT resolver was provided", { domain });
|
|
304
582
|
}
|
|
305
|
-
const expected = normalizeDid(expectedControllerDid);
|
|
306
583
|
const prefix = options.recordPrefix ?? "_controllers";
|
|
307
584
|
const host = `${prefix}.${domain.toLowerCase().replace(/\.$/, "")}`;
|
|
308
585
|
let records;
|
|
@@ -314,15 +591,18 @@ async function verifyDnsTxtControllerDid(domain, expectedControllerDid, options
|
|
|
314
591
|
for (const recordParts of records) {
|
|
315
592
|
const record = recordParts.join("");
|
|
316
593
|
const parsed = parseDnsTxtRecord(record);
|
|
317
|
-
if (parsed.version
|
|
318
|
-
|
|
594
|
+
if (parsed.version !== "1") continue;
|
|
595
|
+
for (const recordController of parsed.controllers) {
|
|
596
|
+
if (isSameControllerId(recordController, expectedControllerDid)) {
|
|
597
|
+
return { valid: true, record };
|
|
598
|
+
}
|
|
319
599
|
}
|
|
320
600
|
}
|
|
321
|
-
return { valid: false, reason: "
|
|
601
|
+
return { valid: false, reason: "Controller DID not found in DNS TXT records" };
|
|
322
602
|
}
|
|
323
603
|
var init_dns_txt_shared = __esm({
|
|
324
604
|
"src/reputation/proof/dns-txt-shared.ts"() {
|
|
325
|
-
|
|
605
|
+
init_controller_id();
|
|
326
606
|
init_errors();
|
|
327
607
|
init_dns_txt_record();
|
|
328
608
|
}
|
|
@@ -793,19 +1073,32 @@ async function submitDelegatedAttestation(params) {
|
|
|
793
1073
|
payload = {};
|
|
794
1074
|
}
|
|
795
1075
|
if (!response.ok) {
|
|
796
|
-
|
|
797
|
-
|
|
1076
|
+
const relayError = {
|
|
1077
|
+
httpStatus: response.status,
|
|
1078
|
+
code: payload.code,
|
|
1079
|
+
error: payload.error ?? payload.message,
|
|
798
1080
|
payload
|
|
799
|
-
}
|
|
1081
|
+
};
|
|
1082
|
+
throw new OmaTrustError("RELAY_ERROR", `Relay submission failed (HTTP ${response.status})`, relayError);
|
|
800
1083
|
}
|
|
801
1084
|
const uid = payload.uid ?? ZERO_UID;
|
|
802
1085
|
const txHash = payload.txHash;
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1086
|
+
const hasConfirmationSignals = payload.status === "confirmed" || payload.success === true || typeof payload.blockNumber === "number";
|
|
1087
|
+
const status = hasConfirmationSignals ? "confirmed" : "submitted";
|
|
1088
|
+
const relay = {};
|
|
1089
|
+
if (typeof payload.blockNumber === "number") relay.blockNumber = payload.blockNumber;
|
|
1090
|
+
if (typeof payload.chain === "string") relay.chain = payload.chain;
|
|
1091
|
+
if (typeof payload.success === "boolean") relay.success = payload.success;
|
|
1092
|
+
for (const key of Object.keys(payload)) {
|
|
1093
|
+
if (!["uid", "txHash", "status", "blockNumber", "chain", "success"].includes(key)) {
|
|
1094
|
+
relay[key] = payload[key];
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
const result = { uid, txHash, status };
|
|
1098
|
+
if (Object.keys(relay).length > 0) {
|
|
1099
|
+
result.relay = relay;
|
|
1100
|
+
}
|
|
1101
|
+
return result;
|
|
809
1102
|
}
|
|
810
1103
|
|
|
811
1104
|
// src/reputation/query.ts
|
|
@@ -911,7 +1204,7 @@ async function getAttestationsForDid(params) {
|
|
|
911
1204
|
provider,
|
|
912
1205
|
fromBlock,
|
|
913
1206
|
toBlock,
|
|
914
|
-
{ recipient: didToAddress(params.
|
|
1207
|
+
{ recipient: didToAddress(params.subjectDid), schemas: params.schemas }
|
|
915
1208
|
);
|
|
916
1209
|
}
|
|
917
1210
|
async function getAttestationsByAttester(params) {
|
|
@@ -1163,6 +1456,10 @@ function getExplorerAddressUrl(chainId, address) {
|
|
|
1163
1456
|
|
|
1164
1457
|
// src/reputation/proof/did-json.ts
|
|
1165
1458
|
init_did();
|
|
1459
|
+
init_jwk();
|
|
1460
|
+
init_errors();
|
|
1461
|
+
|
|
1462
|
+
// src/shared/did-document.ts
|
|
1166
1463
|
init_errors();
|
|
1167
1464
|
async function fetchDidDocument(domain) {
|
|
1168
1465
|
const normalized = domain.toLowerCase().replace(/\.$/, "");
|
|
@@ -1174,15 +1471,16 @@ async function fetchDidDocument(domain) {
|
|
|
1174
1471
|
throw new OmaTrustError("NETWORK_ERROR", "Failed to fetch DID document", { domain, err });
|
|
1175
1472
|
}
|
|
1176
1473
|
if (!response.ok) {
|
|
1177
|
-
throw new OmaTrustError("NETWORK_ERROR",
|
|
1474
|
+
throw new OmaTrustError("NETWORK_ERROR", `DID document fetch failed: ${response.status}`, {
|
|
1178
1475
|
domain,
|
|
1179
1476
|
status: response.status
|
|
1180
1477
|
});
|
|
1181
1478
|
}
|
|
1182
|
-
|
|
1183
|
-
return body;
|
|
1479
|
+
return await response.json();
|
|
1184
1480
|
}
|
|
1185
|
-
|
|
1481
|
+
|
|
1482
|
+
// src/reputation/proof/did-json.ts
|
|
1483
|
+
function extractEvmAddressesFromDidDocument(didDocument) {
|
|
1186
1484
|
const methods = didDocument.verificationMethod;
|
|
1187
1485
|
if (!Array.isArray(methods)) {
|
|
1188
1486
|
return [];
|
|
@@ -1206,14 +1504,52 @@ function extractAddressesFromDidDocument(didDocument) {
|
|
|
1206
1504
|
}
|
|
1207
1505
|
return [...addresses];
|
|
1208
1506
|
}
|
|
1507
|
+
function extractJwksFromDidDocument(didDocument) {
|
|
1508
|
+
const methods = didDocument.verificationMethod;
|
|
1509
|
+
if (!Array.isArray(methods)) {
|
|
1510
|
+
return [];
|
|
1511
|
+
}
|
|
1512
|
+
const jwks = [];
|
|
1513
|
+
for (const method of methods) {
|
|
1514
|
+
const publicKeyJwk = method.publicKeyJwk;
|
|
1515
|
+
if (publicKeyJwk && typeof publicKeyJwk === "object" && !Array.isArray(publicKeyJwk)) {
|
|
1516
|
+
jwks.push(publicKeyJwk);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
return jwks;
|
|
1520
|
+
}
|
|
1209
1521
|
function verifyDidDocumentControllerDid(didDocument, expectedControllerDid) {
|
|
1522
|
+
const method = extractDidMethod(expectedControllerDid);
|
|
1523
|
+
if (method === "jwk") {
|
|
1524
|
+
try {
|
|
1525
|
+
const expectedJwk = didJwkToJwk(expectedControllerDid);
|
|
1526
|
+
const documentJwks = extractJwksFromDidDocument(didDocument);
|
|
1527
|
+
for (const docJwk of documentJwks) {
|
|
1528
|
+
try {
|
|
1529
|
+
if (publicJwkEquals(docJwk, expectedJwk)) {
|
|
1530
|
+
return { valid: true };
|
|
1531
|
+
}
|
|
1532
|
+
} catch {
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
return {
|
|
1536
|
+
valid: false,
|
|
1537
|
+
reason: "No matching publicKeyJwk found in DID document verification methods"
|
|
1538
|
+
};
|
|
1539
|
+
} catch {
|
|
1540
|
+
return {
|
|
1541
|
+
valid: false,
|
|
1542
|
+
reason: "Failed to decode did:jwk controller DID"
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1210
1546
|
let expectedAddress;
|
|
1211
1547
|
try {
|
|
1212
1548
|
expectedAddress = ethers.getAddress(extractAddressFromDid(expectedControllerDid));
|
|
1213
1549
|
} catch {
|
|
1214
|
-
return { valid: false, reason: "
|
|
1550
|
+
return { valid: false, reason: "Controller DID does not resolve to an EVM address and is not did:jwk" };
|
|
1215
1551
|
}
|
|
1216
|
-
const addresses =
|
|
1552
|
+
const addresses = extractEvmAddressesFromDidDocument(didDocument);
|
|
1217
1553
|
if (addresses.some((address) => address.toLowerCase() === expectedAddress.toLowerCase())) {
|
|
1218
1554
|
return { valid: true };
|
|
1219
1555
|
}
|
|
@@ -1267,6 +1603,469 @@ function verifyEip712Signature(typedData, signature) {
|
|
|
1267
1603
|
|
|
1268
1604
|
// src/reputation/verify.ts
|
|
1269
1605
|
init_dns_txt_record();
|
|
1606
|
+
|
|
1607
|
+
// src/reputation/proof/x402-jws.ts
|
|
1608
|
+
init_errors();
|
|
1609
|
+
init_jwk();
|
|
1610
|
+
|
|
1611
|
+
// src/identity/resolve-key.ts
|
|
1612
|
+
init_errors();
|
|
1613
|
+
init_assert();
|
|
1614
|
+
|
|
1615
|
+
// src/identity/did-url.ts
|
|
1616
|
+
init_errors();
|
|
1617
|
+
init_assert();
|
|
1618
|
+
var DID_URL_REGEX = /^did:[a-z0-9]+:.+$/i;
|
|
1619
|
+
function parseDidUrl(input) {
|
|
1620
|
+
assertString(input, "input", "INVALID_DID_URL");
|
|
1621
|
+
const trimmed = input.trim();
|
|
1622
|
+
const hashIndex = trimmed.indexOf("#");
|
|
1623
|
+
let did;
|
|
1624
|
+
let fragment;
|
|
1625
|
+
if (hashIndex === -1) {
|
|
1626
|
+
did = trimmed;
|
|
1627
|
+
fragment = null;
|
|
1628
|
+
} else {
|
|
1629
|
+
did = trimmed.slice(0, hashIndex);
|
|
1630
|
+
const rawFragment = trimmed.slice(hashIndex + 1);
|
|
1631
|
+
if (rawFragment.length === 0) {
|
|
1632
|
+
throw new OmaTrustError(
|
|
1633
|
+
"INVALID_DID_URL",
|
|
1634
|
+
"DID URL has empty fragment (trailing '#' with no identifier)",
|
|
1635
|
+
{ input }
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
fragment = rawFragment;
|
|
1639
|
+
}
|
|
1640
|
+
if (!DID_URL_REGEX.test(did)) {
|
|
1641
|
+
throw new OmaTrustError(
|
|
1642
|
+
"INVALID_DID_URL",
|
|
1643
|
+
"Invalid DID URL: base DID portion is malformed",
|
|
1644
|
+
{ input, did }
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
return {
|
|
1648
|
+
didUrl: trimmed,
|
|
1649
|
+
did,
|
|
1650
|
+
fragment
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// src/identity/resolve-key.ts
|
|
1655
|
+
init_did();
|
|
1656
|
+
init_jwk();
|
|
1657
|
+
function findVerificationMethod(didDocument, didUrl, fragment) {
|
|
1658
|
+
const methods = didDocument.verificationMethod;
|
|
1659
|
+
if (!Array.isArray(methods)) {
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
for (const method of methods) {
|
|
1663
|
+
if (!method || typeof method !== "object") continue;
|
|
1664
|
+
const id = method.id;
|
|
1665
|
+
if (typeof id !== "string") continue;
|
|
1666
|
+
if (id === didUrl) return method;
|
|
1667
|
+
if (fragment && (id === `#${fragment}` || id.endsWith(`#${fragment}`))) {
|
|
1668
|
+
return method;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
return null;
|
|
1672
|
+
}
|
|
1673
|
+
function extractMethodIdsFromDidDocument(didDocument) {
|
|
1674
|
+
const methods = didDocument.verificationMethod;
|
|
1675
|
+
if (!Array.isArray(methods)) return [];
|
|
1676
|
+
return methods.filter((m) => m && typeof m.id === "string").map((m) => m.id);
|
|
1677
|
+
}
|
|
1678
|
+
async function resolveDidUrlToPublicKey(didUrl, options) {
|
|
1679
|
+
assertString(didUrl, "didUrl", "INVALID_DID_URL");
|
|
1680
|
+
const parsed = parseDidUrl(didUrl);
|
|
1681
|
+
const method = extractDidMethod(parsed.did);
|
|
1682
|
+
if (!method) {
|
|
1683
|
+
throw new OmaTrustError("INVALID_DID_URL", "Cannot extract DID method from DID URL", {
|
|
1684
|
+
didUrl,
|
|
1685
|
+
did: parsed.did
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
switch (method) {
|
|
1689
|
+
case "web":
|
|
1690
|
+
return resolveDidUrlKey(parsed.didUrl, parsed.did, parsed.fragment);
|
|
1691
|
+
default:
|
|
1692
|
+
throw new OmaTrustError(
|
|
1693
|
+
"UNSUPPORTED_DID_METHOD",
|
|
1694
|
+
`DID URL key resolution is not supported for method "${method}"`,
|
|
1695
|
+
{ didUrl, method }
|
|
1696
|
+
);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
async function resolveDidUrlKey(didUrl, did, fragment, options) {
|
|
1700
|
+
const domain = getDomainFromDidWeb(did);
|
|
1701
|
+
if (!domain) {
|
|
1702
|
+
throw new OmaTrustError("INVALID_DID_URL", "Cannot extract domain from did:web DID", {
|
|
1703
|
+
didUrl,
|
|
1704
|
+
did
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
const fetchFn = fetchDidDocument;
|
|
1708
|
+
const didDocument = await fetchFn(domain);
|
|
1709
|
+
const method = findVerificationMethod(didDocument, didUrl, fragment);
|
|
1710
|
+
if (!method) {
|
|
1711
|
+
throw new OmaTrustError(
|
|
1712
|
+
"KEY_NOT_FOUND",
|
|
1713
|
+
`No verification method found matching "${fragment ? `#${fragment}` : didUrl}"`,
|
|
1714
|
+
{ didUrl, fragment, availableMethods: extractMethodIdsFromDidDocument(didDocument) }
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
const publicKeyJwk = method.publicKeyJwk;
|
|
1718
|
+
if (!publicKeyJwk || typeof publicKeyJwk !== "object") {
|
|
1719
|
+
throw new OmaTrustError(
|
|
1720
|
+
"KEY_NOT_FOUND",
|
|
1721
|
+
`Verification method "${method.id}" does not contain publicKeyJwk`,
|
|
1722
|
+
{ didUrl, verificationMethodId: method.id }
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
const validation = validatePublicJwk(publicKeyJwk);
|
|
1726
|
+
if (!validation.valid) {
|
|
1727
|
+
throw new OmaTrustError(
|
|
1728
|
+
"INVALID_JWK",
|
|
1729
|
+
`publicKeyJwk in verification method "${method.id}" is invalid: ${validation.error}`,
|
|
1730
|
+
{ didUrl, verificationMethodId: method.id }
|
|
1731
|
+
);
|
|
1732
|
+
}
|
|
1733
|
+
return {
|
|
1734
|
+
didUrl,
|
|
1735
|
+
did,
|
|
1736
|
+
fragment,
|
|
1737
|
+
publicKeyJwk,
|
|
1738
|
+
verificationMethodId: method.id
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// src/reputation/proof/x402-jws.ts
|
|
1743
|
+
var REQUIRED_OFFER_FIELDS = [
|
|
1744
|
+
"version",
|
|
1745
|
+
"resourceUrl",
|
|
1746
|
+
"scheme",
|
|
1747
|
+
"network",
|
|
1748
|
+
"asset",
|
|
1749
|
+
"payTo",
|
|
1750
|
+
"amount"
|
|
1751
|
+
];
|
|
1752
|
+
var REQUIRED_RECEIPT_FIELDS = [
|
|
1753
|
+
"version",
|
|
1754
|
+
"network",
|
|
1755
|
+
"resourceUrl",
|
|
1756
|
+
"payer",
|
|
1757
|
+
"issuedAt"
|
|
1758
|
+
];
|
|
1759
|
+
function validateOfferPayload(payload) {
|
|
1760
|
+
for (const field of REQUIRED_OFFER_FIELDS) {
|
|
1761
|
+
if (!(field in payload) || payload[field] === void 0 || payload[field] === null) {
|
|
1762
|
+
return { valid: false, field };
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
return { valid: true };
|
|
1766
|
+
}
|
|
1767
|
+
function validateReceiptPayload(payload) {
|
|
1768
|
+
for (const field of REQUIRED_RECEIPT_FIELDS) {
|
|
1769
|
+
if (!(field in payload) || payload[field] === void 0 || payload[field] === null) {
|
|
1770
|
+
return { valid: false, field };
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
return { valid: true };
|
|
1774
|
+
}
|
|
1775
|
+
function failure(code, message, partial) {
|
|
1776
|
+
return {
|
|
1777
|
+
valid: false,
|
|
1778
|
+
error: { code, message },
|
|
1779
|
+
...partial
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
async function verifyX402JwsArtifact(artifact, options) {
|
|
1783
|
+
if (!artifact || typeof artifact !== "object") {
|
|
1784
|
+
return failure("INVALID_ARTIFACT", "Artifact must be a non-null object");
|
|
1785
|
+
}
|
|
1786
|
+
if (artifact.format !== "jws") {
|
|
1787
|
+
return failure("INVALID_ARTIFACT", `Expected format "jws", got "${artifact.format}"`);
|
|
1788
|
+
}
|
|
1789
|
+
if (typeof artifact.signature !== "string" || artifact.signature.length === 0) {
|
|
1790
|
+
return failure("INVALID_ARTIFACT", "Artifact signature must be a non-empty string");
|
|
1791
|
+
}
|
|
1792
|
+
const compactJws = artifact.signature;
|
|
1793
|
+
const parts = compactJws.split(".");
|
|
1794
|
+
if (parts.length !== 3) {
|
|
1795
|
+
return failure("MALFORMED_JWS", "Invalid compact JWS format: expected 3 dot-separated parts");
|
|
1796
|
+
}
|
|
1797
|
+
let header;
|
|
1798
|
+
try {
|
|
1799
|
+
header = jose.decodeProtectedHeader(compactJws);
|
|
1800
|
+
} catch {
|
|
1801
|
+
return failure("MALFORMED_JWS", "Failed to decode JWS protected header");
|
|
1802
|
+
}
|
|
1803
|
+
if (!header.alg || typeof header.alg !== "string") {
|
|
1804
|
+
return failure("MISSING_ALG", "JWS header must include alg", { header });
|
|
1805
|
+
}
|
|
1806
|
+
const kid = typeof header.kid === "string" ? header.kid : null;
|
|
1807
|
+
const embeddedJwk = header.jwk;
|
|
1808
|
+
if (!kid && !embeddedJwk) {
|
|
1809
|
+
return failure(
|
|
1810
|
+
"MISSING_KEY_MATERIAL",
|
|
1811
|
+
"JWS header must include at least one of kid or jwk",
|
|
1812
|
+
{ header }
|
|
1813
|
+
);
|
|
1814
|
+
}
|
|
1815
|
+
let publicKeyJwk;
|
|
1816
|
+
let publicKeySource;
|
|
1817
|
+
if (embeddedJwk) {
|
|
1818
|
+
const validation = validatePublicJwk(embeddedJwk);
|
|
1819
|
+
if (!validation.valid) {
|
|
1820
|
+
return failure(
|
|
1821
|
+
"INVALID_EMBEDDED_JWK",
|
|
1822
|
+
`Embedded JWK is invalid: ${validation.error}`,
|
|
1823
|
+
{ header }
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
publicKeyJwk = embeddedJwk;
|
|
1827
|
+
publicKeySource = "embedded-jwk";
|
|
1828
|
+
if (kid) {
|
|
1829
|
+
try {
|
|
1830
|
+
const resolved = await resolveDidUrlToPublicKey(kid, options?.resolveOptions);
|
|
1831
|
+
if (!publicJwkEquals(publicKeyJwk, resolved.publicKeyJwk)) {
|
|
1832
|
+
return failure(
|
|
1833
|
+
"KEY_CONFLICT",
|
|
1834
|
+
"Embedded jwk conflicts with public key resolved from kid",
|
|
1835
|
+
{ header, kid }
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
} catch (err) {
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
} else {
|
|
1842
|
+
publicKeySource = "kid-resolution";
|
|
1843
|
+
try {
|
|
1844
|
+
const resolved = await resolveDidUrlToPublicKey(kid, options?.resolveOptions);
|
|
1845
|
+
publicKeyJwk = resolved.publicKeyJwk;
|
|
1846
|
+
} catch (err) {
|
|
1847
|
+
const message = err instanceof OmaTrustError ? `Failed to resolve kid "${kid}": ${err.message}` : `Failed to resolve kid "${kid}"`;
|
|
1848
|
+
return failure("KID_RESOLUTION_FAILED", message, { header, kid });
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
let payload;
|
|
1852
|
+
try {
|
|
1853
|
+
const key = await jose.importJWK(publicKeyJwk, header.alg);
|
|
1854
|
+
const result = await jose.compactVerify(compactJws, key);
|
|
1855
|
+
const payloadText = new TextDecoder().decode(result.payload);
|
|
1856
|
+
payload = JSON.parse(payloadText);
|
|
1857
|
+
} catch (err) {
|
|
1858
|
+
const message = err instanceof Error ? err.message : "Signature verification failed";
|
|
1859
|
+
return failure("SIGNATURE_INVALID", message, { header, kid });
|
|
1860
|
+
}
|
|
1861
|
+
const publicKeyDid = jwkToDidJwk(publicKeyJwk);
|
|
1862
|
+
return {
|
|
1863
|
+
valid: true,
|
|
1864
|
+
header,
|
|
1865
|
+
payload,
|
|
1866
|
+
kid,
|
|
1867
|
+
publicKeyJwk,
|
|
1868
|
+
publicKeySource,
|
|
1869
|
+
publicKeyDid
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1872
|
+
async function verifyX402JwsOffer(artifact, options) {
|
|
1873
|
+
const result = await verifyX402JwsArtifact(artifact, options);
|
|
1874
|
+
if (!result.valid) return result;
|
|
1875
|
+
const payloadCheck = validateOfferPayload(result.payload);
|
|
1876
|
+
if (!payloadCheck.valid) {
|
|
1877
|
+
return failure(
|
|
1878
|
+
"INVALID_OFFER_PAYLOAD",
|
|
1879
|
+
`Missing required offer field: ${payloadCheck.field}`,
|
|
1880
|
+
{
|
|
1881
|
+
header: result.header,
|
|
1882
|
+
payload: result.payload,
|
|
1883
|
+
kid: result.kid,
|
|
1884
|
+
publicKeyJwk: result.publicKeyJwk,
|
|
1885
|
+
publicKeySource: result.publicKeySource,
|
|
1886
|
+
publicKeyDid: result.publicKeyDid
|
|
1887
|
+
}
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
return result;
|
|
1891
|
+
}
|
|
1892
|
+
async function verifyX402JwsReceipt(artifact, options) {
|
|
1893
|
+
const result = await verifyX402JwsArtifact(artifact, options);
|
|
1894
|
+
if (!result.valid) return result;
|
|
1895
|
+
const payloadCheck = validateReceiptPayload(result.payload);
|
|
1896
|
+
if (!payloadCheck.valid) {
|
|
1897
|
+
return failure(
|
|
1898
|
+
"INVALID_RECEIPT_PAYLOAD",
|
|
1899
|
+
`Missing required receipt field: ${payloadCheck.field}`,
|
|
1900
|
+
{
|
|
1901
|
+
header: result.header,
|
|
1902
|
+
payload: result.payload,
|
|
1903
|
+
kid: result.kid,
|
|
1904
|
+
publicKeyJwk: result.publicKeyJwk,
|
|
1905
|
+
publicKeySource: result.publicKeySource,
|
|
1906
|
+
publicKeyDid: result.publicKeyDid
|
|
1907
|
+
}
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
return result;
|
|
1911
|
+
}
|
|
1912
|
+
var OFFER_DOMAIN = {
|
|
1913
|
+
name: "x402 offer",
|
|
1914
|
+
version: "1",
|
|
1915
|
+
chainId: 1
|
|
1916
|
+
};
|
|
1917
|
+
var RECEIPT_DOMAIN = {
|
|
1918
|
+
name: "x402 receipt",
|
|
1919
|
+
version: "1",
|
|
1920
|
+
chainId: 1
|
|
1921
|
+
};
|
|
1922
|
+
var OFFER_TYPES = {
|
|
1923
|
+
Offer: [
|
|
1924
|
+
{ name: "version", type: "uint256" },
|
|
1925
|
+
{ name: "resourceUrl", type: "string" },
|
|
1926
|
+
{ name: "scheme", type: "string" },
|
|
1927
|
+
{ name: "network", type: "string" },
|
|
1928
|
+
{ name: "asset", type: "string" },
|
|
1929
|
+
{ name: "payTo", type: "string" },
|
|
1930
|
+
{ name: "amount", type: "string" },
|
|
1931
|
+
{ name: "validUntil", type: "uint256" }
|
|
1932
|
+
]
|
|
1933
|
+
};
|
|
1934
|
+
var RECEIPT_TYPES = {
|
|
1935
|
+
Receipt: [
|
|
1936
|
+
{ name: "version", type: "uint256" },
|
|
1937
|
+
{ name: "network", type: "string" },
|
|
1938
|
+
{ name: "resourceUrl", type: "string" },
|
|
1939
|
+
{ name: "payer", type: "string" },
|
|
1940
|
+
{ name: "issuedAt", type: "uint256" },
|
|
1941
|
+
{ name: "transaction", type: "string" }
|
|
1942
|
+
]
|
|
1943
|
+
};
|
|
1944
|
+
var REQUIRED_OFFER_FIELDS2 = [
|
|
1945
|
+
"version",
|
|
1946
|
+
"resourceUrl",
|
|
1947
|
+
"scheme",
|
|
1948
|
+
"network",
|
|
1949
|
+
"asset",
|
|
1950
|
+
"payTo",
|
|
1951
|
+
"amount"
|
|
1952
|
+
];
|
|
1953
|
+
var REQUIRED_RECEIPT_FIELDS2 = [
|
|
1954
|
+
"version",
|
|
1955
|
+
"network",
|
|
1956
|
+
"resourceUrl",
|
|
1957
|
+
"payer",
|
|
1958
|
+
"issuedAt"
|
|
1959
|
+
];
|
|
1960
|
+
function validateOfferPayload2(payload) {
|
|
1961
|
+
for (const field of REQUIRED_OFFER_FIELDS2) {
|
|
1962
|
+
if (!(field in payload) || payload[field] === void 0 || payload[field] === null) {
|
|
1963
|
+
return { valid: false, field };
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return { valid: true };
|
|
1967
|
+
}
|
|
1968
|
+
function validateReceiptPayload2(payload) {
|
|
1969
|
+
for (const field of REQUIRED_RECEIPT_FIELDS2) {
|
|
1970
|
+
if (!(field in payload) || payload[field] === void 0 || payload[field] === null) {
|
|
1971
|
+
return { valid: false, field };
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
return { valid: true };
|
|
1975
|
+
}
|
|
1976
|
+
function failure2(code, message, partial) {
|
|
1977
|
+
return {
|
|
1978
|
+
valid: false,
|
|
1979
|
+
error: { code, message },
|
|
1980
|
+
...partial
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
function prepareOfferMessage(payload) {
|
|
1984
|
+
return {
|
|
1985
|
+
version: payload.version,
|
|
1986
|
+
resourceUrl: payload.resourceUrl,
|
|
1987
|
+
scheme: payload.scheme,
|
|
1988
|
+
network: payload.network,
|
|
1989
|
+
asset: payload.asset,
|
|
1990
|
+
payTo: payload.payTo,
|
|
1991
|
+
amount: payload.amount,
|
|
1992
|
+
validUntil: payload.validUntil ?? 0
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
function prepareReceiptMessage(payload) {
|
|
1996
|
+
return {
|
|
1997
|
+
version: payload.version,
|
|
1998
|
+
network: payload.network,
|
|
1999
|
+
resourceUrl: payload.resourceUrl,
|
|
2000
|
+
payer: payload.payer,
|
|
2001
|
+
issuedAt: payload.issuedAt,
|
|
2002
|
+
transaction: payload.transaction ?? ""
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
function verifyX402Eip712Artifact(artifact, artifactType) {
|
|
2006
|
+
if (!artifact || typeof artifact !== "object") {
|
|
2007
|
+
return failure2("INVALID_ARTIFACT", "Artifact must be a non-null object");
|
|
2008
|
+
}
|
|
2009
|
+
if (artifact.format !== "eip712") {
|
|
2010
|
+
return failure2("INVALID_ARTIFACT", `Expected format "eip712", got "${artifact.format}"`);
|
|
2011
|
+
}
|
|
2012
|
+
if (!artifact.payload || typeof artifact.payload !== "object" || Array.isArray(artifact.payload)) {
|
|
2013
|
+
return failure2("MISSING_PAYLOAD", "EIP-712 artifact must include a payload object");
|
|
2014
|
+
}
|
|
2015
|
+
if (typeof artifact.signature !== "string" || artifact.signature.length === 0) {
|
|
2016
|
+
return failure2("MISSING_SIGNATURE", "EIP-712 artifact must include a non-empty signature");
|
|
2017
|
+
}
|
|
2018
|
+
const payload = artifact.payload;
|
|
2019
|
+
if (artifactType === "offer") {
|
|
2020
|
+
const check = validateOfferPayload2(payload);
|
|
2021
|
+
if (!check.valid) {
|
|
2022
|
+
return failure2(
|
|
2023
|
+
"INVALID_OFFER_PAYLOAD",
|
|
2024
|
+
`Missing required offer field: ${check.field}`,
|
|
2025
|
+
{ payload }
|
|
2026
|
+
);
|
|
2027
|
+
}
|
|
2028
|
+
} else {
|
|
2029
|
+
const check = validateReceiptPayload2(payload);
|
|
2030
|
+
if (!check.valid) {
|
|
2031
|
+
return failure2(
|
|
2032
|
+
"INVALID_RECEIPT_PAYLOAD",
|
|
2033
|
+
`Missing required receipt field: ${check.field}`,
|
|
2034
|
+
{ payload }
|
|
2035
|
+
);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
const domain = artifactType === "offer" ? OFFER_DOMAIN : RECEIPT_DOMAIN;
|
|
2039
|
+
const types = artifactType === "offer" ? OFFER_TYPES : RECEIPT_TYPES;
|
|
2040
|
+
const message = artifactType === "offer" ? prepareOfferMessage(payload) : prepareReceiptMessage(payload);
|
|
2041
|
+
let signer;
|
|
2042
|
+
try {
|
|
2043
|
+
signer = ethers.verifyTypedData(
|
|
2044
|
+
domain,
|
|
2045
|
+
types,
|
|
2046
|
+
message,
|
|
2047
|
+
artifact.signature
|
|
2048
|
+
);
|
|
2049
|
+
signer = ethers.getAddress(signer);
|
|
2050
|
+
} catch (err) {
|
|
2051
|
+
const message2 = err instanceof Error ? err.message : "EIP-712 signature verification failed";
|
|
2052
|
+
return failure2("SIGNATURE_INVALID", message2, { payload });
|
|
2053
|
+
}
|
|
2054
|
+
return {
|
|
2055
|
+
valid: true,
|
|
2056
|
+
payload,
|
|
2057
|
+
signer,
|
|
2058
|
+
artifactType
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
function verifyX402Eip712Offer(artifact) {
|
|
2062
|
+
return verifyX402Eip712Artifact(artifact, "offer");
|
|
2063
|
+
}
|
|
2064
|
+
function verifyX402Eip712Receipt(artifact) {
|
|
2065
|
+
return verifyX402Eip712Artifact(artifact, "receipt");
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
// src/reputation/verify.ts
|
|
1270
2069
|
function parseChainId(input) {
|
|
1271
2070
|
if (typeof input === "number") {
|
|
1272
2071
|
return input;
|
|
@@ -1323,18 +2122,18 @@ function decodeJwtPayload(compactJws) {
|
|
|
1323
2122
|
return JSON.parse(json);
|
|
1324
2123
|
}
|
|
1325
2124
|
async function verifyProof(params) {
|
|
1326
|
-
const { proof, provider,
|
|
2125
|
+
const { proof, provider, expectedSubjectDid, expectedControllerDid } = params;
|
|
1327
2126
|
try {
|
|
1328
2127
|
switch (proof.proofType) {
|
|
1329
2128
|
case "tx-encoded-value": {
|
|
1330
2129
|
if (!provider) {
|
|
1331
2130
|
return { valid: false, proofType: proof.proofType, reason: "Provider is required" };
|
|
1332
2131
|
}
|
|
1333
|
-
if (!
|
|
2132
|
+
if (!expectedSubjectDid || !expectedControllerDid) {
|
|
1334
2133
|
return {
|
|
1335
2134
|
valid: false,
|
|
1336
2135
|
proofType: proof.proofType,
|
|
1337
|
-
reason: "
|
|
2136
|
+
reason: "expectedSubjectDid and expectedControllerDid are required"
|
|
1338
2137
|
};
|
|
1339
2138
|
}
|
|
1340
2139
|
const proofObject = proof.proofObject;
|
|
@@ -1346,13 +2145,13 @@ async function verifyProof(params) {
|
|
|
1346
2145
|
return { valid: false, proofType: proof.proofType, reason: "Transaction not found" };
|
|
1347
2146
|
}
|
|
1348
2147
|
const expectedAmount = calculateTransferAmount(
|
|
1349
|
-
|
|
1350
|
-
|
|
2148
|
+
expectedSubjectDid,
|
|
2149
|
+
expectedControllerDid,
|
|
1351
2150
|
chainId,
|
|
1352
2151
|
getProofPurpose(proof)
|
|
1353
2152
|
);
|
|
1354
|
-
const subjectAddress = ethers.getAddress(extractAddressFromDid(
|
|
1355
|
-
const controllerAddress = ethers.getAddress(extractAddressFromDid(
|
|
2153
|
+
const subjectAddress = ethers.getAddress(extractAddressFromDid(expectedSubjectDid));
|
|
2154
|
+
const controllerAddress = ethers.getAddress(extractAddressFromDid(expectedControllerDid));
|
|
1356
2155
|
if (tx.from && ethers.getAddress(tx.from) !== subjectAddress) {
|
|
1357
2156
|
return { valid: false, proofType: proof.proofType, reason: "Transaction sender mismatch" };
|
|
1358
2157
|
}
|
|
@@ -1426,6 +2225,38 @@ async function verifyProof(params) {
|
|
|
1426
2225
|
if (!proof.proofObject || typeof proof.proofObject !== "object") {
|
|
1427
2226
|
return { valid: false, proofType: proof.proofType, reason: "Invalid x402 proof object" };
|
|
1428
2227
|
}
|
|
2228
|
+
const proofObj = proof.proofObject;
|
|
2229
|
+
if (proofObj.format === "jws" && typeof proofObj.signature === "string") {
|
|
2230
|
+
const artifact = {
|
|
2231
|
+
format: "jws",
|
|
2232
|
+
signature: proofObj.signature
|
|
2233
|
+
};
|
|
2234
|
+
const jwsResult = proof.proofType === "x402-offer" ? await verifyX402JwsOffer(artifact) : await verifyX402JwsReceipt(artifact);
|
|
2235
|
+
if (!jwsResult.valid) {
|
|
2236
|
+
return {
|
|
2237
|
+
valid: false,
|
|
2238
|
+
proofType: proof.proofType,
|
|
2239
|
+
reason: jwsResult.error?.message ?? "JWS verification failed"
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
return { valid: true, proofType: proof.proofType };
|
|
2243
|
+
}
|
|
2244
|
+
if (proofObj.format === "eip712" && typeof proofObj.signature === "string" && proofObj.payload && typeof proofObj.payload === "object") {
|
|
2245
|
+
const artifact = {
|
|
2246
|
+
format: "eip712",
|
|
2247
|
+
payload: proofObj.payload,
|
|
2248
|
+
signature: proofObj.signature
|
|
2249
|
+
};
|
|
2250
|
+
const eip712Result = proof.proofType === "x402-offer" ? verifyX402Eip712Offer(artifact) : verifyX402Eip712Receipt(artifact);
|
|
2251
|
+
if (!eip712Result.valid) {
|
|
2252
|
+
return {
|
|
2253
|
+
valid: false,
|
|
2254
|
+
proofType: proof.proofType,
|
|
2255
|
+
reason: eip712Result.error?.message ?? "EIP-712 verification failed"
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
return { valid: true, proofType: proof.proofType };
|
|
2259
|
+
}
|
|
1429
2260
|
return { valid: true, proofType: proof.proofType };
|
|
1430
2261
|
}
|
|
1431
2262
|
case "evidence-pointer": {
|
|
@@ -1437,9 +2268,9 @@ async function verifyProof(params) {
|
|
|
1437
2268
|
if (!response.ok) {
|
|
1438
2269
|
return { valid: false, proofType: proof.proofType, reason: `Evidence fetch failed (${response.status})` };
|
|
1439
2270
|
}
|
|
1440
|
-
if (object.url.endsWith("/.well-known/did.json") &&
|
|
2271
|
+
if (object.url.endsWith("/.well-known/did.json") && expectedControllerDid) {
|
|
1441
2272
|
const didDoc = await response.json();
|
|
1442
|
-
const didCheck = verifyDidDocumentControllerDid(didDoc,
|
|
2273
|
+
const didCheck = verifyDidDocumentControllerDid(didDoc, expectedControllerDid);
|
|
1443
2274
|
return {
|
|
1444
2275
|
valid: didCheck.valid,
|
|
1445
2276
|
proofType: proof.proofType,
|
|
@@ -1447,10 +2278,10 @@ async function verifyProof(params) {
|
|
|
1447
2278
|
};
|
|
1448
2279
|
}
|
|
1449
2280
|
const body = await response.text();
|
|
1450
|
-
if (
|
|
2281
|
+
if (expectedControllerDid && !body.includes(expectedControllerDid)) {
|
|
1451
2282
|
try {
|
|
1452
2283
|
const parsed = parseDnsTxtRecord(body);
|
|
1453
|
-
if (parsed.
|
|
2284
|
+
if (!parsed.controllers.includes(expectedControllerDid)) {
|
|
1454
2285
|
return {
|
|
1455
2286
|
valid: false,
|
|
1456
2287
|
proofType: proof.proofType,
|
|
@@ -1506,8 +2337,8 @@ async function verifyAttestation(params) {
|
|
|
1506
2337
|
const result = await verifyProof({
|
|
1507
2338
|
proof,
|
|
1508
2339
|
provider: params.provider,
|
|
1509
|
-
|
|
1510
|
-
|
|
2340
|
+
expectedSubjectDid: params.context?.subjectDid,
|
|
2341
|
+
expectedControllerDid: params.context?.controllerDid
|
|
1511
2342
|
});
|
|
1512
2343
|
checks[proof.proofType] = result.valid;
|
|
1513
2344
|
if (!result.valid) {
|
|
@@ -1612,6 +2443,38 @@ async function callControllerWitness(params) {
|
|
|
1612
2443
|
method: "did-json"
|
|
1613
2444
|
};
|
|
1614
2445
|
}
|
|
2446
|
+
var DEFAULT_CONTROLLER_WITNESS_URL = "https://api.omatrust.org/v1/controller-witness";
|
|
2447
|
+
async function requestControllerWitness(params) {
|
|
2448
|
+
const url = params.gatewayUrl ?? DEFAULT_CONTROLLER_WITNESS_URL;
|
|
2449
|
+
const body = {
|
|
2450
|
+
subjectDid: params.subjectDid,
|
|
2451
|
+
controllerDid: params.controllerDid
|
|
2452
|
+
};
|
|
2453
|
+
if (params.chainId !== void 0) {
|
|
2454
|
+
body.chainId = params.chainId;
|
|
2455
|
+
}
|
|
2456
|
+
let response;
|
|
2457
|
+
try {
|
|
2458
|
+
response = await fetch(url, {
|
|
2459
|
+
method: "POST",
|
|
2460
|
+
headers: { "Content-Type": "application/json" },
|
|
2461
|
+
credentials: "include",
|
|
2462
|
+
body: JSON.stringify(body),
|
|
2463
|
+
signal: AbortSignal.timeout(params.timeoutMs ?? 15e3)
|
|
2464
|
+
});
|
|
2465
|
+
} catch (err) {
|
|
2466
|
+
throw new OmaTrustError("NETWORK_ERROR", "Controller witness request failed", { err });
|
|
2467
|
+
}
|
|
2468
|
+
if (!response.ok) {
|
|
2469
|
+
const errorBody = await response.json().catch(() => ({ error: response.statusText }));
|
|
2470
|
+
throw new OmaTrustError(
|
|
2471
|
+
"API_ERROR",
|
|
2472
|
+
errorBody.error ?? `Controller witness failed: ${response.status}`,
|
|
2473
|
+
{ status: response.status, ...errorBody }
|
|
2474
|
+
);
|
|
2475
|
+
}
|
|
2476
|
+
return await response.json();
|
|
2477
|
+
}
|
|
1615
2478
|
|
|
1616
2479
|
// src/reputation/proof/tx-interaction.ts
|
|
1617
2480
|
init_errors();
|
|
@@ -1758,29 +2621,20 @@ async function verifyDnsTxtControllerDid2(domain, expectedControllerDid, options
|
|
|
1758
2621
|
);
|
|
1759
2622
|
}
|
|
1760
2623
|
|
|
1761
|
-
// src/reputation/
|
|
2624
|
+
// src/reputation/subject-ownership.ts
|
|
1762
2625
|
init_did();
|
|
1763
2626
|
init_errors();
|
|
1764
2627
|
init_dns_txt_shared();
|
|
2628
|
+
|
|
2629
|
+
// src/reputation/contract-ownership.ts
|
|
2630
|
+
init_did();
|
|
1765
2631
|
var EIP1967_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103";
|
|
1766
2632
|
var OWNERSHIP_PATTERNS = [
|
|
1767
2633
|
{ method: "owner", signature: "function owner() view returns (address)" },
|
|
1768
2634
|
{ method: "admin", signature: "function admin() view returns (address)" },
|
|
1769
2635
|
{ method: "getOwner", signature: "function getOwner() view returns (address)" }
|
|
1770
2636
|
];
|
|
1771
|
-
function
|
|
1772
|
-
const normalized = normalizeDid(input);
|
|
1773
|
-
if (extractDidMethod(normalized) !== "pkh") {
|
|
1774
|
-
throw new OmaTrustError("INVALID_INPUT", "connectedWalletDid must be a did:pkh DID", {
|
|
1775
|
-
connectedWalletDid: input
|
|
1776
|
-
});
|
|
1777
|
-
}
|
|
1778
|
-
return normalized;
|
|
1779
|
-
}
|
|
1780
|
-
function normalizeSubjectDid(input) {
|
|
1781
|
-
return normalizeDid(input);
|
|
1782
|
-
}
|
|
1783
|
-
async function readAddressFromContract(provider, contractAddress, signature, method) {
|
|
2637
|
+
async function readOwnerFromContract(provider, contractAddress, signature, method) {
|
|
1784
2638
|
try {
|
|
1785
2639
|
const iface = new ethers.Interface([signature]);
|
|
1786
2640
|
const data = iface.encodeFunctionData(method, []);
|
|
@@ -1793,16 +2647,24 @@ async function readAddressFromContract(provider, contractAddress, signature, met
|
|
|
1793
2647
|
}
|
|
1794
2648
|
return null;
|
|
1795
2649
|
}
|
|
1796
|
-
async function
|
|
2650
|
+
async function discoverContractOwner(provider, contractAddress) {
|
|
2651
|
+
try {
|
|
2652
|
+
const code = await provider.getCode(contractAddress);
|
|
2653
|
+
if (code === "0x" || code === "0x0") {
|
|
2654
|
+
return null;
|
|
2655
|
+
}
|
|
2656
|
+
} catch {
|
|
2657
|
+
return null;
|
|
2658
|
+
}
|
|
1797
2659
|
for (const pattern of OWNERSHIP_PATTERNS) {
|
|
1798
|
-
const address = await
|
|
2660
|
+
const address = await readOwnerFromContract(
|
|
1799
2661
|
provider,
|
|
1800
2662
|
contractAddress,
|
|
1801
2663
|
pattern.signature,
|
|
1802
2664
|
pattern.method
|
|
1803
2665
|
);
|
|
1804
2666
|
if (address) {
|
|
1805
|
-
return
|
|
2667
|
+
return address;
|
|
1806
2668
|
}
|
|
1807
2669
|
}
|
|
1808
2670
|
try {
|
|
@@ -1810,13 +2672,31 @@ async function discoverControllingWallet(provider, contractAddress, chainId) {
|
|
|
1810
2672
|
if (adminValue && adminValue !== "0x" && adminValue !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
|
|
1811
2673
|
const adminAddress = ethers.getAddress(`0x${adminValue.slice(-40)}`);
|
|
1812
2674
|
if (adminAddress !== ethers.ZeroAddress) {
|
|
1813
|
-
return
|
|
2675
|
+
return adminAddress;
|
|
1814
2676
|
}
|
|
1815
2677
|
}
|
|
1816
2678
|
} catch {
|
|
1817
2679
|
}
|
|
1818
2680
|
return null;
|
|
1819
2681
|
}
|
|
2682
|
+
async function discoverControllingWalletDid(provider, contractAddress, chainId) {
|
|
2683
|
+
const owner = await discoverContractOwner(provider, contractAddress);
|
|
2684
|
+
return owner ? buildEvmDidPkh(chainId, owner) : null;
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2687
|
+
// src/reputation/subject-ownership.ts
|
|
2688
|
+
function assertConnectedWalletDid(input) {
|
|
2689
|
+
const normalized = normalizeDid(input);
|
|
2690
|
+
if (extractDidMethod(normalized) !== "pkh") {
|
|
2691
|
+
throw new OmaTrustError("INVALID_INPUT", "connectedWalletDid must be a did:pkh DID", {
|
|
2692
|
+
connectedWalletDid: input
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
return normalized;
|
|
2696
|
+
}
|
|
2697
|
+
function normalizeSubjectDid(input) {
|
|
2698
|
+
return normalizeDid(input);
|
|
2699
|
+
}
|
|
1820
2700
|
async function verifyDidWebOwnership(params) {
|
|
1821
2701
|
const subjectDid = normalizeSubjectDid(params.subjectDid);
|
|
1822
2702
|
const connectedWalletDid = assertConnectedWalletDid(params.connectedWalletDid);
|
|
@@ -1914,7 +2794,7 @@ async function verifyDidPkhOwnership(params) {
|
|
|
1914
2794
|
connectedWalletDid
|
|
1915
2795
|
};
|
|
1916
2796
|
}
|
|
1917
|
-
const controllingWalletDid = await
|
|
2797
|
+
const controllingWalletDid = await discoverControllingWalletDid(params.provider, subjectAddress, chainId);
|
|
1918
2798
|
if (params.txHash) {
|
|
1919
2799
|
if (!controllingWalletDid) {
|
|
1920
2800
|
return {
|
|
@@ -1997,7 +2877,7 @@ async function verifyDidPkhOwnership(params) {
|
|
|
1997
2877
|
};
|
|
1998
2878
|
}
|
|
1999
2879
|
for (const pattern of OWNERSHIP_PATTERNS) {
|
|
2000
|
-
const ownerAddress = await
|
|
2880
|
+
const ownerAddress = await readOwnerFromContract(
|
|
2001
2881
|
params.provider,
|
|
2002
2882
|
subjectAddress,
|
|
2003
2883
|
pattern.signature,
|
|
@@ -2091,8 +2971,9 @@ exports.createX402ReceiptProof = createX402ReceiptProof;
|
|
|
2091
2971
|
exports.decodeAttestationData = decodeAttestationData;
|
|
2092
2972
|
exports.deduplicateReviews = deduplicateReviews;
|
|
2093
2973
|
exports.encodeAttestationData = encodeAttestationData;
|
|
2094
|
-
exports.
|
|
2974
|
+
exports.extractEvmAddressesFromDidDocument = extractEvmAddressesFromDidDocument;
|
|
2095
2975
|
exports.extractExpirationTime = extractExpirationTime;
|
|
2976
|
+
exports.extractJwksFromDidDocument = extractJwksFromDidDocument;
|
|
2096
2977
|
exports.fetchDidDocument = fetchDidDocument;
|
|
2097
2978
|
exports.formatSchemaUid = formatSchemaUid;
|
|
2098
2979
|
exports.formatTransferAmount = formatTransferAmount;
|
|
@@ -2113,6 +2994,7 @@ exports.listAttestations = listAttestations;
|
|
|
2113
2994
|
exports.normalizeSchema = normalizeSchema;
|
|
2114
2995
|
exports.parseDnsTxtRecord = parseDnsTxtRecord;
|
|
2115
2996
|
exports.prepareDelegatedAttestation = prepareDelegatedAttestation;
|
|
2997
|
+
exports.requestControllerWitness = requestControllerWitness;
|
|
2116
2998
|
exports.revokeAttestation = revokeAttestation;
|
|
2117
2999
|
exports.schemaToString = schemaToString;
|
|
2118
3000
|
exports.splitSignature = splitSignature;
|