@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.
@@ -13,7 +13,7 @@ interface ActivityAttestation {
13
13
  expires_at: string;
14
14
  }
15
15
  interface ActivityAttestationBundle {
16
- attestation: ActivityAttestation;
16
+ attestation?: ActivityAttestation;
17
17
  sig: string;
18
18
  kid: string;
19
19
  canonical_b64: string;
@@ -13,7 +13,7 @@ interface ActivityAttestation {
13
13
  expires_at: string;
14
14
  }
15
15
  interface ActivityAttestationBundle {
16
- attestation: ActivityAttestation;
16
+ attestation?: ActivityAttestation;
17
17
  sig: string;
18
18
  kid: string;
19
19
  canonical_b64: string;
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-1VYMOhzV.mjs';
2
- export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-1VYMOhzV.mjs';
3
- import { B as BillableEvent, E as EventKey, I as IntegratorPriceConfig, T as TelemetryEvent, S as SignInOptions, a as Session, P as PaymentAuthorizeOptions, b as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-VvKGegqS.mjs';
4
- export { c as ALL_EVENT_SUBTYPES, d as ARCHETYPE_TEMPLATES, e as AgentClassOverride, h as AttestTier, C as ClassASubtype, i as ClassBSubtype, j as ClassCSubtype, k as ComputedFees, D as DropCadence, l as DropClosedWebhookPayload, m as DropResponseBlock, n as DropScheduleSummary, o as EVENT_SUBTYPES, p as EventClass, q as EventSubtype, r as EventSubtypeMetadata, s as FederationStatus, t as IntegratorArchetype, u as IntegratorEventConfig, M as MAX_DROP_WINDOW_DAYS, v as MIN_INTEGRATOR_PRICE_SATS, w as PLATFORM_FEE_POLICY, x as SessionPolicy, y as SigningMethod, z as SiteFeeShape, G as SystemWebhookPayload, W as WebhookHeaders, H as WebhookPayload, J as computeFees, K as subtypesForClass, L as validateIntegratorConfig } from './integrator-VvKGegqS.mjs';
1
+ import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-6pjtyKYh.mjs';
2
+ export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-6pjtyKYh.mjs';
3
+ import { B as BillableEvent, E as EventKey, I as IntegratorPriceConfig, T as TelemetryEvent, S as SignInOptions, a as Session, P as PaymentAuthorizeOptions, b as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-C-enR55c.mjs';
4
+ export { c as ALL_EVENT_SUBTYPES, d as ARCHETYPE_TEMPLATES, e as AgentClassOverride, h as AttestTier, C as ClassASubtype, i as ClassBSubtype, j as ClassCSubtype, k as ComputedFees, D as DropCadence, l as DropClosedWebhookPayload, m as DropResponseBlock, n as DropScheduleSummary, o as EVENT_SUBTYPES, p as EventClass, q as EventSubtype, r as EventSubtypeMetadata, s as FederationStatus, t as IntegratorArchetype, u as IntegratorEventConfig, M as MAX_DROP_WINDOW_DAYS, v as MIN_INTEGRATOR_PRICE_SATS, w as PLATFORM_FEE_POLICY, x as SessionPolicy, y as SigningMethod, z as SiteFeeShape, G as SystemWebhookPayload, W as WebhookHeaders, H as WebhookPayload, J as computeFees, K as subtypesForClass, L as validateIntegratorConfig } from './integrator-C-enR55c.mjs';
5
5
 
6
6
  type Scope = 'bitcoin_address' | 'email' | 'attest_tier' | 'display_name' | 'cross_integrator_event_count' | 'cross_integrator_human_event_count' | 'trust_attestation_count';
7
7
  interface TrustAttestationCount {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-1VYMOhzV.js';
2
- export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-1VYMOhzV.js';
3
- import { B as BillableEvent, E as EventKey, I as IntegratorPriceConfig, T as TelemetryEvent, S as SignInOptions, a as Session, P as PaymentAuthorizeOptions, b as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-VvKGegqS.js';
4
- export { c as ALL_EVENT_SUBTYPES, d as ARCHETYPE_TEMPLATES, e as AgentClassOverride, h as AttestTier, C as ClassASubtype, i as ClassBSubtype, j as ClassCSubtype, k as ComputedFees, D as DropCadence, l as DropClosedWebhookPayload, m as DropResponseBlock, n as DropScheduleSummary, o as EVENT_SUBTYPES, p as EventClass, q as EventSubtype, r as EventSubtypeMetadata, s as FederationStatus, t as IntegratorArchetype, u as IntegratorEventConfig, M as MAX_DROP_WINDOW_DAYS, v as MIN_INTEGRATOR_PRICE_SATS, w as PLATFORM_FEE_POLICY, x as SessionPolicy, y as SigningMethod, z as SiteFeeShape, G as SystemWebhookPayload, W as WebhookHeaders, H as WebhookPayload, J as computeFees, K as subtypesForClass, L as validateIntegratorConfig } from './integrator-VvKGegqS.js';
1
+ import { v as verifyActivityAttestation, r as refreshEnvelopeJwks } from './identity-6pjtyKYh.js';
2
+ export { A as ActivityAttestation, a as ActivityAttestationBundle, b as ActivityVerifyCheck, c as ActivityVerifyResult, V as VerifyActivityOptions, i as identity } from './identity-6pjtyKYh.js';
3
+ import { B as BillableEvent, E as EventKey, I as IntegratorPriceConfig, T as TelemetryEvent, S as SignInOptions, a as Session, P as PaymentAuthorizeOptions, b as PaymentResult, V as ValidationResult, f as fromTemplate, g as getArchetypeTemplate, A as ArchetypeTemplate, F as Federation } from './integrator-C-enR55c.js';
4
+ export { c as ALL_EVENT_SUBTYPES, d as ARCHETYPE_TEMPLATES, e as AgentClassOverride, h as AttestTier, C as ClassASubtype, i as ClassBSubtype, j as ClassCSubtype, k as ComputedFees, D as DropCadence, l as DropClosedWebhookPayload, m as DropResponseBlock, n as DropScheduleSummary, o as EVENT_SUBTYPES, p as EventClass, q as EventSubtype, r as EventSubtypeMetadata, s as FederationStatus, t as IntegratorArchetype, u as IntegratorEventConfig, M as MAX_DROP_WINDOW_DAYS, v as MIN_INTEGRATOR_PRICE_SATS, w as PLATFORM_FEE_POLICY, x as SessionPolicy, y as SigningMethod, z as SiteFeeShape, G as SystemWebhookPayload, W as WebhookHeaders, H as WebhookPayload, J as computeFees, K as subtypesForClass, L as validateIntegratorConfig } from './integrator-C-enR55c.js';
5
5
 
6
6
  type Scope = 'bitcoin_address' | 'email' | 'attest_tier' | 'display_name' | 'cross_integrator_event_count' | 'cross_integrator_human_event_count' | 'trust_attestation_count';
7
7
  interface TrustAttestationCount {
package/dist/index.js CHANGED
@@ -1234,33 +1234,85 @@ async function verifyEd255192(key, sig, msg) {
1234
1234
  return false;
1235
1235
  }
1236
1236
  }
1237
+ var SIGNED_FIELDS = [
1238
+ "v",
1239
+ "kind",
1240
+ "did_oc",
1241
+ "event_count",
1242
+ "human_event_count",
1243
+ "lifetime_sats",
1244
+ "distinct_integrator_count",
1245
+ "oldest_event_at",
1246
+ "active_days",
1247
+ "computed_at",
1248
+ "expires_at"
1249
+ ];
1250
+ var COUNTS = [
1251
+ "event_count",
1252
+ "human_event_count",
1253
+ "lifetime_sats",
1254
+ "distinct_integrator_count",
1255
+ "active_days"
1256
+ ];
1257
+ function readSignedAttestation(canonical, id) {
1258
+ const text = new TextDecoder().decode(canonical);
1259
+ let parsed;
1260
+ try {
1261
+ parsed = JSON.parse(text);
1262
+ } catch {
1263
+ return null;
1264
+ }
1265
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
1266
+ const o = parsed;
1267
+ if (o.v !== 1 || o.kind !== "oc-me-activity" || typeof o.did_oc !== "string") return null;
1268
+ const countsOk = COUNTS.every((k) => {
1269
+ const n = o[k];
1270
+ return typeof n === "number" && Number.isSafeInteger(n) && n >= 0;
1271
+ });
1272
+ if (!countsOk) return null;
1273
+ if (o.oldest_event_at !== null && typeof o.oldest_event_at !== "string") return null;
1274
+ if (typeof o.computed_at !== "string" || typeof o.expires_at !== "string") return null;
1275
+ const ordered = Object.fromEntries(SIGNED_FIELDS.map((k) => [k, o[k]]));
1276
+ if (JSON.stringify(ordered) !== text) return null;
1277
+ return { id, ...ordered };
1278
+ }
1279
+ function sameAttestation(copy, signed) {
1280
+ const c = copy;
1281
+ const v = signed;
1282
+ return ["id", ...SIGNED_FIELDS].every((k) => c[k] === v[k]);
1283
+ }
1237
1284
  async function verifyActivityAttestation(bundle, options = {}) {
1238
1285
  const checks = [];
1239
- const shapeOk = !!bundle && typeof bundle === "object" && typeof bundle.sig === "string" && typeof bundle.kid === "string" && typeof bundle.canonical_b64 === "string" && !!bundle.attestation && typeof bundle.attestation.id === "string" && typeof bundle.attestation.expires_at === "string";
1286
+ 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");
1240
1287
  checks.push({
1241
1288
  ok: shapeOk,
1242
- label: "bundle shape \xB7 sig / kid / canonical_b64 / attestation"
1289
+ label: "bundle shape \xB7 sig / kid / canonical_b64"
1243
1290
  });
1244
1291
  if (!shapeOk) {
1245
1292
  return { ok: false, reason: "bundle shape invalid", checks };
1246
1293
  }
1247
- const a = bundle.attestation;
1248
1294
  const canonical = base64ToBytes(bundle.canonical_b64);
1249
1295
  checks.push({
1250
1296
  ok: canonical !== null,
1251
1297
  label: "canonical_b64 decodes",
1252
1298
  detail: canonical ? `${canonical.length} bytes` : "invalid base64"
1253
1299
  });
1254
- if (!canonical) return { ok: false, reason: "canonical_b64 invalid base64", checks, attestation: a };
1255
- const digest = await sha256(canonical);
1256
- const computedId = bytesToHex(digest);
1257
- const idOk = computedId === a.id;
1300
+ if (!canonical) return { ok: false, reason: "canonical_b64 invalid base64", checks };
1301
+ const computedId = bytesToHex(await sha256(canonical));
1302
+ const signed = readSignedAttestation(canonical, computedId);
1303
+ checks.push({
1304
+ ok: signed !== null,
1305
+ label: "canonical_bytes are an oc-me-activity attestation in canonical form"
1306
+ });
1307
+ if (!signed) return { ok: false, reason: "canonical bytes are not an activity attestation", checks };
1308
+ const copy = bundle.attestation;
1309
+ const copyOk = copy === void 0 || sameAttestation(copy, signed);
1258
1310
  checks.push({
1259
- ok: idOk,
1260
- label: "sha256(canonical_bytes) === id",
1261
- detail: idOk ? a.id : `expected ${a.id}, got ${computedId}`
1311
+ ok: copyOk,
1312
+ label: "attestation === the signed bytes, id = sha256(canonical_bytes)",
1313
+ detail: copyOk ? computedId : "the readable copy differs from what was signed"
1262
1314
  });
1263
- if (!idOk) return { ok: false, reason: "id does not match canonical-bytes hash", checks, attestation: a };
1315
+ if (!copyOk) return { ok: false, reason: "attestation does not match the signed bytes", checks };
1264
1316
  let key = null;
1265
1317
  if (options.jwk) {
1266
1318
  if (options.jwk.kid !== bundle.kid) {
@@ -1269,7 +1321,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1269
1321
  label: "JWK with matching kid present",
1270
1322
  detail: `provided jwk.kid=${options.jwk.kid} but bundle.kid=${bundle.kid}`
1271
1323
  });
1272
- return { ok: false, reason: "kid mismatch with provided jwk", checks, attestation: a };
1324
+ return { ok: false, reason: "kid mismatch with provided jwk", checks };
1273
1325
  }
1274
1326
  try {
1275
1327
  key = await importJWK(options.jwk, "EdDSA");
@@ -1280,7 +1332,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1280
1332
  label: "JWK with matching kid present",
1281
1333
  detail: `provided jwk failed import: ${err.message}`
1282
1334
  });
1283
- return { ok: false, reason: "provided jwk failed import", checks, attestation: a };
1335
+ return { ok: false, reason: "provided jwk failed import", checks };
1284
1336
  }
1285
1337
  } else {
1286
1338
  const issuer = options.issuer ?? DEFAULT_ISSUER2;
@@ -1299,7 +1351,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1299
1351
  detail: key ? `kid ${bundle.kid}` : `no JWK with kid ${bundle.kid} at ${issuer}${ENVELOPE_JWKS_PATH}`
1300
1352
  });
1301
1353
  if (!key) {
1302
- return { ok: false, reason: `kid ${bundle.kid} not in envelope JWKS`, checks, attestation: a };
1354
+ return { ok: false, reason: `kid ${bundle.kid} not in envelope JWKS`, checks };
1303
1355
  }
1304
1356
  } catch (err) {
1305
1357
  checks.push({
@@ -1310,8 +1362,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1310
1362
  return {
1311
1363
  ok: false,
1312
1364
  reason: `envelope JWKS unavailable: ${err.message}`,
1313
- checks,
1314
- attestation: a
1365
+ checks
1315
1366
  };
1316
1367
  }
1317
1368
  }
@@ -1322,7 +1373,7 @@ async function verifyActivityAttestation(bundle, options = {}) {
1322
1373
  label: "ed25519.verify(sig, canonical_bytes, jwk.public)",
1323
1374
  detail: "malformed sig (expected hex)"
1324
1375
  });
1325
- return { ok: false, reason: "malformed sig", checks, attestation: a };
1376
+ return { ok: false, reason: "malformed sig", checks };
1326
1377
  }
