@drakon-systems/ekho-sdk 0.6.1 → 0.7.0

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +4 -0
  3. package/dist/esm/identity/index.d.ts +5 -0
  4. package/dist/esm/identity/index.d.ts.map +1 -0
  5. package/dist/esm/identity/index.js +11 -0
  6. package/dist/esm/identity/index.js.map +1 -0
  7. package/dist/esm/identity/primitives.d.ts +53 -0
  8. package/dist/esm/identity/primitives.d.ts.map +1 -0
  9. package/dist/esm/identity/primitives.js +116 -0
  10. package/dist/esm/identity/primitives.js.map +1 -0
  11. package/dist/esm/identity/store.d.ts +67 -0
  12. package/dist/esm/identity/store.d.ts.map +1 -0
  13. package/dist/esm/identity/store.js +116 -0
  14. package/dist/esm/identity/store.js.map +1 -0
  15. package/dist/esm/identity/verification.d.ts +152 -0
  16. package/dist/esm/identity/verification.d.ts.map +1 -0
  17. package/dist/esm/identity/verification.js +492 -0
  18. package/dist/esm/identity/verification.js.map +1 -0
  19. package/dist/esm/identity/verify.d.ts +41 -0
  20. package/dist/esm/identity/verify.d.ts.map +1 -0
  21. package/dist/esm/identity/verify.js +92 -0
  22. package/dist/esm/identity/verify.js.map +1 -0
  23. package/dist/esm/types.d.ts +2 -0
  24. package/dist/esm/types.d.ts.map +1 -1
  25. package/dist/identity/index.d.ts +5 -0
  26. package/dist/identity/index.d.ts.map +1 -0
  27. package/dist/identity/index.js +27 -0
  28. package/dist/identity/index.js.map +1 -0
  29. package/dist/identity/primitives.d.ts +53 -0
  30. package/dist/identity/primitives.d.ts.map +1 -0
  31. package/dist/identity/primitives.js +133 -0
  32. package/dist/identity/primitives.js.map +1 -0
  33. package/dist/identity/store.d.ts +67 -0
  34. package/dist/identity/store.d.ts.map +1 -0
  35. package/dist/identity/store.js +127 -0
  36. package/dist/identity/store.js.map +1 -0
  37. package/dist/identity/verification.d.ts +152 -0
  38. package/dist/identity/verification.d.ts.map +1 -0
  39. package/dist/identity/verification.js +503 -0
  40. package/dist/identity/verification.js.map +1 -0
  41. package/dist/identity/verify.d.ts +41 -0
  42. package/dist/identity/verify.d.ts.map +1 -0
  43. package/dist/identity/verify.js +96 -0
  44. package/dist/identity/verify.js.map +1 -0
  45. package/dist/types.d.ts +2 -0
  46. package/dist/types.d.ts.map +1 -1
  47. package/package.json +11 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../src/identity/verification.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,503 @@
