@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
|
@@ -5,10 +5,33 @@ var ethers = require('ethers');
|
|
|
5
5
|
var jose = require('jose');
|
|
6
6
|
var canonicalize = require('canonicalize');
|
|
7
7
|
var promises = require('dns/promises');
|
|
8
|
+
var cid = require('multiformats/cid');
|
|
9
|
+
require('multiformats/hashes/sha2');
|
|
10
|
+
var raw = require('multiformats/codecs/raw');
|
|
11
|
+
var base32 = require('multiformats/bases/base32');
|
|
8
12
|
|
|
9
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
14
|
|
|
15
|
+
function _interopNamespace(e) {
|
|
16
|
+
if (e && e.__esModule) return e;
|
|
17
|
+
var n = Object.create(null);
|
|
18
|
+
if (e) {
|
|
19
|
+
Object.keys(e).forEach(function (k) {
|
|
20
|
+
if (k !== 'default') {
|
|
21
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
22
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () { return e[k]; }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
n.default = e;
|
|
30
|
+
return Object.freeze(n);
|
|
31
|
+
}
|
|
32
|
+
|
|
11
33
|
var canonicalize__default = /*#__PURE__*/_interopDefault(canonicalize);
|
|
34
|
+
var raw__namespace = /*#__PURE__*/_interopNamespace(raw);
|
|
12
35
|
|
|
13
36
|
// src/reputation/submit.ts
|
|
14
37
|
|
|
@@ -16,10 +39,10 @@ var canonicalize__default = /*#__PURE__*/_interopDefault(canonicalize);
|
|
|
16
39
|
var OmaTrustError = class extends Error {
|
|
17
40
|
code;
|
|
18
41
|
details;
|
|
19
|
-
constructor(
|
|
42
|
+
constructor(code2, message, details) {
|
|
20
43
|
super(message);
|
|
21
44
|
this.name = "OmaTrustError";
|
|
22
|
-
this.code =
|
|
45
|
+
this.code = code2;
|
|
23
46
|
this.details = details;
|
|
24
47
|
}
|
|
25
48
|
};
|
|
@@ -200,14 +223,14 @@ function extractExpirationTime(data) {
|
|
|
200
223
|
}
|
|
201
224
|
|
|
202
225
|
// src/shared/assert.ts
|
|
203
|
-
function assertString(value, name,
|
|
226
|
+
function assertString(value, name, code2 = "INVALID_INPUT") {
|
|
204
227
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
205
|
-
throw new OmaTrustError(
|
|
228
|
+
throw new OmaTrustError(code2, `${name} must be a non-empty string`, { value });
|
|
206
229
|
}
|
|
207
230
|
}
|
|
208
|
-
function assertObject(value, name,
|
|
231
|
+
function assertObject(value, name, code2 = "INVALID_INPUT") {
|
|
209
232
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
210
|
-
throw new OmaTrustError(
|
|
233
|
+
throw new OmaTrustError(code2, `${name} must be an object`, { value });
|
|
211
234
|
}
|
|
212
235
|
}
|
|
213
236
|
|
|
@@ -228,6 +251,145 @@ function parseCaip10(input) {
|
|
|
228
251
|
}
|
|
229
252
|
return { namespace, reference, address };
|
|
230
253
|
}
|
|
254
|
+
var VALID_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
|
|
255
|
+
var PRIVATE_KEY_FIELDS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
|
|
256
|
+
var REQUIRED_PUBLIC_FIELDS = {
|
|
257
|
+
EC: ["crv", "x", "y"],
|
|
258
|
+
OKP: ["crv", "x"],
|
|
259
|
+
RSA: ["n", "e"]
|
|
260
|
+
};
|
|
261
|
+
function validatePublicJwk(jwk) {
|
|
262
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
263
|
+
return { valid: false, error: "JWK must be a non-null object" };
|
|
264
|
+
}
|
|
265
|
+
const obj = jwk;
|
|
266
|
+
const kty = obj.kty;
|
|
267
|
+
if (typeof kty !== "string" || !VALID_KTY.has(kty)) {
|
|
268
|
+
return {
|
|
269
|
+
valid: false,
|
|
270
|
+
error: `Invalid or missing kty (must be one of: ${[...VALID_KTY].join(", ")})`
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
for (const field of PRIVATE_KEY_FIELDS) {
|
|
274
|
+
if (field in obj) {
|
|
275
|
+
return {
|
|
276
|
+
valid: false,
|
|
277
|
+
error: `JWK contains private key field "${field}" \u2014 only public keys are allowed`
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
const required = REQUIRED_PUBLIC_FIELDS[kty];
|
|
282
|
+
if (required) {
|
|
283
|
+
for (const field of required) {
|
|
284
|
+
if (!(field in obj) || obj[field] === void 0 || obj[field] === null || obj[field] === "") {
|
|
285
|
+
return {
|
|
286
|
+
valid: false,
|
|
287
|
+
error: `Missing required public key field "${field}" for kty="${kty}"`
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return { valid: true };
|
|
293
|
+
}
|
|
294
|
+
function canonicalizeJwkJson(jwk) {
|
|
295
|
+
const sorted = Object.keys(jwk).sort();
|
|
296
|
+
const obj = {};
|
|
297
|
+
for (const key of sorted) {
|
|
298
|
+
obj[key] = jwk[key];
|
|
299
|
+
}
|
|
300
|
+
return JSON.stringify(obj);
|
|
301
|
+
}
|
|
302
|
+
function jwkToDidJwk(jwk) {
|
|
303
|
+
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
304
|
+
const validation = validatePublicJwk(jwk);
|
|
305
|
+
if (!validation.valid) {
|
|
306
|
+
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
307
|
+
}
|
|
308
|
+
const canonical = canonicalizeJwkJson(jwk);
|
|
309
|
+
const encoded = jose.base64url.encode(new TextEncoder().encode(canonical));
|
|
310
|
+
return `did:jwk:${encoded}`;
|
|
311
|
+
}
|
|
312
|
+
function didJwkToJwk(didJwk) {
|
|
313
|
+
if (typeof didJwk !== "string" || !didJwk.startsWith("did:jwk:")) {
|
|
314
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:jwk DID", { input: didJwk });
|
|
315
|
+
}
|
|
316
|
+
const parts = didJwk.split(":");
|
|
317
|
+
if (parts.length !== 3) {
|
|
318
|
+
throw new OmaTrustError("INVALID_DID", "did:jwk must have exactly 3 colon-separated parts", {
|
|
319
|
+
input: didJwk
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
const encoded = parts[2];
|
|
323
|
+
if (!encoded || encoded.length === 0) {
|
|
324
|
+
throw new OmaTrustError("INVALID_DID", "Missing base64url-encoded JWK identifier", {
|
|
325
|
+
input: didJwk
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
let decoded;
|
|
329
|
+
try {
|
|
330
|
+
const bytes = jose.base64url.decode(encoded);
|
|
331
|
+
decoded = new TextDecoder().decode(bytes);
|
|
332
|
+
} catch {
|
|
333
|
+
throw new OmaTrustError("INVALID_DID", "Failed to base64url-decode did:jwk identifier", {
|
|
334
|
+
input: didJwk
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
let jwk;
|
|
338
|
+
try {
|
|
339
|
+
jwk = JSON.parse(decoded);
|
|
340
|
+
} catch {
|
|
341
|
+
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk identifier is not valid JSON", {
|
|
342
|
+
input: didJwk
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
346
|
+
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk must be a JSON object", {
|
|
347
|
+
input: didJwk
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
const validation = validatePublicJwk(jwk);
|
|
351
|
+
if (!validation.valid) {
|
|
352
|
+
throw new OmaTrustError("INVALID_DID", validation.error ?? "Invalid public JWK in did:jwk", {
|
|
353
|
+
input: didJwk
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return jwk;
|
|
357
|
+
}
|
|
358
|
+
function extractPublicKeyFields(jwk) {
|
|
359
|
+
const result = {};
|
|
360
|
+
const metadataFields = /* @__PURE__ */ new Set(["kid", "use", "key_ops", "alg", "ext"]);
|
|
361
|
+
for (const [key, value] of Object.entries(jwk)) {
|
|
362
|
+
if (PRIVATE_KEY_FIELDS.has(key)) continue;
|
|
363
|
+
if (metadataFields.has(key)) continue;
|
|
364
|
+
result[key] = value;
|
|
365
|
+
}
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
function publicJwkEquals(a, b) {
|
|
369
|
+
assertObject(a, "a", "INVALID_JWK");
|
|
370
|
+
assertObject(b, "b", "INVALID_JWK");
|
|
371
|
+
const aObj = a;
|
|
372
|
+
const bObj = b;
|
|
373
|
+
for (const field of PRIVATE_KEY_FIELDS) {
|
|
374
|
+
if (field in aObj) {
|
|
375
|
+
throw new OmaTrustError(
|
|
376
|
+
"INVALID_JWK",
|
|
377
|
+
`First JWK contains private key field "${field}"`,
|
|
378
|
+
{ field }
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
if (field in bObj) {
|
|
382
|
+
throw new OmaTrustError(
|
|
383
|
+
"INVALID_JWK",
|
|
384
|
+
`Second JWK contains private key field "${field}"`,
|
|
385
|
+
{ field }
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const aPublic = extractPublicKeyFields(aObj);
|
|
390
|
+
const bPublic = extractPublicKeyFields(bObj);
|
|
391
|
+
return canonicalizeJwkJson(aPublic) === canonicalizeJwkJson(bPublic);
|
|
392
|
+
}
|
|
231
393
|
|
|
232
394
|
// src/identity/did.ts
|
|
233
395
|
var DID_REGEX = /^did:[a-z0-9]+:.+$/i;
|
|
@@ -299,7 +461,7 @@ function normalizeDidKey(input) {
|
|
|
299
461
|
}
|
|
300
462
|
function normalizeDid(input) {
|
|
301
463
|
assertString(input, "input", "INVALID_DID");
|
|
302
|
-
const trimmed = input.trim();
|
|
464
|
+
const trimmed = input.trim().split("#")[0];
|
|
303
465
|
if (!trimmed.startsWith("did:")) {
|
|
304
466
|
return normalizeDidWeb(trimmed);
|
|
305
467
|
}
|
|
@@ -460,6 +622,10 @@ function validateDidJwk(did) {
|
|
|
460
622
|
error: "DID must reference a public key \u2014 private key component (d) is not allowed"
|
|
461
623
|
};
|
|
462
624
|
}
|
|
625
|
+
const jwkValidation = validatePublicJwk(jwk);
|
|
626
|
+
if (!jwkValidation.valid) {
|
|
627
|
+
return { valid: false, method: "jwk", error: jwkValidation.error };
|
|
628
|
+
}
|
|
463
629
|
return { valid: true, method: "jwk" };
|
|
464
630
|
}
|
|
465
631
|
function normalizeDidJwk(input) {
|
|
@@ -1118,154 +1284,15 @@ function createTxEncodedValueProof(chainId, txHash, purpose) {
|
|
|
1118
1284
|
};
|
|
1119
1285
|
}
|
|
1120
1286
|
function formatTransferAmount(amount, chainId) {
|
|
1121
|
-
const config = getConfig(chainId);
|
|
1122
|
-
const normalized = typeof amount === "number" ? BigInt(Math.floor(amount)) : amount;
|
|
1123
|
-
return `${ethers.formatUnits(normalized, config.decimals)} ${config.nativeSymbol}`;
|
|
1124
|
-
}
|
|
1125
|
-
function getExplorerTxUrl(chainId, txHash) {
|
|
1126
|
-
return `${getConfig(chainId).explorer}/tx/${txHash}`;
|
|
1127
|
-
}
|
|
1128
|
-
function getExplorerAddressUrl(chainId, address) {
|
|
1129
|
-
return `${getConfig(chainId).explorer}/address/${address}`;
|
|
1130
|
-
}
|
|
1131
|
-
var VALID_KTY = /* @__PURE__ */ new Set(["EC", "OKP", "RSA"]);
|
|
1132
|
-
var PRIVATE_KEY_FIELDS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
|
|
1133
|
-
var REQUIRED_PUBLIC_FIELDS = {
|
|
1134
|
-
EC: ["crv", "x", "y"],
|
|
1135
|
-
OKP: ["crv", "x"],
|
|
1136
|
-
RSA: ["n", "e"]
|
|
1137
|
-
};
|
|
1138
|
-
function validatePublicJwk(jwk) {
|
|
1139
|
-
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
1140
|
-
return { valid: false, error: "JWK must be a non-null object" };
|
|
1141
|
-
}
|
|
1142
|
-
const obj = jwk;
|
|
1143
|
-
const kty = obj.kty;
|
|
1144
|
-
if (typeof kty !== "string" || !VALID_KTY.has(kty)) {
|
|
1145
|
-
return {
|
|
1146
|
-
valid: false,
|
|
1147
|
-
error: `Invalid or missing kty (must be one of: ${[...VALID_KTY].join(", ")})`
|
|
1148
|
-
};
|
|
1149
|
-
}
|
|
1150
|
-
for (const field of PRIVATE_KEY_FIELDS) {
|
|
1151
|
-
if (field in obj) {
|
|
1152
|
-
return {
|
|
1153
|
-
valid: false,
|
|
1154
|
-
error: `JWK contains private key field "${field}" \u2014 only public keys are allowed`
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
const required = REQUIRED_PUBLIC_FIELDS[kty];
|
|
1159
|
-
if (required) {
|
|
1160
|
-
for (const field of required) {
|
|
1161
|
-
if (!(field in obj) || obj[field] === void 0 || obj[field] === null || obj[field] === "") {
|
|
1162
|
-
return {
|
|
1163
|
-
valid: false,
|
|
1164
|
-
error: `Missing required public key field "${field}" for kty="${kty}"`
|
|
1165
|
-
};
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
return { valid: true };
|
|
1170
|
-
}
|
|
1171
|
-
function canonicalizeJwkJson(jwk) {
|
|
1172
|
-
const sorted = Object.keys(jwk).sort();
|
|
1173
|
-
const obj = {};
|
|
1174
|
-
for (const key of sorted) {
|
|
1175
|
-
obj[key] = jwk[key];
|
|
1176
|
-
}
|
|
1177
|
-
return JSON.stringify(obj);
|
|
1178
|
-
}
|
|
1179
|
-
function jwkToDidJwk(jwk) {
|
|
1180
|
-
assertObject(jwk, "jwk", "INVALID_JWK");
|
|
1181
|
-
const validation = validatePublicJwk(jwk);
|
|
1182
|
-
if (!validation.valid) {
|
|
1183
|
-
throw new OmaTrustError("INVALID_JWK", validation.error ?? "Invalid public JWK", { jwk });
|
|
1184
|
-
}
|
|
1185
|
-
const canonical = canonicalizeJwkJson(jwk);
|
|
1186
|
-
const encoded = jose.base64url.encode(new TextEncoder().encode(canonical));
|
|
1187
|
-
return `did:jwk:${encoded}`;
|
|
1188
|
-
}
|
|
1189
|
-
function didJwkToJwk(didJwk) {
|
|
1190
|
-
if (typeof didJwk !== "string" || !didJwk.startsWith("did:jwk:")) {
|
|
1191
|
-
throw new OmaTrustError("INVALID_DID", "Expected a did:jwk DID", { input: didJwk });
|
|
1192
|
-
}
|
|
1193
|
-
const parts = didJwk.split(":");
|
|
1194
|
-
if (parts.length !== 3) {
|
|
1195
|
-
throw new OmaTrustError("INVALID_DID", "did:jwk must have exactly 3 colon-separated parts", {
|
|
1196
|
-
input: didJwk
|
|
1197
|
-
});
|
|
1198
|
-
}
|
|
1199
|
-
const encoded = parts[2];
|
|
1200
|
-
if (!encoded || encoded.length === 0) {
|
|
1201
|
-
throw new OmaTrustError("INVALID_DID", "Missing base64url-encoded JWK identifier", {
|
|
1202
|
-
input: didJwk
|
|
1203
|
-
});
|
|
1204
|
-
}
|
|
1205
|
-
let decoded;
|
|
1206
|
-
try {
|
|
1207
|
-
const bytes = jose.base64url.decode(encoded);
|
|
1208
|
-
decoded = new TextDecoder().decode(bytes);
|
|
1209
|
-
} catch {
|
|
1210
|
-
throw new OmaTrustError("INVALID_DID", "Failed to base64url-decode did:jwk identifier", {
|
|
1211
|
-
input: didJwk
|
|
1212
|
-
});
|
|
1213
|
-
}
|
|
1214
|
-
let jwk;
|
|
1215
|
-
try {
|
|
1216
|
-
jwk = JSON.parse(decoded);
|
|
1217
|
-
} catch {
|
|
1218
|
-
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk identifier is not valid JSON", {
|
|
1219
|
-
input: didJwk
|
|
1220
|
-
});
|
|
1221
|
-
}
|
|
1222
|
-
if (!jwk || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
1223
|
-
throw new OmaTrustError("INVALID_DID", "Decoded did:jwk must be a JSON object", {
|
|
1224
|
-
input: didJwk
|
|
1225
|
-
});
|
|
1226
|
-
}
|
|
1227
|
-
const validation = validatePublicJwk(jwk);
|
|
1228
|
-
if (!validation.valid) {
|
|
1229
|
-
throw new OmaTrustError("INVALID_DID", validation.error ?? "Invalid public JWK in did:jwk", {
|
|
1230
|
-
input: didJwk
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
return jwk;
|
|
1234
|
-
}
|
|
1235
|
-
function extractPublicKeyFields(jwk) {
|
|
1236
|
-
const result = {};
|
|
1237
|
-
const metadataFields = /* @__PURE__ */ new Set(["kid", "use", "key_ops", "alg", "ext"]);
|
|
1238
|
-
for (const [key, value] of Object.entries(jwk)) {
|
|
1239
|
-
if (PRIVATE_KEY_FIELDS.has(key)) continue;
|
|
1240
|
-
if (metadataFields.has(key)) continue;
|
|
1241
|
-
result[key] = value;
|
|
1242
|
-
}
|
|
1243
|
-
return result;
|
|
1244
|
-
}
|
|
1245
|
-
function publicJwkEquals(a, b) {
|
|
1246
|
-
assertObject(a, "a", "INVALID_JWK");
|
|
1247
|
-
assertObject(b, "b", "INVALID_JWK");
|
|
1248
|
-
const aObj = a;
|
|
1249
|
-
const bObj = b;
|
|
1250
|
-
for (const field of PRIVATE_KEY_FIELDS) {
|
|
1251
|
-
if (field in aObj) {
|
|
1252
|
-
throw new OmaTrustError(
|
|
1253
|
-
"INVALID_JWK",
|
|
1254
|
-
`First JWK contains private key field "${field}"`,
|
|
1255
|
-
{ field }
|
|
1256
|
-
);
|
|
1257
|
-
}
|
|
1258
|
-
if (field in bObj) {
|
|
1259
|
-
throw new OmaTrustError(
|
|
1260
|
-
"INVALID_JWK",
|
|
1261
|
-
`Second JWK contains private key field "${field}"`,
|
|
1262
|
-
{ field }
|
|
1263
|
-
);
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
const aPublic = extractPublicKeyFields(aObj);
|
|
1267
|
-
const bPublic = extractPublicKeyFields(bObj);
|
|
1268
|
-
return canonicalizeJwkJson(aPublic) === canonicalizeJwkJson(bPublic);
|
|
1287
|
+
const config = getConfig(chainId);
|
|
1288
|
+
const normalized = typeof amount === "number" ? BigInt(Math.floor(amount)) : amount;
|
|
1289
|
+
return `${ethers.formatUnits(normalized, config.decimals)} ${config.nativeSymbol}`;
|
|
1290
|
+
}
|
|
1291
|
+
function getExplorerTxUrl(chainId, txHash) {
|
|
1292
|
+
return `${getConfig(chainId).explorer}/tx/${txHash}`;
|
|
1293
|
+
}
|
|
1294
|
+
function getExplorerAddressUrl(chainId, address) {
|
|
1295
|
+
return `${getConfig(chainId).explorer}/address/${address}`;
|
|
1269
1296
|
}
|
|
1270
1297
|
|
|
1271
1298
|
// src/shared/did-document.ts
|
|
@@ -1593,10 +1620,10 @@ function validateReceiptPayload(payload) {
|
|
|
1593
1620
|
}
|
|
1594
1621
|
return { valid: true };
|
|
1595
1622
|
}
|
|
1596
|
-
function failure(
|
|
1623
|
+
function failure(code2, message, partial) {
|
|
1597
1624
|
return {
|
|
1598
1625
|
valid: false,
|
|
1599
|
-
error: { code, message },
|
|
1626
|
+
error: { code: code2, message },
|
|
1600
1627
|
...partial
|
|
1601
1628
|
};
|
|
1602
1629
|
}
|
|
@@ -1794,10 +1821,10 @@ function validateReceiptPayload2(payload) {
|
|
|
1794
1821
|
}
|
|
1795
1822
|
return { valid: true };
|
|
1796
1823
|
}
|
|
1797
|
-
function failure2(
|
|
1824
|
+
function failure2(code2, message, partial) {
|
|
1798
1825
|
return {
|
|
1799
1826
|
valid: false,
|
|
1800
|
-
error: { code, message },
|
|
1827
|
+
error: { code: code2, message },
|
|
1801
1828
|
...partial
|
|
1802
1829
|
};
|
|
1803
1830
|
}
|
|
@@ -2315,8 +2342,8 @@ async function readOwnerFromContract(provider, contractAddress, signature, metho
|
|
|
2315
2342
|
}
|
|
2316
2343
|
async function discoverContractOwner(provider, contractAddress) {
|
|
2317
2344
|
try {
|
|
2318
|
-
const
|
|
2319
|
-
if (
|
|
2345
|
+
const code2 = await provider.getCode(contractAddress);
|
|
2346
|
+
if (code2 === "0x" || code2 === "0x0") {
|
|
2320
2347
|
return null;
|
|
2321
2348
|
}
|
|
2322
2349
|
} catch {
|
|
@@ -2868,6 +2895,42 @@ function createX402OfferProof(offer) {
|
|
|
2868
2895
|
};
|
|
2869
2896
|
}
|
|
2870
2897
|
|
|
2898
|
+
// src/reputation/proof/x402-verify.ts
|
|
2899
|
+
async function verifyX402Artifact(artifact, options) {
|
|
2900
|
+
if (!artifact || typeof artifact !== "object") {
|
|
2901
|
+
return {
|
|
2902
|
+
valid: false,
|
|
2903
|
+
error: { code: "INVALID_ARTIFACT", message: "Artifact must be a non-null object" }
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
const format = artifact.format;
|
|
2907
|
+
switch (format) {
|
|
2908
|
+
case "jws": {
|
|
2909
|
+
const jwsArtifact = artifact;
|
|
2910
|
+
const jwsOptions = options.resolveOptions ? { resolveOptions: options.resolveOptions } : void 0;
|
|
2911
|
+
if (options.artifactType === "offer") {
|
|
2912
|
+
return verifyX402JwsOffer(jwsArtifact, jwsOptions);
|
|
2913
|
+
}
|
|
2914
|
+
return verifyX402JwsReceipt(jwsArtifact, jwsOptions);
|
|
2915
|
+
}
|
|
2916
|
+
case "eip712": {
|
|
2917
|
+
const eip712Artifact = artifact;
|
|
2918
|
+
if (options.artifactType === "offer") {
|
|
2919
|
+
return verifyX402Eip712Offer(eip712Artifact);
|
|
2920
|
+
}
|
|
2921
|
+
return verifyX402Eip712Receipt(eip712Artifact);
|
|
2922
|
+
}
|
|
2923
|
+
default:
|
|
2924
|
+
return {
|
|
2925
|
+
valid: false,
|
|
2926
|
+
error: {
|
|
2927
|
+
code: "UNSUPPORTED_FORMAT",
|
|
2928
|
+
message: `Unsupported x402 artifact format: "${format}"`
|
|
2929
|
+
}
|
|
2930
|
+
};
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2871
2934
|
// src/reputation/proof/evidence-pointer.ts
|
|
2872
2935
|
function createEvidencePointerProof(url) {
|
|
2873
2936
|
if (!url || typeof url !== "string") {
|
|
@@ -2976,8 +3039,8 @@ async function verifyDidPkhOwnership(params) {
|
|
|
2976
3039
|
subjectDid: params.subjectDid
|
|
2977
3040
|
});
|
|
2978
3041
|
}
|
|
2979
|
-
const
|
|
2980
|
-
const isContract =
|
|
3042
|
+
const code2 = await params.provider.getCode(subjectAddress);
|
|
3043
|
+
const isContract = code2 !== "0x" && code2 !== "0x0";
|
|
2981
3044
|
if (!isContract) {
|
|
2982
3045
|
if (ethers.getAddress(subjectAddress) === ethers.getAddress(connectedWalletAddress)) {
|
|
2983
3046
|
return {
|
|
@@ -3153,6 +3216,658 @@ async function verifySubjectOwnership(params) {
|
|
|
3153
3216
|
subjectDid
|
|
3154
3217
|
});
|
|
3155
3218
|
}
|
|
3219
|
+
function extractEip712Signer(proof) {
|
|
3220
|
+
const { domain, message, signature } = proof.proofObject;
|
|
3221
|
+
const typedData = {
|
|
3222
|
+
domain,
|
|
3223
|
+
types: {
|
|
3224
|
+
OmaTrustProof: [
|
|
3225
|
+
{ name: "signer", type: "address" },
|
|
3226
|
+
{ name: "authorizedEntity", type: "string" },
|
|
3227
|
+
{ name: "signingPurpose", type: "string" },
|
|
3228
|
+
{ name: "creationTimestamp", type: "uint256" },
|
|
3229
|
+
{ name: "expirationTimestamp", type: "uint256" },
|
|
3230
|
+
{ name: "randomValue", type: "bytes32" },
|
|
3231
|
+
{ name: "statement", type: "string" }
|
|
3232
|
+
]
|
|
3233
|
+
},
|
|
3234
|
+
message
|
|
3235
|
+
};
|
|
3236
|
+
try {
|
|
3237
|
+
const result = verifyEip712Signature(typedData, signature);
|
|
3238
|
+
return result.valid && result.signer ? result.signer : null;
|
|
3239
|
+
} catch (err) {
|
|
3240
|
+
console.warn("[omatrust] EIP-712 signer extraction failed:", err);
|
|
3241
|
+
return null;
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
function extractJwsHeaderJwk(proof) {
|
|
3245
|
+
const jws = proof.proofObject;
|
|
3246
|
+
if (typeof jws !== "string") return null;
|
|
3247
|
+
const parts = jws.split(".");
|
|
3248
|
+
if (parts.length !== 3) return null;
|
|
3249
|
+
try {
|
|
3250
|
+
const headerB64 = parts[0].replace(/-/g, "+").replace(/_/g, "/");
|
|
3251
|
+
const padded = headerB64.padEnd(
|
|
3252
|
+
headerB64.length + (4 - headerB64.length % 4) % 4,
|
|
3253
|
+
"="
|
|
3254
|
+
);
|
|
3255
|
+
let headerJson;
|
|
3256
|
+
if (typeof atob === "function") {
|
|
3257
|
+
headerJson = decodeURIComponent(
|
|
3258
|
+
Array.from(atob(padded)).map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
|
|
3259
|
+
);
|
|
3260
|
+
} else {
|
|
3261
|
+
headerJson = Buffer.from(padded, "base64").toString("utf8");
|
|
3262
|
+
}
|
|
3263
|
+
const header = JSON.parse(headerJson);
|
|
3264
|
+
return header.jwk ?? null;
|
|
3265
|
+
} catch {
|
|
3266
|
+
return null;
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
function extractJwsPayload(proof) {
|
|
3270
|
+
const jws = proof.proofObject;
|
|
3271
|
+
if (typeof jws !== "string") return null;
|
|
3272
|
+
const parts = jws.split(".");
|
|
3273
|
+
if (parts.length !== 3) return null;
|
|
3274
|
+
try {
|
|
3275
|
+
const payloadB64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
3276
|
+
const padded = payloadB64.padEnd(
|
|
3277
|
+
payloadB64.length + (4 - payloadB64.length % 4) % 4,
|
|
3278
|
+
"="
|
|
3279
|
+
);
|
|
3280
|
+
let payloadJson;
|
|
3281
|
+
if (typeof atob === "function") {
|
|
3282
|
+
payloadJson = decodeURIComponent(
|
|
3283
|
+
Array.from(atob(padded)).map((char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`).join("")
|
|
3284
|
+
);
|
|
3285
|
+
} else {
|
|
3286
|
+
payloadJson = Buffer.from(padded, "base64").toString("utf8");
|
|
3287
|
+
}
|
|
3288
|
+
return JSON.parse(payloadJson);
|
|
3289
|
+
} catch {
|
|
3290
|
+
return null;
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
function signerMatchesDid(signerAddress, did) {
|
|
3294
|
+
try {
|
|
3295
|
+
const didAddress = extractAddressFromDid(did);
|
|
3296
|
+
return ethers.getAddress(signerAddress).toLowerCase() === ethers.getAddress(didAddress).toLowerCase();
|
|
3297
|
+
} catch {
|
|
3298
|
+
return false;
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
function jwkMatchesDid(jwk, did) {
|
|
3302
|
+
const method = extractDidMethod(did);
|
|
3303
|
+
if (method === "jwk") {
|
|
3304
|
+
try {
|
|
3305
|
+
const didJwk = didJwkToJwk(did);
|
|
3306
|
+
return publicJwkEquals(jwk, didJwk);
|
|
3307
|
+
} catch {
|
|
3308
|
+
return false;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
return false;
|
|
3312
|
+
}
|
|
3313
|
+
function proofSignerMatchesDid(proof, did) {
|
|
3314
|
+
switch (proof.proofType) {
|
|
3315
|
+
case "pop-eip712": {
|
|
3316
|
+
const signer = extractEip712Signer(proof);
|
|
3317
|
+
if (!signer) return false;
|
|
3318
|
+
return signerMatchesDid(signer, did);
|
|
3319
|
+
}
|
|
3320
|
+
case "pop-jws": {
|
|
3321
|
+
const jwsProof = proof;
|
|
3322
|
+
const jwk = extractJwsHeaderJwk(jwsProof);
|
|
3323
|
+
if (jwk && jwkMatchesDid(jwk, did)) return true;
|
|
3324
|
+
const payload = extractJwsPayload(jwsProof);
|
|
3325
|
+
if (payload && typeof payload.iss === "string") {
|
|
3326
|
+
if (payload.iss === did) return true;
|
|
3327
|
+
}
|
|
3328
|
+
return false;
|
|
3329
|
+
}
|
|
3330
|
+
case "tx-encoded-value":
|
|
3331
|
+
case "tx-interaction":
|
|
3332
|
+
return false;
|
|
3333
|
+
case "evidence-pointer":
|
|
3334
|
+
return false;
|
|
3335
|
+
default:
|
|
3336
|
+
return false;
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
function proofAuthorizedEntityMatchesDid(proof, did) {
|
|
3340
|
+
switch (proof.proofType) {
|
|
3341
|
+
case "pop-eip712": {
|
|
3342
|
+
const eip712 = proof;
|
|
3343
|
+
const authorizedEntity = eip712.proofObject.message.authorizedEntity;
|
|
3344
|
+
return typeof authorizedEntity === "string" && authorizedEntity === did;
|
|
3345
|
+
}
|
|
3346
|
+
case "pop-jws": {
|
|
3347
|
+
const payload = extractJwsPayload(proof);
|
|
3348
|
+
if (!payload) return false;
|
|
3349
|
+
return typeof payload.aud === "string" && payload.aud === did;
|
|
3350
|
+
}
|
|
3351
|
+
default:
|
|
3352
|
+
return false;
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
function verifyLinkedIdentifierProofs(data) {
|
|
3356
|
+
if (!data.subject || !data.linkedId) {
|
|
3357
|
+
return {
|
|
3358
|
+
valid: false,
|
|
3359
|
+
checks: [],
|
|
3360
|
+
reasons: ["subject and linkedId are required"]
|
|
3361
|
+
};
|
|
3362
|
+
}
|
|
3363
|
+
if (!Array.isArray(data.proofs) || data.proofs.length === 0) {
|
|
3364
|
+
return {
|
|
3365
|
+
valid: false,
|
|
3366
|
+
checks: [],
|
|
3367
|
+
reasons: ["At least one proof is required"]
|
|
3368
|
+
};
|
|
3369
|
+
}
|
|
3370
|
+
const checks = [];
|
|
3371
|
+
let subjectProved = false;
|
|
3372
|
+
let linkedIdProved = false;
|
|
3373
|
+
for (let i = 0; i < data.proofs.length; i++) {
|
|
3374
|
+
const proof = data.proofs[i];
|
|
3375
|
+
if (proofSignerMatchesDid(proof, data.subject)) {
|
|
3376
|
+
checks.push({
|
|
3377
|
+
proofIndex: i,
|
|
3378
|
+
proofType: proof.proofType,
|
|
3379
|
+
checkType: "signer-is-subject",
|
|
3380
|
+
valid: true
|
|
3381
|
+
});
|
|
3382
|
+
subjectProved = true;
|
|
3383
|
+
if (!proofAuthorizedEntityMatchesDid(proof, data.linkedId)) {
|
|
3384
|
+
checks.push({
|
|
3385
|
+
proofIndex: i,
|
|
3386
|
+
proofType: proof.proofType,
|
|
3387
|
+
checkType: "signer-is-subject",
|
|
3388
|
+
valid: false,
|
|
3389
|
+
reason: "Proof from subject does not authorize linkedId (aud mismatch)"
|
|
3390
|
+
});
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
if (proofSignerMatchesDid(proof, data.linkedId)) {
|
|
3394
|
+
checks.push({
|
|
3395
|
+
proofIndex: i,
|
|
3396
|
+
proofType: proof.proofType,
|
|
3397
|
+
checkType: "signer-is-linkedId",
|
|
3398
|
+
valid: true
|
|
3399
|
+
});
|
|
3400
|
+
linkedIdProved = true;
|
|
3401
|
+
if (!proofAuthorizedEntityMatchesDid(proof, data.subject)) {
|
|
3402
|
+
checks.push({
|
|
3403
|
+
proofIndex: i,
|
|
3404
|
+
proofType: proof.proofType,
|
|
3405
|
+
checkType: "signer-is-linkedId",
|
|
3406
|
+
valid: false,
|
|
3407
|
+
reason: "Proof from linkedId does not authorize subject (aud mismatch)"
|
|
3408
|
+
});
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
if (proof.proofType === "evidence-pointer") {
|
|
3412
|
+
checks.push({
|
|
3413
|
+
proofIndex: i,
|
|
3414
|
+
proofType: proof.proofType,
|
|
3415
|
+
checkType: "signer-is-subject",
|
|
3416
|
+
valid: true,
|
|
3417
|
+
reason: "Evidence pointer accepted (requires URL fetch for full verification)"
|
|
3418
|
+
});
|
|
3419
|
+
subjectProved = true;
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3422
|
+
const reasons = [];
|
|
3423
|
+
if (!subjectProved) {
|
|
3424
|
+
reasons.push("No proof demonstrates control by subject");
|
|
3425
|
+
}
|
|
3426
|
+
if (!linkedIdProved) {
|
|
3427
|
+
reasons.push("No proof demonstrates control by linkedId");
|
|
3428
|
+
}
|
|
3429
|
+
return {
|
|
3430
|
+
valid: reasons.length === 0,
|
|
3431
|
+
checks,
|
|
3432
|
+
reasons
|
|
3433
|
+
};
|
|
3434
|
+
}
|
|
3435
|
+
function verifyKeyBindingProofs(data) {
|
|
3436
|
+
if (!data.subject || !data.keyId) {
|
|
3437
|
+
return {
|
|
3438
|
+
valid: false,
|
|
3439
|
+
checks: [],
|
|
3440
|
+
reasons: ["subject and keyId are required"]
|
|
3441
|
+
};
|
|
3442
|
+
}
|
|
3443
|
+
if (!Array.isArray(data.proofs) || data.proofs.length === 0) {
|
|
3444
|
+
return {
|
|
3445
|
+
valid: false,
|
|
3446
|
+
checks: [],
|
|
3447
|
+
reasons: ["At least one proof is required"]
|
|
3448
|
+
};
|
|
3449
|
+
}
|
|
3450
|
+
const checks = [];
|
|
3451
|
+
let subjectAuthorizedKey = false;
|
|
3452
|
+
for (let i = 0; i < data.proofs.length; i++) {
|
|
3453
|
+
const proof = data.proofs[i];
|
|
3454
|
+
if (proofSignerMatchesDid(proof, data.subject)) {
|
|
3455
|
+
const authorizesKey = proofAuthorizedEntityMatchesDid(proof, data.keyId);
|
|
3456
|
+
checks.push({
|
|
3457
|
+
proofIndex: i,
|
|
3458
|
+
proofType: proof.proofType,
|
|
3459
|
+
checkType: "signer-is-subject-for-key",
|
|
3460
|
+
valid: authorizesKey,
|
|
3461
|
+
reason: authorizesKey ? void 0 : "Proof signed by subject but does not authorize the keyId"
|
|
3462
|
+
});
|
|
3463
|
+
if (authorizesKey) {
|
|
3464
|
+
subjectAuthorizedKey = true;
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
if (proofSignerMatchesDid(proof, data.keyId)) {
|
|
3468
|
+
checks.push({
|
|
3469
|
+
proofIndex: i,
|
|
3470
|
+
proofType: proof.proofType,
|
|
3471
|
+
checkType: "signer-is-keyId",
|
|
3472
|
+
valid: true,
|
|
3473
|
+
reason: "Key proved possession (supplementary, not sufficient alone)"
|
|
3474
|
+
});
|
|
3475
|
+
}
|
|
3476
|
+
if (proof.proofType === "evidence-pointer") {
|
|
3477
|
+
checks.push({
|
|
3478
|
+
proofIndex: i,
|
|
3479
|
+
proofType: proof.proofType,
|
|
3480
|
+
checkType: "signer-is-subject-for-key",
|
|
3481
|
+
valid: true,
|
|
3482
|
+
reason: "Evidence pointer accepted (requires URL fetch for full verification)"
|
|
3483
|
+
});
|
|
3484
|
+
subjectAuthorizedKey = true;
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
if (data.publicKeyJwk && extractDidMethod(data.keyId) === "jwk") {
|
|
3488
|
+
try {
|
|
3489
|
+
const keyIdJwk = didJwkToJwk(data.keyId);
|
|
3490
|
+
const jwkConsistent = publicJwkEquals(data.publicKeyJwk, keyIdJwk);
|
|
3491
|
+
if (!jwkConsistent) {
|
|
3492
|
+
return {
|
|
3493
|
+
valid: false,
|
|
3494
|
+
checks,
|
|
3495
|
+
reasons: ["publicKeyJwk does not match the key material in keyId (did:jwk)"]
|
|
3496
|
+
};
|
|
3497
|
+
}
|
|
3498
|
+
} catch {
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
const reasons = [];
|
|
3502
|
+
if (!subjectAuthorizedKey) {
|
|
3503
|
+
reasons.push(
|
|
3504
|
+
"No proof demonstrates that subject authorized the key binding"
|
|
3505
|
+
);
|
|
3506
|
+
}
|
|
3507
|
+
return {
|
|
3508
|
+
valid: reasons.length === 0,
|
|
3509
|
+
checks,
|
|
3510
|
+
reasons
|
|
3511
|
+
};
|
|
3512
|
+
}
|
|
3513
|
+
var DID_ARTIFACT_PREFIX = "did:artifact:";
|
|
3514
|
+
var CID_VERSION = 1;
|
|
3515
|
+
var RAW_CODEC = raw__namespace.code;
|
|
3516
|
+
var SHA2_256_CODE = 18;
|
|
3517
|
+
var SHA2_256_DIGEST_LENGTH = 32;
|
|
3518
|
+
function parseArtifactDid(did) {
|
|
3519
|
+
if (typeof did !== "string" || !did.startsWith(DID_ARTIFACT_PREFIX)) {
|
|
3520
|
+
throw new OmaTrustError("INVALID_DID", "Expected a did:artifact DID", { did });
|
|
3521
|
+
}
|
|
3522
|
+
const identifier = did.slice(DID_ARTIFACT_PREFIX.length);
|
|
3523
|
+
if (!identifier || identifier.length === 0) {
|
|
3524
|
+
throw new OmaTrustError("INVALID_DID", "Missing method-specific identifier", { did });
|
|
3525
|
+
}
|
|
3526
|
+
if (identifier[0] !== "b") {
|
|
3527
|
+
throw new OmaTrustError(
|
|
3528
|
+
"INVALID_DID",
|
|
3529
|
+
`Invalid multibase prefix "${identifier[0]}", expected "b" (base32lower)`,
|
|
3530
|
+
{ did }
|
|
3531
|
+
);
|
|
3532
|
+
}
|
|
3533
|
+
let cid$1;
|
|
3534
|
+
try {
|
|
3535
|
+
cid$1 = cid.CID.parse(identifier, base32.base32);
|
|
3536
|
+
} catch (err) {
|
|
3537
|
+
throw new OmaTrustError(
|
|
3538
|
+
"INVALID_DID",
|
|
3539
|
+
"Failed to decode base32 CID from did:artifact identifier",
|
|
3540
|
+
{ did, cause: err }
|
|
3541
|
+
);
|
|
3542
|
+
}
|
|
3543
|
+
if (cid$1.version !== CID_VERSION) {
|
|
3544
|
+
throw new OmaTrustError(
|
|
3545
|
+
"INVALID_DID",
|
|
3546
|
+
`CID version must be 1, got ${cid$1.version}`,
|
|
3547
|
+
{ did }
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
if (cid$1.code !== RAW_CODEC) {
|
|
3551
|
+
throw new OmaTrustError(
|
|
3552
|
+
"INVALID_DID",
|
|
3553
|
+
`Multicodec must be raw (0x55), got 0x${cid$1.code.toString(16)}`,
|
|
3554
|
+
{ did }
|
|
3555
|
+
);
|
|
3556
|
+
}
|
|
3557
|
+
if (cid$1.multihash.code !== SHA2_256_CODE) {
|
|
3558
|
+
throw new OmaTrustError(
|
|
3559
|
+
"INVALID_DID",
|
|
3560
|
+
`Multihash function must be sha2-256 (0x12), got 0x${cid$1.multihash.code.toString(16)}`,
|
|
3561
|
+
{ did }
|
|
3562
|
+
);
|
|
3563
|
+
}
|
|
3564
|
+
if (cid$1.multihash.digest.length !== SHA2_256_DIGEST_LENGTH) {
|
|
3565
|
+
throw new OmaTrustError(
|
|
3566
|
+
"INVALID_DID",
|
|
3567
|
+
`SHA-256 digest must be 32 bytes, got ${cid$1.multihash.digest.length}`,
|
|
3568
|
+
{ did }
|
|
3569
|
+
);
|
|
3570
|
+
}
|
|
3571
|
+
const digest = cid$1.multihash.digest;
|
|
3572
|
+
const digestHex = Array.from(digest).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3573
|
+
return { did, identifier, digest, digestHex };
|
|
3574
|
+
}
|
|
3575
|
+
|
|
3576
|
+
// src/reputation/artifact-verification.ts
|
|
3577
|
+
async function verifyResponsibilityClaim(params) {
|
|
3578
|
+
const {
|
|
3579
|
+
attestation,
|
|
3580
|
+
artifactDid,
|
|
3581
|
+
provider,
|
|
3582
|
+
easContractAddress,
|
|
3583
|
+
chain,
|
|
3584
|
+
chainId,
|
|
3585
|
+
responsibilityClaimSchemaString
|
|
3586
|
+
} = params;
|
|
3587
|
+
const reasons = [];
|
|
3588
|
+
const checks = {
|
|
3589
|
+
schemaValid: false,
|
|
3590
|
+
subjectMatches: false,
|
|
3591
|
+
notRevoked: false,
|
|
3592
|
+
currentlyEffective: false,
|
|
3593
|
+
controllerAuthorized: false,
|
|
3594
|
+
issuedDuringAuthorizationWindow: false
|
|
3595
|
+
};
|
|
3596
|
+
let decoded;
|
|
3597
|
+
try {
|
|
3598
|
+
if (attestation.raw) {
|
|
3599
|
+
decoded = decodeAttestationData(responsibilityClaimSchemaString, attestation.raw);
|
|
3600
|
+
} else if (attestation.data && typeof attestation.data === "object") {
|
|
3601
|
+
decoded = attestation.data;
|
|
3602
|
+
} else {
|
|
3603
|
+
reasons.push("No attestation data available to decode");
|
|
3604
|
+
return buildFailedResult(checks, reasons);
|
|
3605
|
+
}
|
|
3606
|
+
} catch (err) {
|
|
3607
|
+
reasons.push(
|
|
3608
|
+
`Failed to decode attestation data: ${err instanceof Error ? err.message : "unknown error"}`
|
|
3609
|
+
);
|
|
3610
|
+
return buildFailedResult(checks, reasons);
|
|
3611
|
+
}
|
|
3612
|
+
const responsibleParty = decoded.responsibleParty;
|
|
3613
|
+
const subject = decoded.subject;
|
|
3614
|
+
const responsibilityType = decoded.responsibilityType;
|
|
3615
|
+
const issuedAt = decoded.issuedAt;
|
|
3616
|
+
const effectiveAt = decoded.effectiveAt;
|
|
3617
|
+
const expiresAt = decoded.expiresAt;
|
|
3618
|
+
const subjectLabel = decoded.subjectLabel;
|
|
3619
|
+
if (!responsibleParty || !subject || !responsibilityType || !issuedAt) {
|
|
3620
|
+
if (!responsibleParty) reasons.push("Missing required field: responsibleParty");
|
|
3621
|
+
if (!subject) reasons.push("Missing required field: subject");
|
|
3622
|
+
if (!responsibilityType) reasons.push("Missing required field: responsibilityType");
|
|
3623
|
+
if (!issuedAt) reasons.push("Missing required field: issuedAt");
|
|
3624
|
+
return buildFailedResult(checks, reasons, {
|
|
3625
|
+
responsibleParty,
|
|
3626
|
+
subjectLabel,
|
|
3627
|
+
responsibilityType
|
|
3628
|
+
});
|
|
3629
|
+
}
|
|
3630
|
+
if (!Array.isArray(responsibilityType) || responsibilityType.length === 0) {
|
|
3631
|
+
reasons.push("responsibilityType must be a non-empty array");
|
|
3632
|
+
return buildFailedResult(checks, reasons, {
|
|
3633
|
+
responsibleParty,
|
|
3634
|
+
subjectLabel,
|
|
3635
|
+
responsibilityType
|
|
3636
|
+
});
|
|
3637
|
+
}
|
|
3638
|
+
checks.schemaValid = true;
|
|
3639
|
+
if (artifactDid) {
|
|
3640
|
+
checks.subjectMatches = subject.toLowerCase() === artifactDid.toLowerCase();
|
|
3641
|
+
if (!checks.subjectMatches) {
|
|
3642
|
+
reasons.push(`Subject "${subject}" does not match expected artifact "${artifactDid}"`);
|
|
3643
|
+
}
|
|
3644
|
+
} else {
|
|
3645
|
+
checks.subjectMatches = true;
|
|
3646
|
+
}
|
|
3647
|
+
checks.notRevoked = attestation.revocationTime === BigInt(0);
|
|
3648
|
+
if (!checks.notRevoked) {
|
|
3649
|
+
reasons.push("Attestation has been revoked");
|
|
3650
|
+
}
|
|
3651
|
+
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
3652
|
+
const effectiveTime = toBigInt(effectiveAt);
|
|
3653
|
+
const expirationTime = toBigInt(expiresAt);
|
|
3654
|
+
const isEffective = effectiveTime === BigInt(0) || effectiveTime <= now;
|
|
3655
|
+
const isNotExpired = expirationTime === BigInt(0) || expirationTime > now;
|
|
3656
|
+
checks.currentlyEffective = isEffective && isNotExpired;
|
|
3657
|
+
if (!isEffective) {
|
|
3658
|
+
reasons.push("Attestation is not yet effective");
|
|
3659
|
+
}
|
|
3660
|
+
if (!isNotExpired) {
|
|
3661
|
+
reasons.push("Attestation has expired");
|
|
3662
|
+
}
|
|
3663
|
+
const controllerDid = `did:pkh:eip155:${chainId}:${attestation.attester.toLowerCase()}`;
|
|
3664
|
+
let authorization = null;
|
|
3665
|
+
try {
|
|
3666
|
+
const resolvedChain = chain ?? `eip155:${chainId}`;
|
|
3667
|
+
authorization = await getControllerAuthorization({
|
|
3668
|
+
subjectDid: responsibleParty,
|
|
3669
|
+
controllerDid,
|
|
3670
|
+
provider,
|
|
3671
|
+
chain: resolvedChain,
|
|
3672
|
+
easContractAddress
|
|
3673
|
+
});
|
|
3674
|
+
checks.controllerAuthorized = authorization.authorized;
|
|
3675
|
+
if (!checks.controllerAuthorized) {
|
|
3676
|
+
reasons.push(`Controller ${controllerDid} is not authorized for ${responsibleParty}`);
|
|
3677
|
+
}
|
|
3678
|
+
if (authorization.authorized && authorization.anchoredFrom !== null) {
|
|
3679
|
+
const issuedAtBigInt = toBigInt(issuedAt);
|
|
3680
|
+
const afterStart = issuedAtBigInt >= authorization.anchoredFrom;
|
|
3681
|
+
const beforeEnd = authorization.until === null || issuedAtBigInt <= authorization.until;
|
|
3682
|
+
checks.issuedDuringAuthorizationWindow = afterStart && beforeEnd;
|
|
3683
|
+
if (!afterStart) {
|
|
3684
|
+
reasons.push("Attestation was issued before the authorization window started");
|
|
3685
|
+
}
|
|
3686
|
+
if (!beforeEnd) {
|
|
3687
|
+
reasons.push("Attestation was issued after the authorization window ended");
|
|
3688
|
+
}
|
|
3689
|
+
} else if (authorization.authorized && authorization.anchoredFrom === null) {
|
|
3690
|
+
checks.issuedDuringAuthorizationWindow = true;
|
|
3691
|
+
} else {
|
|
3692
|
+
checks.issuedDuringAuthorizationWindow = false;
|
|
3693
|
+
}
|
|
3694
|
+
} catch (err) {
|
|
3695
|
+
reasons.push(
|
|
3696
|
+
`Controller authorization check failed: ${err instanceof Error ? err.message : "unknown error"}`
|
|
3697
|
+
);
|
|
3698
|
+
checks.controllerAuthorized = false;
|
|
3699
|
+
checks.issuedDuringAuthorizationWindow = false;
|
|
3700
|
+
}
|
|
3701
|
+
const valid = Object.values(checks).every(Boolean);
|
|
3702
|
+
return {
|
|
3703
|
+
valid,
|
|
3704
|
+
responsibleParty,
|
|
3705
|
+
controllerDid,
|
|
3706
|
+
responsibilityTypes: responsibilityType,
|
|
3707
|
+
subjectLabel: subjectLabel || void 0,
|
|
3708
|
+
authorization,
|
|
3709
|
+
checks,
|
|
3710
|
+
reasons
|
|
3711
|
+
};
|
|
3712
|
+
}
|
|
3713
|
+
async function getVerifiedArtifactAttestations(params) {
|
|
3714
|
+
const {
|
|
3715
|
+
artifactDid,
|
|
3716
|
+
provider,
|
|
3717
|
+
easContractAddress,
|
|
3718
|
+
chain,
|
|
3719
|
+
chainId,
|
|
3720
|
+
schemaUids,
|
|
3721
|
+
responsibilityClaimSchemaUid,
|
|
3722
|
+
responsibilityClaimSchemaString,
|
|
3723
|
+
securityAssessmentSchemaUid,
|
|
3724
|
+
certificationSchemaUid,
|
|
3725
|
+
fromBlock,
|
|
3726
|
+
limit
|
|
3727
|
+
} = params;
|
|
3728
|
+
parseArtifactDid(artifactDid);
|
|
3729
|
+
if (schemaUids.length === 0) {
|
|
3730
|
+
return {
|
|
3731
|
+
artifactDid,
|
|
3732
|
+
responsibilityClaims: [],
|
|
3733
|
+
securityAssessments: [],
|
|
3734
|
+
certifications: [],
|
|
3735
|
+
otherAttestations: []
|
|
3736
|
+
};
|
|
3737
|
+
}
|
|
3738
|
+
const results = await listAttestations({
|
|
3739
|
+
subjectDid: artifactDid,
|
|
3740
|
+
provider,
|
|
3741
|
+
easContractAddress,
|
|
3742
|
+
schemas: schemaUids,
|
|
3743
|
+
limit: limit ?? 100,
|
|
3744
|
+
fromBlock
|
|
3745
|
+
});
|
|
3746
|
+
const responsibilityClaims = [];
|
|
3747
|
+
const securityAssessments = [];
|
|
3748
|
+
const certifications = [];
|
|
3749
|
+
const otherAttestations = [];
|
|
3750
|
+
for (const att of results) {
|
|
3751
|
+
const schemaUidLower = att.schema.toLowerCase();
|
|
3752
|
+
if (schemaUidLower === responsibilityClaimSchemaUid.toLowerCase()) {
|
|
3753
|
+
const verification = await verifyResponsibilityClaim({
|
|
3754
|
+
attestation: att,
|
|
3755
|
+
artifactDid,
|
|
3756
|
+
provider,
|
|
3757
|
+
easContractAddress,
|
|
3758
|
+
chain,
|
|
3759
|
+
chainId,
|
|
3760
|
+
responsibilityClaimSchemaString
|
|
3761
|
+
});
|
|
3762
|
+
responsibilityClaims.push({ attestation: att, verification });
|
|
3763
|
+
} else if (securityAssessmentSchemaUid && schemaUidLower === securityAssessmentSchemaUid.toLowerCase()) {
|
|
3764
|
+
const verification = await runStandardVerification(att, provider);
|
|
3765
|
+
securityAssessments.push({ attestation: att, verification });
|
|
3766
|
+
} else if (certificationSchemaUid && schemaUidLower === certificationSchemaUid.toLowerCase()) {
|
|
3767
|
+
const verification = await runStandardVerification(att, provider);
|
|
3768
|
+
certifications.push({ attestation: att, verification });
|
|
3769
|
+
} else {
|
|
3770
|
+
const verification = await runStandardVerification(att, provider);
|
|
3771
|
+
otherAttestations.push({ attestation: att, verification });
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
return {
|
|
3775
|
+
artifactDid,
|
|
3776
|
+
responsibilityClaims,
|
|
3777
|
+
securityAssessments,
|
|
3778
|
+
certifications,
|
|
3779
|
+
otherAttestations
|
|
3780
|
+
};
|
|
3781
|
+
}
|
|
3782
|
+
async function isArtifactClaimedBy(params) {
|
|
3783
|
+
const { artifactDid, responsibleParty, responsibilityTypes } = params;
|
|
3784
|
+
const result = await getVerifiedArtifactAttestations({
|
|
3785
|
+
artifactDid,
|
|
3786
|
+
provider: params.provider,
|
|
3787
|
+
easContractAddress: params.easContractAddress,
|
|
3788
|
+
chain: params.chain,
|
|
3789
|
+
chainId: params.chainId,
|
|
3790
|
+
schemaUids: params.schemaUids,
|
|
3791
|
+
responsibilityClaimSchemaUid: params.responsibilityClaimSchemaUid,
|
|
3792
|
+
responsibilityClaimSchemaString: params.responsibilityClaimSchemaString,
|
|
3793
|
+
securityAssessmentSchemaUid: params.securityAssessmentSchemaUid,
|
|
3794
|
+
certificationSchemaUid: params.certificationSchemaUid
|
|
3795
|
+
});
|
|
3796
|
+
const matchingClaims = result.responsibilityClaims.filter(
|
|
3797
|
+
(claim) => claim.verification.responsibleParty.toLowerCase() === responsibleParty.toLowerCase()
|
|
3798
|
+
);
|
|
3799
|
+
const validClaims = matchingClaims.filter((claim) => claim.verification.valid);
|
|
3800
|
+
let finalClaims = validClaims;
|
|
3801
|
+
let matchedTypes = [];
|
|
3802
|
+
if (responsibilityTypes && responsibilityTypes.length > 0) {
|
|
3803
|
+
finalClaims = validClaims.filter(
|
|
3804
|
+
(claim) => claim.verification.responsibilityTypes.some(
|
|
3805
|
+
(t) => responsibilityTypes.includes(t)
|
|
3806
|
+
)
|
|
3807
|
+
);
|
|
3808
|
+
matchedTypes = [
|
|
3809
|
+
...new Set(
|
|
3810
|
+
finalClaims.flatMap(
|
|
3811
|
+
(claim) => claim.verification.responsibilityTypes.filter(
|
|
3812
|
+
(t) => responsibilityTypes.includes(t)
|
|
3813
|
+
)
|
|
3814
|
+
)
|
|
3815
|
+
)
|
|
3816
|
+
];
|
|
3817
|
+
} else {
|
|
3818
|
+
matchedTypes = [
|
|
3819
|
+
...new Set(
|
|
3820
|
+
validClaims.flatMap((claim) => claim.verification.responsibilityTypes)
|
|
3821
|
+
)
|
|
3822
|
+
];
|
|
3823
|
+
}
|
|
3824
|
+
const reasons = [];
|
|
3825
|
+
if (finalClaims.length === 0) {
|
|
3826
|
+
if (matchingClaims.length === 0) {
|
|
3827
|
+
reasons.push(
|
|
3828
|
+
`No responsibility claims found from ${responsibleParty} for this artifact`
|
|
3829
|
+
);
|
|
3830
|
+
} else if (validClaims.length === 0) {
|
|
3831
|
+
reasons.push(
|
|
3832
|
+
`Claims from ${responsibleParty} exist but none passed verification`
|
|
3833
|
+
);
|
|
3834
|
+
} else if (responsibilityTypes) {
|
|
3835
|
+
reasons.push(
|
|
3836
|
+
`No claims matched the requested responsibility types: ${responsibilityTypes.join(", ")}`
|
|
3837
|
+
);
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
return {
|
|
3841
|
+
claimed: finalClaims.length > 0,
|
|
3842
|
+
claims: finalClaims,
|
|
3843
|
+
matchedResponsibilityTypes: matchedTypes,
|
|
3844
|
+
reasons
|
|
3845
|
+
};
|
|
3846
|
+
}
|
|
3847
|
+
function toBigInt(value) {
|
|
3848
|
+
if (value === void 0 || value === null) return BigInt(0);
|
|
3849
|
+
if (typeof value === "bigint") return value;
|
|
3850
|
+
return BigInt(value);
|
|
3851
|
+
}
|
|
3852
|
+
function buildFailedResult(checks, reasons, decoded) {
|
|
3853
|
+
return {
|
|
3854
|
+
valid: false,
|
|
3855
|
+
responsibleParty: decoded?.responsibleParty ?? "",
|
|
3856
|
+
controllerDid: "",
|
|
3857
|
+
responsibilityTypes: decoded?.responsibilityType ?? [],
|
|
3858
|
+
subjectLabel: decoded?.subjectLabel || void 0,
|
|
3859
|
+
authorization: null,
|
|
3860
|
+
checks,
|
|
3861
|
+
reasons
|
|
3862
|
+
};
|
|
3863
|
+
}
|
|
3864
|
+
async function runStandardVerification(attestation, provider) {
|
|
3865
|
+
try {
|
|
3866
|
+
return await verifyAttestation({ attestation, provider });
|
|
3867
|
+
} catch {
|
|
3868
|
+
return void 0;
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3156
3871
|
|
|
3157
3872
|
exports.EIP1967_ADMIN_SLOT = EIP1967_ADMIN_SLOT;
|
|
3158
3873
|
exports.OWNERSHIP_PATTERNS = OWNERSHIP_PATTERNS;
|
|
@@ -3195,7 +3910,9 @@ exports.getMajorVersion = getMajorVersion;
|
|
|
3195
3910
|
exports.getOmaTrustProofEip712Types = getOmaTrustProofEip712Types;
|
|
3196
3911
|
exports.getSchemaDetails = getSchemaDetails;
|
|
3197
3912
|
exports.getSupportedChainIds = getSupportedChainIds;
|
|
3913
|
+
exports.getVerifiedArtifactAttestations = getVerifiedArtifactAttestations;
|
|
3198
3914
|
exports.hashSeed = hashSeed;
|
|
3915
|
+
exports.isArtifactClaimedBy = isArtifactClaimedBy;
|
|
3199
3916
|
exports.isChainSupported = isChainSupported;
|
|
3200
3917
|
exports.listAttestations = listAttestations;
|
|
3201
3918
|
exports.normalizeSchema = normalizeSchema;
|
|
@@ -3216,10 +3933,14 @@ exports.verifyDidPkhOwnership = verifyDidPkhOwnership;
|
|
|
3216
3933
|
exports.verifyDidWebOwnership = verifyDidWebOwnership;
|
|
3217
3934
|
exports.verifyDnsTxtControllerDid = verifyDnsTxtControllerDid2;
|
|
3218
3935
|
exports.verifyEip712Signature = verifyEip712Signature;
|
|
3936
|
+
exports.verifyKeyBindingProofs = verifyKeyBindingProofs;
|
|
3937
|
+
exports.verifyLinkedIdentifierProofs = verifyLinkedIdentifierProofs;
|
|
3219
3938
|
exports.verifyProof = verifyProof;
|
|
3939
|
+
exports.verifyResponsibilityClaim = verifyResponsibilityClaim;
|
|
3220
3940
|
exports.verifySchemaExists = verifySchemaExists;
|
|
3221
3941
|
exports.verifySubjectOwnership = verifySubjectOwnership;
|
|
3222
3942
|
exports.verifyTransferProof = verifyTransferProof;
|
|
3943
|
+
exports.verifyX402Artifact = verifyX402Artifact;
|
|
3223
3944
|
exports.verifyX402Eip712Artifact = verifyX402Eip712Artifact;
|
|
3224
3945
|
exports.verifyX402Eip712Offer = verifyX402Eip712Offer;
|
|
3225
3946
|
exports.verifyX402Eip712Receipt = verifyX402Eip712Receipt;
|