1327
1378
  const sigOk = await verifyEd255192(key, sigBytes, canonical);
1328
1379
  checks.push({
@@ -1330,17 +1381,17 @@ async function verifyActivityAttestation(bundle, options = {}) {
1330
1381
  label: "ed25519.verify(sig, canonical_bytes, jwk.public)",
1331
1382
  detail: sigOk ? "signature valid" : "signature does not match"
1332
1383
  });
1333
- if (!sigOk) return { ok: false, reason: "signature does not match", checks, attestation: a };
1384
+ if (!sigOk) return { ok: false, reason: "signature does not match", checks };
1334
1385
  const now = options.now ?? /* @__PURE__ */ new Date();
1335
- const expiresMs = Date.parse(a.expires_at);
1386
+ const expiresMs = Date.parse(signed.expires_at);
1336
1387
  const freshOk = Number.isFinite(expiresMs) && expiresMs > now.getTime();
1337
1388
  checks.push({
1338
1389
  ok: freshOk,
1339
1390
  label: "now < attestation.expires_at",
1340
1391
  detail: freshOk ? `expires ${new Date(expiresMs).toISOString()}` : "attestation has expired"
1341
1392
  });
1342
- if (!freshOk) return { ok: false, reason: "attestation has expired", checks, attestation: a };
1343
- return { ok: true, attestation: a, checks };
1393
+ if (!freshOk) return { ok: false, reason: "attestation has expired", checks };
1394
+ return { ok: true, attestation: signed, checks };
1344
1395
  }
1345
1396
  async function refreshEnvelopeJwks(issuer = DEFAULT_ISSUER2) {
1346
1397
  jwksCache2.delete(issuer);