1
+ "use strict";
2
+ // Agent-side verification wiring (mirrors the Python plugin's verification.py):
3
+ // pin sync (endorsement-chained, no relay TOFU), per-message verdicts, the
4
+ // graceful execution-authority gate, and outbound signing.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NO_SNAPSHOT_VERIFICATION = exports.ADVISORY_REVOCATION_WARNING_MAX_SCOPES = exports.ADVISORY_REVOCATION_WARNING_SUMMARY_EVERY = void 0;
7
+ exports.resetAdvisoryRevocationWarningStateForTests = resetAdvisoryRevocationWarningStateForTests;
8
+ exports.syncPinnedOperatorKeys = syncPinnedOperatorKeys;
9
+ exports.verifyBatch = verifyBatch;
10
+ exports.parseRequireSignedMode = parseRequireSignedMode;
11
+ exports.shouldAutowake = shouldAutowake;
12
+ exports.buildSignedSendFields = buildSignedSendFields;
13
+ exports.makeSnapshotVerifier = makeSnapshotVerifier;
14
+ const primitives_js_1 = require("./primitives.js");
15
+ const verify_js_1 = require("./verify.js");
16
+ const store_js_1 = require("./store.js");
17
+ /** How many identical advisory polls to swallow before a reminder. ~5s poll
18
+ * → a reminder about every 10 minutes, not 150k lines in a day and a half. */
19
+ exports.ADVISORY_REVOCATION_WARNING_SUMMARY_EVERY = 120;
20
+ /** Process-local cap on identity+fleet throttle scopes. Eviction re-emits that
21
+ * scope's next first-seen warning; it cannot mute a different live scope. */
22
+ exports.ADVISORY_REVOCATION_WARNING_MAX_SCOPES = 64;
23
+ const MAX_ADVISORY_KEYS_IN_LOG = 8;
24
+ const MAX_ADVISORY_KID_CHARS = 32;
25
+ /** Process-local only. Keyed by identity public key + fleet so one box cannot
26
+ * mute another identity or fleet. Cleared when the advisory set goes empty. */
27
+ const advisoryWarnByScope = new Map();
28
+ /** Test-only isolation for the process-local Map. Not plugin runtime API. */
29
+ function resetAdvisoryRevocationWarningStateForTests() {
30
+ advisoryWarnByScope.clear();
31
+ }
32
+ function advisoryScopeKey(identity, fleetId) {
33
+ return `${(0, store_js_1.identityPublicKey)(identity)}\0${fleetId ?? ""}`;
34
+ }
35
+ function touchAdvisoryScope(scopeKey, entry) {
36
+ advisoryWarnByScope.delete(scopeKey);
37
+ advisoryWarnByScope.set(scopeKey, entry);
38
+ while (advisoryWarnByScope.size > exports.ADVISORY_REVOCATION_WARNING_MAX_SCOPES) {
39
+ const oldest = advisoryWarnByScope.keys().next().value;
40
+ if (oldest === undefined || oldest === scopeKey)
41
+ break;
42
+ advisoryWarnByScope.delete(oldest);
43
+ }
44
+ }
45
+ /** Relay-supplied key IDs are untrusted. Escape C0/C1 controls (U+0000–U+001F,
46
+ * U+007F–U+009F, including CSI/OSC) and Unicode line separators so each warning
47
+ * stays one bounded line; truncate the escaped form, never the raw id. */
48
+ function formatKidForLog(kid) {
49
+ let escaped = "";
50
+ for (const ch of kid) {
51
+ const code = ch.charCodeAt(0);
52
+ if (ch === "\\")
53
+ escaped += "\\\\";
54
+ else if (ch === "\n")
55
+ escaped += "\\n";
56
+ else if (ch === "\r")
57
+ escaped += "\\r";
58
+ else if (ch === "\t")
59
+ escaped += "\\t";
60
+ else if (ch === "\0")
61
+ escaped += "\\0";
62
+ else if (code < 0x20 || (code >= 0x7f && code <= 0x9f) || code === 0x2028 || code === 0x2029) {
63
+ escaped += `\\u${code.toString(16).padStart(4, "0")}`;
64
+ }
65
+ else {
66
+ escaped += ch;
67
+ }
68
+ }
69
+ if (escaped.length <= MAX_ADVISORY_KID_CHARS)
70
+ return escaped;
71
+ return `${escaped.slice(0, MAX_ADVISORY_KID_CHARS)}...`;
72
+ }
73
+ /** Bounded sample for the log line. Fingerprinting uses the complete sorted set. */
74
+ function formatAdvisoryKeyList(kids) {
75
+ const shown = kids.slice(0, MAX_ADVISORY_KEYS_IN_LOG).map(formatKidForLog);
76
+ const omitted = kids.length - shown.length;
77
+ const list = shown.join(", ");
78
+ if (omitted <= 0)
79
+ return list;
80
+ return `${list} (+${omitted} omitted)`;
81
+ }
82
+ function formatAdvisoryWarning(kids) {
83
+ if (kids.length === 1) {
84
+ return (`[ekho] relay reports operator key ${formatKidForLog(kids[0])} as REVOKED without a valid revocation signature. ` +
85
+ `Treating the claim as ADVISORY: the key is NOT unpinned and NOT tombstoned, but it will not ` +
86
+ `be newly adopted until a signed revocation arrives.`);
87
+ }
88
+ return (`[ekho] relay reports ${kids.length} operator keys as REVOKED without a valid revocation signature: ` +
89
+ `${formatAdvisoryKeyList(kids)}. Treating the claim as ADVISORY: the keys are NOT unpinned and NOT ` +
90
+ `tombstoned, but they will not be newly adopted until a signed revocation arrives.`);
91
+ }
92
+ function formatAdvisorySummary(kids, suppressed) {
93
+ return (`[ekho] still treating ${kids.length} unsigned/invalid operator-key revocation claim(s) as ADVISORY ` +
94
+ `(suppressed ${suppressed} identical warning(s) this process). Keys: ${formatAdvisoryKeyList(kids)}. ` +
95
+ `Not unpinned, not tombstoned; still blocking new adoption.`);
96
+ }
97
+ /** One aggregate warning when the advisory set appears or changes; identical
98
+ * repeats are silent; a bounded reminder keeps the condition visible; an empty
99
+ * set forgets the scope so a later recurrence is logged again. Trust is
100
+ * untouched — this is log volume only. */
101
+ function warnAdvisoryRevocations(ctx, advisory) {
102
+ if (advisory.size === 0) {
103
+ advisoryWarnByScope.delete(ctx.scopeKey);
104
+ return;
105
+ }
106
+ const kids = [...advisory].sort();
107
+ // Canonical JSON is unambiguous; NUL-join collides `["a\0b"]` with `["a","b"]`.
108
+ const fingerprint = (0, primitives_js_1.sha256Hex)(JSON.stringify(kids));
109
+ const prev = advisoryWarnByScope.get(ctx.scopeKey);
110
+ if (!prev || prev.fingerprint !== fingerprint) {
111
+ ctx.log?.warn?.(formatAdvisoryWarning(kids));
112
+ touchAdvisoryScope(ctx.scopeKey, { fingerprint, suppressed: 0 });
113
+ return;
114
+ }
115
+ prev.suppressed += 1;
116
+ if (prev.suppressed >= exports.ADVISORY_REVOCATION_WARNING_SUMMARY_EVERY) {
117
+ ctx.log?.warn?.(formatAdvisorySummary(kids, prev.suppressed));
118
+ prev.suppressed = 0;
119
+ touchAdvisoryScope(ctx.scopeKey, prev);
120
+ }
121
+ }
122
+ /** Apply the relay's revocation / un-revocation claims to the working trust root
123
+ * (#27). Mutates `pinned`, `revokedLedger` and `admissions` in place; a claim
124
+ * only lands if a currently pinned operator key signed it. */
125
+ function applyRelayKeyClaims(ctx) {
126
+ const out = {
127
+ advisory: new Set(),
128
+ pinRemoved: false,
129
+ ledgerChanged: false,
130
+ admissionsChanged: false
131
+ };
132
+ clearTombstonesOnSignedUnrevoke(ctx, out);
133
+ applySignedRevocations(ctx, out);
134
+ warnAdvisoryRevocations(ctx, out.advisory);
135
+ return out;
136
+ }
137
+ /** A SIGNED un-revoke clears a tombstone so the key can be re-admitted through
138
+ * the endorsement chain. It never re-pins by itself — re-admission still costs
139
+ * a valid endorsement. Runs before the revocation pass so a valid revocation in
140
+ * the same batch still wins (fail closed).
141
+ *
142
+ * The unsigned ABSENCE of `revoked` must never clear a tombstone: that was the
143
+ * #14 hole, where a relay could resurrect a dead key just by not mentioning it.
144
+ *
145
+ * #48: the payload now binds revoked_at_being_cleared + issued_at + nonce.
146
+ * Missing bind fields refuse the un-revoke (fail closed). The relay still
147
+ * does not emit unrevoke_sig. */
148
+ function clearTombstonesOnSignedUnrevoke(ctx, out) {
149
+ for (const k of ctx.operatorKeys) {
150
+ const kid = k.key_id;
151
+ const sig = k.unrevoke_sig;
152
+ const revokedAt = k.unrevoke_revoked_at;
153
+ const issuedAt = k.unrevoke_issued_at;
154
+ const nonce = k.unrevoke_nonce;
155
+ if (!kid || !sig || !ctx.revokedLedger[kid])
156
+ continue;
157
+ if (!revokedAt || !issuedAt || !nonce) {
158
+ ctx.log?.warn?.(`[ekho] refusing un-revoke of operator key ${kid}: payload bind fields missing. ` +
159
+ `The tombstone stands.`);
160
+ continue;
161
+ }
162
+ if (!ctx.fleetId || !ctx.signedByAPinnedKey((0, primitives_js_1.unrevokePayload)(ctx.fleetId, kid, revokedAt, issuedAt, nonce), sig)) {
163
+ ctx.log?.warn?.(`[ekho] refusing un-revoke of operator key ${kid}: no currently pinned operator key signed it. ` +
164
+ `The tombstone stands.`);
165
+ continue;
166
+ }
167
+ // #52: the compare half of the compare-and-swap. Signing over
168
+ // revoked_at_being_cleared is only worth anything if apply-time checks it
169
+ // against the tombstone actually standing right now — otherwise a valid
170
+ // un-revoke captured for an OLD revocation clears whatever NEWER one has
171
+ // replaced it.
172
+ if (revokedAt !== ctx.revokedLedger[kid]) {
173
+ ctx.log?.warn?.(`[ekho] refusing un-revoke of operator key ${kid}: it is bound to a revocation at ${revokedAt}, ` +
174
+ `but the live tombstone is at ${ctx.revokedLedger[kid]} — a newer revocation this un-revoke ` +
175
+ `never authorized. The tombstone stands.`);
176
+ continue;
177
+ }
178
+ delete ctx.revokedLedger[kid];
179
+ out.ledgerChanged = true;
180
+ ctx.log?.info?.(`[ekho] operator key ${kid} un-revoked by a signed operator instruction; tombstone cleared. ` +
181
+ `The key is NOT re-pinned — it has to be re-endorsed by a pinned key.`);
182
+ }
183
+ }
184
+ /** A SIGNED revocation is the only thing that can remove trust. Anything less is
185
+ * recorded as advisory: the key is skipped for new adoption and nothing else. */
186
+ function applySignedRevocations(ctx, out) {
187
+ for (const k of ctx.operatorKeys) {
188
+ const kid = k.key_id;
189
+ if (!kid || !k.revoked)
190
+ continue;
191
+ const at = k.revoked_at;
192
+ const sig = k.revocation_sig;
193
+ const proven = Boolean(sig && at && ctx.fleetId && ctx.signedByAPinnedKey((0, primitives_js_1.revocationPayload)(ctx.fleetId, kid, at), sig));
194
+ if (!proven) {
195
+ noteAdvisoryClaim(out, kid);
196
+ }
197
+ else if (isLastPinnedKey(ctx, kid)) {
198
+ noteLastRootRefusal(ctx, kid);
199
+ }
200
+ else {
201
+ dropRevokedKey(ctx, out, kid, at);
202
+ }
203
+ }
204
+ }
205
+ /** The relay says a key is dead but cannot prove it. Skip the key for NEW
206
+ * adoption, write nothing. Visibility is the process-local aggregate throttle
207
+ * in warnAdvisoryRevocations — not a per-key line on every poll.
208
+ *
209
+ * Deleting the pin here is the tempting one-liner and it is wrong twice over:
210
+ * it lets whoever controls the relay drop trust unilaterally, AND a deleted pin
211
+ * is re-admitted on the very next poll by the same still-valid endorsement.
212
+ * Rejecting a key takes a revokedOperatorKeys tombstone, not a deletion — and a
213
+ * tombstone takes a signature. */
214
+ function noteAdvisoryClaim(out, kid) {
215
+ out.advisory.add(kid);
216
+ }
217
+ function isLastPinnedKey(ctx, kid) {
218
+ return Boolean(ctx.pinned[kid]) && Object.keys(ctx.pinned).length === 1;
219
+ }
220
+ /** Last-root protection: honoring this would leave the box with no trust root at
221
+ * all — indistinguishable from the attack the signature requirement just
222
+ * closed. Refuse the claim whole, so we never hold a key that is tombstoned
223
+ * (unrecoverable) and still pinned (still trusted). */
224
+ function noteLastRootRefusal(ctx, kid) {
225
+ ctx.log?.warn?.(`[ekho] refusing the signed revocation of operator key ${kid}: it is the LAST pinned operator key, ` +
226
+ `and honoring it would leave this agent with no trust root at all. Endorse a replacement key ` +
227
+ `first — the replacement makes this revocation safe to honor on the next poll.`);
228
+ }
229
+ /** Honor a proven revocation: tombstone, then unpin.
230
+ *
231
+ * #14: the tombstone is the durable half. Unpinning alone never made a
232
+ * revocation stick — the config seed re-added the key on the very next wake,
233
+ * and TOFU/chaining would too. */
234
+ function dropRevokedKey(ctx, out, kid, at) {
235
+ if (!ctx.revokedLedger[kid]) {
236
+ ctx.revokedLedger[kid] = at;
237
+ out.ledgerChanged = true;
238
+ }
239
+ if (ctx.pinned[kid]) {
240
+ Reflect.deleteProperty(ctx.pinned, kid);
241
+ out.pinRemoved = true;
242
+ ctx.log?.warn?.(`[ekho] operator key ${kid} is revoked (signed, at ${at}); it is no longer pinned.`);
243
+ }
244
+ if (ctx.admissions[kid]) {
245
+ // The admission record answers "why is this key trusted here?" — keep it
246
+ // only while the answer is "it is".
247
+ Reflect.deleteProperty(ctx.admissions, kid);
248
+ out.admissionsChanged = true;
249
+ }
250
+ }
251
+ /** Update pinned operator keys from the inbox. Adds a new key ONLY if endorsed by
252
+ * an already-pinned key; removes one ONLY on a SIGNED revocation. Returns true
253
+ * if the identity changed (and so must be persisted).
254
+ *
255
+ * Trust mutates in one direction only, and never on the relay's say-so (#27).
256
+ * An unsigned `revoked: true` is a HINT: the key is skipped for new adoption
257
+ * and the claim is logged, but nothing is written and nothing is unpinned.
258
+ * Treating it as authoritative (the #14 regression) meant one poll from a
259
+ * compromised relay could tombstone and unpin an entire fleet's trust root,
260
+ * permanently — the tombstone survives restarts by design, so the damage was
261
+ * not even recoverable by restarting against an honest relay.
262
+ *
263
+ * One deliberate exception to "no relay TOFU" (#5): an identity that has never
264
+ * pinned ANY key can't grow a chain — endorsements need an already-pinned root,
265
+ * so verification stayed dormant forever on every agent nobody hand-configured
266
+ * (the Aug 2026 silent-drop incident). First contact with an empty pin set
267
+ * adopts the relay's current non-revoked keys as the trust root, exactly once
268
+ * (tofuAt latches). Enrollment already trusts the relay this much — it accepts
269
+ * the shared secret over the same channel. Pre-pinning via config/env skips
270
+ * TOFU entirely and stays the stronger option. */
271
+ function syncPinnedOperatorKeys(identity, operatorKeys, fleetId, log = console) {
272
+ const pinned = { ...identity.pinnedOperatorKeys };
273
+ const revokedLedger = { ...(identity.revokedOperatorKeys ?? {}) };
274
+ const admissions = { ...(identity.operatorKeyAdmissions ?? {}) };
275
+ // The keys allowed to authorize a trust-root mutation this poll, snapshotted
276
+ // BEFORE any of them are applied. Frozen on purpose: verifying against the
277
+ // live map would make the outcome depend on the order the relay happened to
278
+ // serve its entries in, which is the relay's choice, not ours.
279
+ const authorities = { ...identity.pinnedOperatorKeys };
280
+ const signedByAPinnedKey = (payload, sig) => {
281
+ for (const pub of Object.values(authorities)) {
282
+ if ((0, primitives_js_1.verifyCanonical)(payload, sig, (0, primitives_js_1.fromB64url)(pub)))
283
+ return true;
284
+ }
285
+ return false;
286
+ };
287
+ // Phases 1 and 2 (#27) — mutates `pinned` / `revokedLedger` / `admissions` in
288
+ // place and reports back what it touched.
289
+ const claims = applyRelayKeyClaims({
290
+ operatorKeys,
291
+ fleetId,
292
+ log,
293
+ pinned,
294
+ revokedLedger,
295
+ admissions,
296
+ signedByAPinnedKey,
297
+ scopeKey: advisoryScopeKey(identity, fleetId)
298
+ });
299
+ const advisory = claims.advisory;
300
+ let changed = claims.pinRemoved;
301
+ let admissionsChanged = claims.admissionsChanged;
302
+ if (claims.ledgerChanged) {
303
+ identity.revokedOperatorKeys = revokedLedger;
304
+ changed = true; // must persist, even when the key was never pinned here
305
+ }
306
+ if (Object.keys(pinned).length === 0 && !identity.tofuAt) {
307
+ let adopted = false;
308
+ const at = new Date().toISOString();
309
+ for (const k of operatorKeys) {
310
+ if (k.key_id && k.public_key && !advisory.has(k.key_id) && !revokedLedger[k.key_id]) {
311
+ pinned[k.key_id] = k.public_key;
312
+ admissions[k.key_id] = { admitted_by: "tofu", admitted_at: at }; // #26
313
+ admissionsChanged = true;
314
+ adopted = true;
315
+ }
316
+ }
317
+ if (adopted) {
318
+ // Latch only when something was adopted — an empty roster now must not
319
+ // burn the one TOFU opportunity of a fresh identity. (Tracked separately
320
+ // from `changed`, which a revocation tombstone alone can now set.)
321
+ identity.tofuAt = at;
322
+ identity.pinnedOperatorKeys = pinned;
323
+ identity.operatorKeyAdmissions = admissions;
324
+ return true;
325
+ }
326
+ }
327
+ for (const k of operatorKeys) {
328
+ const kid = k.key_id;
329
+ if (!kid)
330
+ continue;
331
+ if (pinned[kid])
332
+ continue;
333
+ if (revokedLedger[kid])
334
+ continue; // #14: a tombstoned key never comes back
335
+ if (advisory.has(kid))
336
+ continue; // #27: claimed-revoked → no NEW adoption
337
+ const endorser = k.endorsed_by_key_id;
338
+ const esig = k.endorsement_sig;
339
+ const pub = k.public_key;
340
+ if (endorser && esig && pub && fleetId && pinned[endorser]) {
341
+ if ((0, primitives_js_1.verifyCanonical)((0, primitives_js_1.endorsementPayload)(fleetId, kid, pub), esig, (0, primitives_js_1.fromB64url)(pinned[endorser]))) {
342
+ pinned[kid] = pub;
343
+ changed = true;
344
+ // #26: keep the endorsement we just verified, so this box can answer
345
+ // "why is this key trusted here?" offline — the relay is exactly the
346
+ // party we would otherwise have to ask.
347
+ admissions[kid] = {
348
+ admitted_by: "chain",
349
+ endorsed_by_key_id: endorser,
350
+ endorsement_sig: esig,
351
+ admitted_at: new Date().toISOString()
352
+ };
353
+ admissionsChanged = true;
354
+ }
355
+ }
356
+ }
357
+ if (changed)
358
+ identity.pinnedOperatorKeys = pinned;
359
+ if (admissionsChanged) {
360
+ identity.operatorKeyAdmissions = admissions;
361
+ changed = true;
362
+ }
363
+ return changed;
364
+ }
365
+ function verifyBatch(messages, opts) {
366
+ const operatorKeys = { ...(opts.identity.pinnedOperatorKeys ?? {}) };
367
+ const out = {};
368
+ if (Object.keys(operatorKeys).length === 0 || !opts.fleetId) {
369
+ for (const m of messages)
370
+ out[String(m.message_id)] = null;
371
+ return out;
372
+ }
373
+ const rosterByAgent = {};
374
+ for (const r of opts.roster)
375
+ if (r.agent_id)
376
+ rosterByAgent[String(r.agent_id)] = r;
377
+ for (const m of messages) {
378
+ out[String(m.message_id)] = (0, verify_js_1.verifyInbound)(m, {
379
+ selfAgentId: opts.selfAgentId,
380
+ fleetId: opts.fleetId,
381
+ operatorKeys,
382
+ rosterByAgent,
383
+ seenNonces: opts.seenNonces,
384
+ now: opts.now
385
+ });
386
+ }
387
+ return out;
388
+ }
389
+ function parseRequireSignedMode(raw) {
390
+ const v = String(raw ?? "").trim().toLowerCase();
391
+ return v === "require" || v === "off" ? v : "warn";
392
+ }
393
+ /** The execution-authority gate. Signed → act iff verified; signed-but-invalid →
394
+ * blocked; unsigned → per requireSigned mode (see above). */
395
+ function shouldAutowake(msg, verification, operatorTrusted, peerEnabled, requireSigned = "warn") {
396
+ const isOperator = msg.sender_kind === "operator";
397
+ const signed = Boolean(isOperator ? msg.operator_sig : msg.agent_sig);
398
+ if (isOperator) {
399
+ if (signed && verification)
400
+ return Boolean(verification.verified);
401
+ return Boolean(operatorTrusted);
402
+ }
403
+ if (!peerEnabled)
404
+ return false;
405
+ if (requireSigned === "require") {
406
+ // Fail closed: signed AND verified, nothing less. A null verification
407
+ // (no pinned keys yet) is exactly the dormant state this mode refuses
408
+ // to treat as trustworthy.
409
+ return Boolean(signed && verification && verification.verified);
410
+ }
411
+ if (signed && verification)
412
+ return Boolean(verification.verified);
413
+ return true;
414
+ }
415
+ /** Sign an outbound peer message so recipients can verify it came from us.
416
+ *
417
+ * v2 (#9) extends coverage to message_type, priority and the attachment ids —
418
+ * previously a compromised relay could relabel a message (direct → alert) or
419
+ * swap its attachments under a still-valid signature. Compatibility is free in
420
+ * both directions: verifiers check the signature over the WHOLE canonical and
421
+ * only bind the fields they know, so old verifiers accept v2 envelopes and new
422
+ * verifiers enforce the extra bindings only when the envelope declares v>=2. */
423
+ function buildSignedSendFields(opts) {
424
+ const seed = new Uint8Array(Buffer.from(opts.identity.seedHex, "hex"));
425
+ const kid = (0, primitives_js_1.keyId)((0, primitives_js_1.fromB64url)((0, primitives_js_1.publicKeyB64urlFromSeed)(seed)));
426
+ const canonical = {
427
+ v: 2,
428
+ fleet_id: opts.fleetId,
429
+ sender_agent_id: opts.selfAgentId,
430
+ key_id: kid,
431
+ recipient: opts.recipient,
432
+ conversation_id: opts.conversationId,
433
+ body_sha256: (0, primitives_js_1.sha256Hex)(opts.bodyText),
434
+ sent_at: opts.sentAt,
435
+ nonce: opts.nonce,
436
+ message_type: opts.messageType,
437
+ priority: opts.priority,
438
+ attachments: [...(opts.attachments ?? [])].sort()
439
+ };
440
+ return { agent_sig: (0, primitives_js_1.signCanonical)(canonical, seed), key_id: kid, sig_canonical: canonical };
441
+ }
442
+ /** The fail-closed default (#20): when verification cannot run — no pinned
443
+ * operator keys, no fleet id, no identity — every snapshot is UNVERIFIED.
444
+ * Never "it has a signature field, so call it signed". */
445
+ const NO_SNAPSHOT_VERIFICATION = () => false;
446
+ exports.NO_SNAPSHOT_VERIFICATION = NO_SNAPSHOT_VERIFICATION;
447
+ /**
448
+ * Build the snapshot verifier for one turn, from the same trust root the
449
+ * autowake path uses: this agent's pinned operator keys plus the batch roster.
450
+ *
451
+ * Runs the ordinary inbound verifier (`verifyInbound`) over a snapshot mapped
452
+ * into its `SignedMessage` shape — there is deliberately no second, laxer
453
+ * verifier for quoted text. Two consequences worth naming:
454
+ *
455
+ * - An older relay that omits `sig_canonical` (or the v2-bound `message_type` /
456
+ * `priority` / `attachments`) simply fails the checks, so its snapshots read
457
+ * UNVERIFIED. That is the intended direction to fail in.
458
+ * - The nonce set is fresh per turn rather than the live seen-nonce set. A
459
+ * quote is by definition a re-presentation of a message that may already
460
+ * have been delivered and had its nonce burned; the burn exists to stop a
461
+ * replayed message WAKING a turn, and a snapshot can never wake one. The
462
+ * staleness window is left at the verifier's default, so a snapshot replayed
463
+ * from beyond it still reads UNVERIFIED.
464
+ */
465
+ function makeSnapshotVerifier(opts) {
466
+ const operatorKeys = { ...(opts.identity?.pinnedOperatorKeys ?? {}) };
467
+ const fleetId = opts.fleetId;
468
+ if (Object.keys(operatorKeys).length === 0 || !fleetId)
469
+ return exports.NO_SNAPSHOT_VERIFICATION;
470
+ const rosterByAgent = {};
471
+ for (const r of opts.roster ?? [])
472
+ if (r.agent_id)
473
+ rosterByAgent[String(r.agent_id)] = r;
474
+ return (snapshot) => {
475
+ if (!snapshot || typeof snapshot !== "object")
476
+ return false;
477
+ const asMessage = {
478
+ message_id: snapshot.message_id,
479
+ sender_kind: snapshot.sender_kind,
480
+ sender_agent_id: snapshot.sender_agent_id,
481
+ message_type: snapshot.message_type,
482
+ priority: snapshot.priority,
483
+ // `text` -> `body.text`: body_sha256 must bind the snapshot's own text.
484
+ body: {
485
+ text: typeof snapshot.text === "string" ? snapshot.text : "",
486
+ attachments: Array.isArray(snapshot.attachments) ? snapshot.attachments : []
487
+ },
488
+ operator_sig: snapshot.operator_sig ?? null,
489
+ agent_sig: snapshot.agent_sig ?? null,
490
+ key_id: snapshot.key_id ?? null,
491
+ sig_canonical: snapshot.sig_canonical ?? null
492
+ };
493
+ return (0, verify_js_1.verifyInbound)(asMessage, {
494
+ selfAgentId: opts.selfAgentId,
495
+ fleetId,
496
+ operatorKeys,
497
+ rosterByAgent,
498
+ seenNonces: new Set(),
499
+ now: opts.now
500
+ }).verified;
501
+ };
502
+ }
503
+ //# sourceMappingURL=verification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification.js","sourceRoot":"","sources":["../../src/identity/verification.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export interface SignedMessage {
2
+ message_id?: string;
3
+ sender_kind?: string;
4
+ sender_agent_id?: string;
5
+ message_type?: string;
6
+ priority?: string;
7
+ body?: {
8
+ text?: string;
9
+ } & Record<string, unknown>;
10
+ operator_sig?: string | null;
11
+ agent_sig?: string | null;
12
+ key_id?: string | null;
13
+ sig_canonical?: Record<string, unknown> | null;
14
+ }
15
+ export interface RosterEntryLike {
16
+ agent_id?: string;
17
+ identity_public_key?: string | null;
18
+ key_id?: string | null;
19
+ endorsed_by_key_id?: string | null;
20
+ endorsement_sig?: string | null;
21
+ }
22
+ export interface VerifyResult {
23
+ verified: boolean;
24
+ kind: "operator" | "peer";
25
+ reason: string | null;
26
+ keyId: string | null;
27
+ }
28
+ export interface VerifyOpts {
29
+ selfAgentId: string;
30
+ fleetId: string;
31
+ operatorKeys: Record<string, string>;
32
+ rosterByAgent: Record<string, RosterEntryLike>;
33
+ seenNonces: Set<string>;
34
+ now: Date;
35
+ maxSkewSeconds?: number;
36
+ maxFutureSkewSeconds?: number;
37
+ }
38
+ export declare const MAX_PAST_SKEW_SECONDS: number;
39
+ export declare const MAX_FUTURE_SKEW_SECONDS = 300;
40
+ export declare function verifyInbound(msg: SignedMessage, opts: VerifyOpts): VerifyResult;
41
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/identity/verify.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC/C,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxB,GAAG,EAAE,IAAI,CAAC;IACV,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AASD,eAAO,MAAM,qBAAqB,QAAc,CAAC;AACjD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,YAAY,CA8EhF"}