@orangecheck/me-client 0.32.1 → 0.32.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{identity-1VYMOhzV.d.mts → identity-6pjtyKYh.d.mts} +1 -1
- package/dist/{identity-1VYMOhzV.d.ts → identity-6pjtyKYh.d.ts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +72 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +72 -21
- package/dist/index.mjs.map +1 -1
- package/dist/{integrator-VvKGegqS.d.mts → integrator-C-enR55c.d.mts} +1 -1
- package/dist/{integrator-VvKGegqS.d.ts → integrator-C-enR55c.d.ts} +1 -1
- package/dist/integrator.d.mts +1 -1
- package/dist/integrator.d.ts +1 -1
- package/dist/integrator.js.map +1 -1
- package/dist/integrator.mjs.map +1 -1
- package/dist/server.d.mts +6 -4
- package/dist/server.d.ts +6 -4
- package/dist/server.js +82 -27
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +82 -27
- package/dist/server.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1232,33 +1232,85 @@ async function verifyEd255192(key, sig, msg) {
|
|
|
1232
1232
|
return false;
|
|
1233
1233
|
}
|
|
1234
1234
|
}
|
|
1235
|
+
var SIGNED_FIELDS = [
|
|
1236
|
+
"v",
|
|
1237
|
+
"kind",
|
|
1238
|
+
"did_oc",
|
|
1239
|
+
"event_count",
|
|
1240
|
+
"human_event_count",
|
|
1241
|
+
"lifetime_sats",
|
|
1242
|
+
"distinct_integrator_count",
|
|
1243
|
+
"oldest_event_at",
|
|
1244
|
+
"active_days",
|
|
1245
|
+
"computed_at",
|
|
1246
|
+
"expires_at"
|
|
1247
|
+
];
|
|
1248
|
+
var COUNTS = [
|
|
1249
|
+
"event_count",
|
|
1250
|
+
"human_event_count",
|
|
1251
|
+
"lifetime_sats",
|
|
1252
|
+
"distinct_integrator_count",
|
|
1253
|
+
"active_days"
|
|
1254
|
+
];
|
|
1255
|
+
function readSignedAttestation(canonical, id) {
|
|
1256
|
+
const text = new TextDecoder().decode(canonical);
|
|
1257
|
+
let parsed;
|
|
1258
|
+
try {
|
|
1259
|
+
parsed = JSON.parse(text);
|
|
1260
|
+
} catch {
|
|
1261
|
+
return null;
|
|
1262
|
+
}
|
|
1263
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
1264
|
+
const o = parsed;
|
|
1265
|
+
if (o.v !== 1 || o.kind !== "oc-me-activity" || typeof o.did_oc !== "string") return null;
|
|
1266
|
+
const countsOk = COUNTS.every((k) => {
|
|
1267
|
+
const n = o[k];
|
|
1268
|
+
return typeof n === "number" && Number.isSafeInteger(n) && n >= 0;
|
|
1269
|
+
});
|
|
1270
|
+
if (!countsOk) return null;
|
|
1271
|
+
if (o.oldest_event_at !== null && typeof o.oldest_event_at !== "string") return null;
|
|
1272
|
+
if (typeof o.computed_at !== "string" || typeof o.expires_at !== "string") return null;
|
|
1273
|
+
const ordered = Object.fromEntries(SIGNED_FIELDS.map((k) => [k, o[k]]));
|
|
1274
|
+
if (JSON.stringify(ordered) !== text) return null;
|
|
1275
|
+
return { id, ...ordered };
|
|
1276
|
+
}
|
|
1277
|
+
function sameAttestation(copy, signed) {
|
|
1278
|
+
const c = copy;
|
|
1279
|
+
const v = signed;
|
|
1280
|
+
return ["id", ...SIGNED_FIELDS].every((k) => c[k] === v[k]);
|
|
1281
|
+
}
|
|
1235
1282
|
async function verifyActivityAttestation(bundle, options = {}) {
|
|
1236
1283
|
const checks = [];
|
|
1237
|
-
const shapeOk = !!bundle && typeof bundle === "object" && typeof bundle.sig === "string" && typeof bundle.kid === "string" && typeof bundle.canonical_b64 === "string" &&
|
|
1284
|
+
const shapeOk = !!bundle && typeof bundle === "object" && typeof bundle.sig === "string" && typeof bundle.kid === "string" && typeof bundle.canonical_b64 === "string" && (bundle.attestation === void 0 || !!bundle.attestation && typeof bundle.attestation === "object");
|
|
1238
1285
|
checks.push({
|
|
1239
1286
|
ok: shapeOk,
|
|
1240
|
-
label: "bundle shape \xB7 sig / kid / canonical_b64
|
|
1287
|
+
label: "bundle shape \xB7 sig / kid / canonical_b64"
|
|
1241
1288
|
});
|
|
1242
1289
|
if (!shapeOk) {
|
|
1243
1290
|
return { ok: false, reason: "bundle shape invalid", checks };
|
|
1244
1291
|
}
|
|
1245
|
-
const a = bundle.attestation;
|
|
1246
1292
|
const canonical = base64ToBytes(bundle.canonical_b64);
|
|
1247
1293
|
checks.push({
|
|
1248
1294
|
ok: canonical !== null,
|
|
1249
1295
|
label: "canonical_b64 decodes",
|
|
1250
1296
|
detail: canonical ? `${canonical.length} bytes` : "invalid base64"
|
|
1251
1297
|
});
|
|
1252
|
-
if (!canonical) return { ok: false, reason: "canonical_b64 invalid base64", checks
|
|
1253
|
-
const
|
|
1254
|
-
const
|
|
1255
|
-
|
|
1298
|
+
if (!canonical) return { ok: false, reason: "canonical_b64 invalid base64", checks };
|
|
1299
|
+
const computedId = bytesToHex(await sha256(canonical));
|
|
1300
|
+
const signed = readSignedAttestation(canonical, computedId);
|
|
1301
|
+
checks.push({
|
|
1302
|
+
ok: signed !== null,
|
|
1303
|
+
label: "canonical_bytes are an oc-me-activity attestation in canonical form"
|
|
1304
|
+
});
|
|
1305
|
+
if (!signed) return { ok: false, reason: "canonical bytes are not an activity attestation", checks };
|
|
1306
|
+
const copy = bundle.attestation;
|
|
1307
|
+
const copyOk = copy === void 0 || sameAttestation(copy, signed);
|
|
1256
1308
|
checks.push({
|
|
1257
|
-
ok:
|
|
1258
|
-
label: "sha256(canonical_bytes)
|
|
1259
|
-
detail:
|
|
1309
|
+
ok: copyOk,
|
|
1310
|
+
label: "attestation === the signed bytes, id = sha256(canonical_bytes)",
|
|
1311
|
+
detail: copyOk ? computedId : "the readable copy differs from what was signed"
|
|
1260
1312
|
});
|
|
1261
|
-
if (!
|
|
1313
|
+
if (!copyOk) return { ok: false, reason: "attestation does not match the signed bytes", checks };
|
|
1262
1314
|
let key = null;
|
|
1263
1315
|
if (options.jwk) {
|
|
1264
1316
|
if (options.jwk.kid !== bundle.kid) {
|
|
@@ -1267,7 +1319,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
|
|
|
1267
1319
|
label: "JWK with matching kid present",
|
|
1268
1320
|
detail: `provided jwk.kid=${options.jwk.kid} but bundle.kid=${bundle.kid}`
|
|
1269
1321
|
});
|
|
1270
|
-
return { ok: false, reason: "kid mismatch with provided jwk", checks
|
|
1322
|
+
return { ok: false, reason: "kid mismatch with provided jwk", checks };
|
|
1271
1323
|
}
|
|
1272
1324
|
try {
|
|
1273
1325
|
key = await importJWK(options.jwk, "EdDSA");
|
|
@@ -1278,7 +1330,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
|
|
|
1278
1330
|
label: "JWK with matching kid present",
|
|
1279
1331
|
detail: `provided jwk failed import: ${err.message}`
|
|
1280
1332
|
});
|
|
1281
|
-
return { ok: false, reason: "provided jwk failed import", checks
|
|
1333
|
+
return { ok: false, reason: "provided jwk failed import", checks };
|
|
1282
1334
|
}
|
|
1283
1335
|
} else {
|
|
1284
1336
|
const issuer = options.issuer ?? DEFAULT_ISSUER2;
|
|
@@ -1297,7 +1349,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
|
|
|
1297
1349
|
detail: key ? `kid ${bundle.kid}` : `no JWK with kid ${bundle.kid} at ${issuer}${ENVELOPE_JWKS_PATH}`
|
|
1298
1350
|
});
|
|
1299
1351
|
if (!key) {
|
|
1300
|
-
return { ok: false, reason: `kid ${bundle.kid} not in envelope JWKS`, checks
|
|
1352
|
+
return { ok: false, reason: `kid ${bundle.kid} not in envelope JWKS`, checks };
|
|
1301
1353
|
}
|
|
1302
1354
|
} catch (err) {
|
|
1303
1355
|
checks.push({
|
|
@@ -1308,8 +1360,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
|
|
|
1308
1360
|
return {
|
|
1309
1361
|
ok: false,
|
|
1310
1362
|
reason: `envelope JWKS unavailable: ${err.message}`,
|
|
1311
|
-
checks
|
|
1312
|
-
attestation: a
|
|
1363
|
+
checks
|
|
1313
1364
|
};
|
|
1314
1365
|
}
|
|
1315
1366
|
}
|
|
@@ -1320,7 +1371,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
|
|
|
1320
1371
|
label: "ed25519.verify(sig, canonical_bytes, jwk.public)",
|
|
1321
1372
|
detail: "malformed sig (expected hex)"
|
|
1322
1373
|
});
|
|
1323
|
-
return { ok: false, reason: "malformed sig", checks
|
|
1374
|
+
return { ok: false, reason: "malformed sig", checks };
|
|
1324
1375
|
}
|
|
1325
1376
|
const sigOk = await verifyEd255192(key, sigBytes, canonical);
|
|
1326
1377
|
checks.push({
|
|
@@ -1328,17 +1379,17 @@ async function verifyActivityAttestation(bundle, options = {}) {
|
|
|
1328
1379
|
label: "ed25519.verify(sig, canonical_bytes, jwk.public)",
|
|
1329
1380
|
detail: sigOk ? "signature valid" : "signature does not match"
|
|
1330
1381
|
});
|
|
1331
|
-
if (!sigOk) return { ok: false, reason: "signature does not match", checks
|
|
1382
|
+
if (!sigOk) return { ok: false, reason: "signature does not match", checks };
|
|
1332
1383
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
1333
|
-
const expiresMs = Date.parse(
|
|
1384
|
+
const expiresMs = Date.parse(signed.expires_at);
|
|
1334
1385
|
const freshOk = Number.isFinite(expiresMs) && expiresMs > now.getTime();
|
|
1335
1386
|
checks.push({
|
|
1336
1387
|
ok: freshOk,
|
|
1337
1388
|
label: "now < attestation.expires_at",
|
|
1338
1389
|
detail: freshOk ? `expires ${new Date(expiresMs).toISOString()}` : "attestation has expired"
|
|
1339
1390
|
});
|
|
1340
|
-
if (!freshOk) return { ok: false, reason: "attestation has expired", checks
|
|
1341
|
-
return { ok: true, attestation:
|
|
1391
|
+
if (!freshOk) return { ok: false, reason: "attestation has expired", checks };
|
|
1392
|
+
return { ok: true, attestation: signed, checks };
|
|
1342
1393
|
}
|
|
1343
1394
|
async function refreshEnvelopeJwks(issuer = DEFAULT_ISSUER2) {
|
|
1344
1395
|
jwksCache2.delete(issuer);
|