@sumicom/quicksave 0.7.1 → 0.8.1

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 (60) hide show
  1. package/dist/ai/claudeCliProvider.d.ts.map +1 -1
  2. package/dist/ai/claudeCliProvider.js +8 -11
  3. package/dist/ai/claudeCliProvider.js.map +1 -1
  4. package/dist/ai/claudeSdkProvider.d.ts.map +1 -1
  5. package/dist/ai/claudeSdkProvider.js +9 -14
  6. package/dist/ai/claudeSdkProvider.js.map +1 -1
  7. package/dist/ai/enrichEntry.d.ts +11 -0
  8. package/dist/ai/enrichEntry.d.ts.map +1 -0
  9. package/dist/ai/enrichEntry.js +27 -0
  10. package/dist/ai/enrichEntry.js.map +1 -0
  11. package/dist/ai/provider.d.ts +6 -0
  12. package/dist/ai/provider.d.ts.map +1 -1
  13. package/dist/ai/sandboxMcp.d.ts +41 -3
  14. package/dist/ai/sandboxMcp.d.ts.map +1 -1
  15. package/dist/ai/sandboxMcp.js +44 -3
  16. package/dist/ai/sandboxMcp.js.map +1 -1
  17. package/dist/ai/sandboxMcpStdio.js +103 -9
  18. package/dist/ai/sandboxMcpStdio.js.map +1 -1
  19. package/dist/ai/sessionManager.d.ts +14 -2
  20. package/dist/ai/sessionManager.d.ts.map +1 -1
  21. package/dist/ai/sessionManager.js +141 -19
  22. package/dist/ai/sessionManager.js.map +1 -1
  23. package/dist/ai/sessionRegistry.d.ts +57 -6
  24. package/dist/ai/sessionRegistry.d.ts.map +1 -1
  25. package/dist/ai/sessionRegistry.js +237 -31
  26. package/dist/ai/sessionRegistry.js.map +1 -1
  27. package/dist/config.d.ts +41 -0
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +86 -0
  30. package/dist/config.js.map +1 -1
  31. package/dist/connection/connection.d.ts +61 -0
  32. package/dist/connection/connection.d.ts.map +1 -1
  33. package/dist/connection/connection.js +274 -1
  34. package/dist/connection/connection.js.map +1 -1
  35. package/dist/connection/relay.d.ts +20 -0
  36. package/dist/connection/relay.d.ts.map +1 -1
  37. package/dist/connection/relay.js +62 -1
  38. package/dist/connection/relay.js.map +1 -1
  39. package/dist/handlers/messageHandler.d.ts +18 -0
  40. package/dist/handlers/messageHandler.d.ts.map +1 -1
  41. package/dist/handlers/messageHandler.js +72 -3
  42. package/dist/handlers/messageHandler.js.map +1 -1
  43. package/dist/index.js +60 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/service/ipcClient.js +1 -1
  46. package/dist/service/ipcServer.d.ts.map +1 -1
  47. package/dist/service/ipcServer.js +10 -4
  48. package/dist/service/ipcServer.js.map +1 -1
  49. package/dist/service/run.d.ts.map +1 -1
  50. package/dist/service/run.js +69 -21
  51. package/dist/service/run.js.map +1 -1
  52. package/dist/service/types.d.ts +15 -0
  53. package/dist/service/types.d.ts.map +1 -1
  54. package/dist/service/types.js +6 -2
  55. package/dist/service/types.js.map +1 -1
  56. package/dist/tombstoneCheck.d.ts +43 -0
  57. package/dist/tombstoneCheck.d.ts.map +1 -0
  58. package/dist/tombstoneCheck.js +96 -0
  59. package/dist/tombstoneCheck.js.map +1 -0
  60. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"sessionRegistry.js","sourceRoot":"","sources":["../../src/ai/sessionRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessionRegistry.js","sourceRoot":"","sources":["../../src/ai/sessionRegistry.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -9,6 +9,24 @@ export interface AgentConfig {
9
9
  publicKey: string;
10
10
  secretKey: string;
11
11
  };
12
+ /**
13
+ * TOFU-pinned PWA group identity. `null` on a fresh / closed agent, which
14
+ * accepts the first successful V2 handshake as the trust anchor and writes
15
+ * both fields here. Once pinned, subsequent handshakes must prove possession
16
+ * of the same Ed25519 signing key before they are accepted.
17
+ *
18
+ * Cleared (set back to `null`) when a tombstone is observed on the pinned
19
+ * mailbox — the agent then enters the "closed" state until the user runs
20
+ * `quicksave pair` again.
21
+ */
22
+ peerPWAPublicKey?: string | null;
23
+ peerPWASignPublicKey?: string | null;
24
+ /**
25
+ * Sticky self-destruct flag set after a verified tombstone. Persists across
26
+ * daemon restarts so a crash/restart window can't silently re-open TOFU.
27
+ * Cleared only by `unlockPairingAndRotate()` (driven by `quicksave pair`).
28
+ */
29
+ closed?: boolean;
12
30
  license?: License;
13
31
  signalingServer: string;
14
32
  anthropicApiKey?: string;
@@ -36,4 +54,27 @@ export declare function removeManagedCodingPath(path: string): void;
36
54
  * This invalidates all existing PWA connections.
37
55
  */
38
56
  export declare function rotateKeyPair(): AgentConfig;
57
+ /** True iff the agent has TOFU-pinned a PWA group identity. */
58
+ export declare function isPaired(config?: AgentConfig): boolean;
59
+ /**
60
+ * Pin the given PWA group identity as this agent's trust anchor. Idempotent
61
+ * if the same pair is already stored; throws if a *different* pair is already
62
+ * pinned (caller must `clearPeerPWA` first, which is the tombstone path).
63
+ */
64
+ export declare function pinPeerPWA(peerPWAPublicKey: string, peerPWASignPublicKey: string): AgentConfig;
65
+ /**
66
+ * Forget the pinned PWA group identity. Called when a signed tombstone is
67
+ * observed on the pinned mailbox. Rotates the agent's entire cryptographic
68
+ * identity (`agentId`, X25519 box keypair, Ed25519 signing keypair) so the
69
+ * old routing address and keys can no longer be used, and sets `closed: true`
70
+ * so the agent refuses every inbound handshake until `quicksave pair`.
71
+ */
72
+ export declare function clearPeerPWA(): AgentConfig;
73
+ /**
74
+ * Lift the `closed` gate and produce a fresh agent identity. Called by the
75
+ * `quicksave pair` CLI path: even if the agent was already in a fresh state
76
+ * after tombstone, rotating again here means each new pairing attempt comes
77
+ * with an unburdened identity — no lingering state from prior pairings.
78
+ */
79
+ export declare function unlockPairingAndRotate(): AgentConfig;
39
80
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0D,KAAK,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGjH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAID,wBAAgB,eAAe,IAAI,IAAI,CAKtC;AAED,wBAAgB,UAAU,IAAI,WAAW,GAAG,IAAI,CAU/C;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGpD;AAED,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,WAAW,CASxE;AAED,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,WAAW,CAsBtE;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAMjD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAGD,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAMvD;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAGD,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQjD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAUpD;AAGD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQvD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAU1D;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,WAAW,CAQ3C"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0D,KAAK,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGjH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAID,wBAAgB,eAAe,IAAI,IAAI,CAKtC;AAED,wBAAgB,UAAU,IAAI,WAAW,GAAG,IAAI,CAU/C;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGpD;AAED,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,WAAW,CAYxE;AAED,wBAAgB,iBAAiB,CAAC,eAAe,EAAE,MAAM,GAAG,WAAW,CAmCtE;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAMjD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAGD,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAMvD;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAGD,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQjD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAUpD;AAGD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQvD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAU1D;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,WAAW,CAQ3C;AAED,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,MAAM,GAAE,WAA2B,GAAG,OAAO,CAMrE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,gBAAgB,EAAE,MAAM,EACxB,oBAAoB,EAAE,MAAM,GAC3B,WAAW,CAqBb;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,WAAW,CAa1C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,WAAW,CAapD"}
package/dist/config.js CHANGED
@@ -30,6 +30,9 @@ export function createDefaultConfig(signalingServer) {
30
30
  agentId: generateAgentId(),
31
31
  keyPair: generateAgentKeyPair(),
32
32
  signKeyPair: encodeKeyPair(generateSigningKeyPair()),
33
+ peerPWAPublicKey: null,
34
+ peerPWASignPublicKey: null,
35
+ closed: false,
33
36
  signalingServer,
34
37
  };
35
38
  saveConfig(config);
@@ -49,6 +52,19 @@ export function getOrCreateConfig(signalingServer) {
49
52
  config.signKeyPair = encodeKeyPair(generateSigningKeyPair());
50
53
  dirty = true;
51
54
  }
55
+ // Pre-TOFU configs are legacy unpaired → normalize missing fields to null.
56
+ if (config.peerPWAPublicKey === undefined) {
57
+ config.peerPWAPublicKey = null;
58
+ dirty = true;
59
+ }
60
+ if (config.peerPWASignPublicKey === undefined) {
61
+ config.peerPWASignPublicKey = null;
62
+ dirty = true;
63
+ }
64
+ if (config.closed === undefined) {
65
+ config.closed = false;
66
+ dirty = true;
67
+ }
52
68
  if (config.signalingServer !== signalingServer) {
53
69
  config.signalingServer = signalingServer;
54
70
  dirty = true;
@@ -145,4 +161,74 @@ export function rotateKeyPair() {
145
161
  saveConfig(config);
146
162
  return config;
147
163
  }
164
+ /** True iff the agent has TOFU-pinned a PWA group identity. */
165
+ export function isPaired(config = loadConfig()) {
166
+ return (!!config &&
167
+ !!config.peerPWAPublicKey &&
168
+ !!config.peerPWASignPublicKey);
169
+ }
170
+ /**
171
+ * Pin the given PWA group identity as this agent's trust anchor. Idempotent
172
+ * if the same pair is already stored; throws if a *different* pair is already
173
+ * pinned (caller must `clearPeerPWA` first, which is the tombstone path).
174
+ */
175
+ export function pinPeerPWA(peerPWAPublicKey, peerPWASignPublicKey) {
176
+ const config = loadConfig();
177
+ if (!config) {
178
+ throw new Error('No config found. Run the agent first to generate a config.');
179
+ }
180
+ if (config.peerPWAPublicKey && config.peerPWASignPublicKey) {
181
+ if (config.peerPWAPublicKey === peerPWAPublicKey &&
182
+ config.peerPWASignPublicKey === peerPWASignPublicKey) {
183
+ return config;
184
+ }
185
+ throw new Error('Agent is already paired with a different PWA group identity. ' +
186
+ 'Clear the pairing (rotate-keys tombstone or manual reset) first.');
187
+ }
188
+ config.peerPWAPublicKey = peerPWAPublicKey;
189
+ config.peerPWASignPublicKey = peerPWASignPublicKey;
190
+ saveConfig(config);
191
+ return config;
192
+ }
193
+ /**
194
+ * Forget the pinned PWA group identity. Called when a signed tombstone is
195
+ * observed on the pinned mailbox. Rotates the agent's entire cryptographic
196
+ * identity (`agentId`, X25519 box keypair, Ed25519 signing keypair) so the
197
+ * old routing address and keys can no longer be used, and sets `closed: true`
198
+ * so the agent refuses every inbound handshake until `quicksave pair`.
199
+ */
200
+ export function clearPeerPWA() {
201
+ const config = loadConfig();
202
+ if (!config) {
203
+ throw new Error('No config found.');
204
+ }
205
+ config.peerPWAPublicKey = null;
206
+ config.peerPWASignPublicKey = null;
207
+ config.agentId = generateAgentId();
208
+ config.keyPair = generateAgentKeyPair();
209
+ config.signKeyPair = encodeKeyPair(generateSigningKeyPair());
210
+ config.closed = true;
211
+ saveConfig(config);
212
+ return config;
213
+ }
214
+ /**
215
+ * Lift the `closed` gate and produce a fresh agent identity. Called by the
216
+ * `quicksave pair` CLI path: even if the agent was already in a fresh state
217
+ * after tombstone, rotating again here means each new pairing attempt comes
218
+ * with an unburdened identity — no lingering state from prior pairings.
219
+ */
220
+ export function unlockPairingAndRotate() {
221
+ const config = loadConfig();
222
+ if (!config) {
223
+ throw new Error('No config found.');
224
+ }
225
+ config.peerPWAPublicKey = null;
226
+ config.peerPWASignPublicKey = null;
227
+ config.agentId = generateAgentId();
228
+ config.keyPair = generateAgentKeyPair();
229
+ config.signKeyPair = encodeKeyPair(generateSigningKeyPair());
230
+ config.closed = false;
231
+ saveConfig(config);
232
+ return config;
233
+ }
148
234
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  import { EventEmitter } from 'events';
2
2
  import { type Message } from '@sumicom/quicksave-shared';
3
+ import { type AgentConfig } from '../config.js';
4
+ import { type TombstoneCheckResult } from '../tombstoneCheck.js';
3
5
  export interface ConnectionConfig {
4
6
  signalingServer: string;
5
7
  agentId: string;
@@ -18,7 +20,24 @@ export interface AgentConnectionEvents {
18
20
  disconnected: (peerAddress: string) => void;
19
21
  message: (message: Message, peerAddress: string) => void;
20
22
  error: (error: Error) => void;
23
+ /**
24
+ * A verified tombstone was observed for the pinned peer PWA group. Config
25
+ * has already been cleared and the keypair rotated. Upper layers should
26
+ * typically stop the process or prompt the user to run `quicksave pair`.
27
+ */
28
+ tombstoned: (details: {
29
+ oldPublicKey: string;
30
+ }) => void;
21
31
  }
32
+ /**
33
+ * Coarse-grained agent pairing state surfaced to the CLI + telemetry.
34
+ *
35
+ * - `unpaired`: ready to TOFU a new PWA group on the next handshake
36
+ * - `paired`: peerPWA identity is pinned; handshakes validated against it
37
+ * - `closed`: tombstone was observed; all incoming handshakes are refused
38
+ * until `unlockPairing()` is called (e.g. by `quicksave pair`)
39
+ */
40
+ export type AgentPairState = 'unpaired' | 'paired' | 'closed';
22
41
  export declare class AgentConnection extends EventEmitter {
23
42
  private config;
24
43
  private signaling;
@@ -27,9 +46,51 @@ export declare class AgentConnection extends EventEmitter {
27
46
  private pubsub;
28
47
  private savedPeerTopics;
29
48
  private static readonly KEY_EXCHANGE_MAX_AGE_MS;
49
+ private static readonly TOMBSTONE_POLL_MS;
50
+ private tombstonePollTimer;
51
+ /** The keyHash we currently have an active relay subscription for, if any. */
52
+ private subscribedKeyHash;
30
53
  constructor(config: ConnectionConfig);
31
54
  private setupSignalingHandlers;
55
+ private handlePushedTombstone;
56
+ /**
57
+ * Subscribe to the pinned peer's tombstone mailbox via the relay push
58
+ * channel, if the agent is currently paired. Idempotent: safe to call from
59
+ * both `connected` and TOFU completion paths.
60
+ */
61
+ private resubscribeIfPaired;
32
62
  start(): Promise<void>;
63
+ /**
64
+ * Check the pinned peer's mailbox for a signed tombstone. No-op if the
65
+ * agent is not currently paired. Exposed so the signaling reconnect path
66
+ * can piggy-back on the check without re-implementing the policy.
67
+ */
68
+ runTombstoneCheck(): Promise<TombstoneCheckResult | null>;
69
+ /**
70
+ * Invoked when a valid tombstone for the pinned peer group has been
71
+ * observed. Clears peer identity state on disk (which also rotates the
72
+ * agent's own keypair), tears down all active peer sessions, and emits
73
+ * `tombstoned` for upper layers. The signaling transport is left running
74
+ * so the agent can accept a fresh TOFU handshake from a rotated group.
75
+ */
76
+ /**
77
+ * Coarse pair-state for CLI + telemetry. Reads the (possibly freshly-saved)
78
+ * config on each call so the answer stays accurate after tombstone cleanup.
79
+ * `closed` is now persisted on disk (`config.closed`), so a daemon restart
80
+ * preserves the self-destructed state.
81
+ */
82
+ getState(): AgentPairState;
83
+ /**
84
+ * Lift the `closed` gate and rotate the agent's own cryptographic identity
85
+ * (`agentId`, X25519 keypair, Ed25519 signing keypair). Called by the
86
+ * `quicksave pair` CLI path. Tears down the current signaling connection
87
+ * and reconnects with the new `agentId` so old routing addresses stop
88
+ * receiving traffic. Safe to call from any state.
89
+ */
90
+ unlockPairing(): Promise<AgentConfig>;
91
+ private handleVerifiedTombstone;
92
+ private startTombstonePolling;
93
+ private stopTombstonePolling;
33
94
  private handleDataMessage;
34
95
  /**
35
96
  * Handle key exchange message
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/connection/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EASL,KAAK,OAAO,EAGb,MAAM,2BAA2B,CAAC;AAOnC,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/B;AAED,qBAAa,eAAgB,SAAQ,YAAY;IAC/C,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,MAAM,CAAgB;IAI9B,OAAO,CAAC,eAAe,CAAuC;IAG9D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAS;gBAE5C,MAAM,EAAE,gBAAgB;IAQpC,OAAO,CAAC,sBAAsB;IAyCxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAQd,iBAAiB;IAsC/B;;OAEG;YACW,iBAAiB;IAqE/B,OAAO,CAAC,UAAU,CAAyC;IAE3D,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI;IAsBnD,OAAO,CAAC,sBAAsB;IAa9B,UAAU,IAAI,IAAI;IAIlB,YAAY,IAAI,MAAM;IAItB,UAAU,IAAI,MAAM;IAIpB,YAAY,IAAI,MAAM;IAItB,QAAQ,IAAI,OAAO;IAInB,gDAAgD;IAChD,aAAa,IAAI;QAAE,KAAK,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;KAAE;IActI,iEAAiE;IACjE,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CAgBlC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAE/E"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/connection/connection.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,11 @@
1
1
  import { EventEmitter } from 'events';
2
2
  import { gzip, gunzip } from 'zlib';
3
3
  import { promisify } from 'util';
4
- import { generateKeyPair, encodeKeyPair, decodeKeyPair, encryptWithSharedSecret, decryptWithSharedSecret, decryptDEK, parseMessage, serializeMessage, } from '@sumicom/quicksave-shared';
4
+ import { generateKeyPair, encodeKeyPair, decodeKeyPair, decodeBase64, encryptWithSharedSecret, decryptWithSharedSecret, decryptDEK, parseMessage, serializeMessage, verifyKeyExchangeV2Signature, } from '@sumicom/quicksave-shared';
5
5
  import { SignalingClient } from './relay.js';
6
6
  import { PubSub, BROADCAST_TOPIC } from './pubsub.js';
7
+ import { clearPeerPWA, isPaired, loadConfig, pinPeerPWA, unlockPairingAndRotate, } from '../config.js';
8
+ import { checkTombstone, hashPublicKey, verifyTombstonePayload, } from '../tombstoneCheck.js';
7
9
  const gzipAsync = promisify(gzip);
8
10
  const gunzipAsync = promisify(gunzip);
9
11
  export class AgentConnection extends EventEmitter {
@@ -17,6 +19,16 @@ export class AgentConnection extends EventEmitter {
17
19
  savedPeerTopics = new Map();
18
20
  // Key exchange replay protection
19
21
  static KEY_EXCHANGE_MAX_AGE_MS = 60000; // 60 seconds
22
+ // Periodic catch-up GET fallback. Runs even when the relay-push channel is
23
+ // healthy — if the push path is silently broken (relay restart before we
24
+ // resubscribe, proxy dropping the message, etc.) this still catches the
25
+ // rotation within 3 minutes. 180s is the ceiling the user signed off on;
26
+ // tighter intervals trade latency for relay load that's not worth paying
27
+ // unless we see an incident.
28
+ static TOMBSTONE_POLL_MS = 180_000;
29
+ tombstonePollTimer = null;
30
+ /** The keyHash we currently have an active relay subscription for, if any. */
31
+ subscribedKeyHash = null;
20
32
  constructor(config) {
21
33
  super();
22
34
  this.config = config;
@@ -25,6 +37,14 @@ export class AgentConnection extends EventEmitter {
25
37
  this.setupSignalingHandlers();
26
38
  }
27
39
  setupSignalingHandlers() {
40
+ this.signaling.on('connected', () => {
41
+ // Each (re)connect is a chance to catch up on a missed tombstone.
42
+ void this.runTombstoneCheck();
43
+ // (Re-)subscribe the push channel if we already know the pinned peer.
44
+ // Unpaired agents have no mailbox to watch yet; TOFU will call this
45
+ // helper explicitly after pinning.
46
+ this.resubscribeIfPaired();
47
+ });
28
48
  this.signaling.on('peer-connected', () => {
29
49
  console.log('PWA peer connected, waiting for key exchange...');
30
50
  });
@@ -58,6 +78,58 @@ export class AgentConnection extends EventEmitter {
58
78
  this.signaling.on('error', (error) => {
59
79
  this.emit('error', error);
60
80
  });
81
+ // Relay-pushed tombstone — the emergency fast path. We still verify locally
82
+ // with the pinned signing pubkey because the relay is untrusted; a forged
83
+ // payload here will simply fail verification and be dropped.
84
+ this.signaling.on('tombstone-event', (keyHash, data) => {
85
+ this.handlePushedTombstone(keyHash, data);
86
+ });
87
+ }
88
+ handlePushedTombstone(keyHash, data) {
89
+ // Short-circuit once we're already closed: the catch-up GET and the push
90
+ // path can both fire for the same tombstone, and after the first handler
91
+ // runs `peerPWAPublicKey` is null on disk.
92
+ if (this.getState() === 'closed')
93
+ return;
94
+ const config = loadConfig();
95
+ if (!config || !isPaired(config))
96
+ return;
97
+ const expectedHash = hashPublicKey(config.peerPWAPublicKey);
98
+ if (keyHash !== expectedHash) {
99
+ // Ignore pushes for mailboxes we aren't pinned to. Shouldn't happen
100
+ // because we only subscribe to our pinned peer, but the relay is
101
+ // untrusted so we verify anyway.
102
+ return;
103
+ }
104
+ const result = verifyTombstonePayload(data, config.peerPWAPublicKey, config.peerPWASignPublicKey);
105
+ if (result.status === 'tombstoned') {
106
+ this.handleVerifiedTombstone(result.tombstone.oldPublicKey);
107
+ }
108
+ else if (result.status === 'verify-failed') {
109
+ console.error(`Pushed tombstone verification failed: ${result.reason}`);
110
+ }
111
+ }
112
+ /**
113
+ * Subscribe to the pinned peer's tombstone mailbox via the relay push
114
+ * channel, if the agent is currently paired. Idempotent: safe to call from
115
+ * both `connected` and TOFU completion paths.
116
+ */
117
+ resubscribeIfPaired() {
118
+ const config = loadConfig();
119
+ if (!config || !isPaired(config))
120
+ return;
121
+ const keyHash = hashPublicKey(config.peerPWAPublicKey);
122
+ if (this.subscribedKeyHash === keyHash) {
123
+ // Already subscribed to the same key — but the SignalingClient replays
124
+ // its own subscription set on reconnect, so we don't need to re-send.
125
+ return;
126
+ }
127
+ // If we were subscribed to an old key (e.g. after unlockPairing), drop it.
128
+ if (this.subscribedKeyHash) {
129
+ this.signaling.unsubscribeTombstone(this.subscribedKeyHash);
130
+ }
131
+ this.signaling.subscribeTombstone(keyHash);
132
+ this.subscribedKeyHash = keyHash;
61
133
  }
62
134
  async start() {
63
135
  console.log('Connecting to signaling server...');
@@ -65,6 +137,148 @@ export class AgentConnection extends EventEmitter {
65
137
  console.log('Connected to signaling server');
66
138
  console.log(`Agent ID: ${this.config.agentId}`);
67
139
  console.log(`Public Key: ${this.config.keyPair.publicKey}`);
140
+ // Tombstone catch-up runs from the 'connected' handler registered in
141
+ // setupSignalingHandlers(), so every reconnect re-checks too. Also start
142
+ // the 180s periodic fallback in case the push channel silently breaks.
143
+ this.startTombstonePolling();
144
+ }
145
+ /**
146
+ * Check the pinned peer's mailbox for a signed tombstone. No-op if the
147
+ * agent is not currently paired. Exposed so the signaling reconnect path
148
+ * can piggy-back on the check without re-implementing the policy.
149
+ */
150
+ async runTombstoneCheck() {
151
+ const config = loadConfig();
152
+ if (!config || !isPaired(config))
153
+ return null;
154
+ const result = await checkTombstone({
155
+ signalingServer: this.config.signalingServer,
156
+ peerPWAPublicKey: config.peerPWAPublicKey,
157
+ peerPWASignPublicKey: config.peerPWASignPublicKey,
158
+ });
159
+ if (result.status === 'tombstoned') {
160
+ this.handleVerifiedTombstone(result.tombstone.oldPublicKey);
161
+ }
162
+ else if (result.status === 'verify-failed') {
163
+ console.error(`Tombstone check: verification failed (${result.reason})`);
164
+ }
165
+ else if (result.status === 'error') {
166
+ // Network / transient errors are non-fatal; we'll recheck next connect.
167
+ console.error(`Tombstone check: ${result.error}`);
168
+ }
169
+ return result;
170
+ }
171
+ /**
172
+ * Invoked when a valid tombstone for the pinned peer group has been
173
+ * observed. Clears peer identity state on disk (which also rotates the
174
+ * agent's own keypair), tears down all active peer sessions, and emits
175
+ * `tombstoned` for upper layers. The signaling transport is left running
176
+ * so the agent can accept a fresh TOFU handshake from a rotated group.
177
+ */
178
+ /**
179
+ * Coarse pair-state for CLI + telemetry. Reads the (possibly freshly-saved)
180
+ * config on each call so the answer stays accurate after tombstone cleanup.
181
+ * `closed` is now persisted on disk (`config.closed`), so a daemon restart
182
+ * preserves the self-destructed state.
183
+ */
184
+ getState() {
185
+ const config = loadConfig();
186
+ if (!config)
187
+ return 'unpaired';
188
+ if (config.closed)
189
+ return 'closed';
190
+ return isPaired(config) ? 'paired' : 'unpaired';
191
+ }
192
+ /**
193
+ * Lift the `closed` gate and rotate the agent's own cryptographic identity
194
+ * (`agentId`, X25519 keypair, Ed25519 signing keypair). Called by the
195
+ * `quicksave pair` CLI path. Tears down the current signaling connection
196
+ * and reconnects with the new `agentId` so old routing addresses stop
197
+ * receiving traffic. Safe to call from any state.
198
+ */
199
+ async unlockPairing() {
200
+ const newConfig = unlockPairingAndRotate();
201
+ this.config = {
202
+ ...this.config,
203
+ agentId: newConfig.agentId,
204
+ keyPair: newConfig.keyPair,
205
+ };
206
+ this.keyPair = decodeKeyPair(newConfig.keyPair);
207
+ // Tear down every active peer session — old DEKs are irrelevant under the
208
+ // rotated keypair anyway.
209
+ for (const [address] of this.peers) {
210
+ this.pubsub.unsubscribeAll(address);
211
+ this.emit('disconnected', address);
212
+ }
213
+ this.peers.clear();
214
+ this.savedPeerTopics.clear();
215
+ // No pinned mailbox yet under the rotated identity — clear the locally
216
+ // tracked subscription so the next TOFU can subscribe fresh.
217
+ this.subscribedKeyHash = null;
218
+ // Reinstantiate signaling under the new agentId so the relay routes to
219
+ // this process under the new address only.
220
+ this.signaling.removeAllListeners();
221
+ this.signaling.disconnect();
222
+ this.signaling = new SignalingClient(this.config.signalingServer, newConfig.agentId);
223
+ this.setupSignalingHandlers();
224
+ try {
225
+ await this.signaling.connect();
226
+ }
227
+ catch (err) {
228
+ console.error('Signaling reconnect after unlockPairing failed:', err);
229
+ // Leave the SignalingClient object in place; its own reconnect loop
230
+ // will keep trying.
231
+ }
232
+ this.emit('identity-rotated', { agentId: newConfig.agentId });
233
+ return newConfig;
234
+ }
235
+ handleVerifiedTombstone(oldPublicKey) {
236
+ // Idempotency guard: the push-channel event and the catch-up GET can race,
237
+ // and both may fire before the first one has finished writing to disk. The
238
+ // persisted `closed` flag is the canonical answer; once set, we ignore
239
+ // further tombstone triggers until `unlockPairing()` clears it.
240
+ if (this.getState() === 'closed') {
241
+ return;
242
+ }
243
+ console.warn(`Tombstone verified for pinned peer ${oldPublicKey.slice(0, 12)}... — self-destructing pairing`);
244
+ // Best-effort unsubscribe from the relay push channel; the closed-state
245
+ // gate in handleKeyExchange is the real line of defense.
246
+ if (this.subscribedKeyHash) {
247
+ this.signaling.unsubscribeTombstone(this.subscribedKeyHash);
248
+ this.subscribedKeyHash = null;
249
+ }
250
+ this.stopTombstonePolling();
251
+ // Tear down every active peer session first so no leftover DEK answers.
252
+ for (const [address] of this.peers) {
253
+ this.pubsub.unsubscribeAll(address);
254
+ this.emit('disconnected', address);
255
+ }
256
+ this.peers.clear();
257
+ this.savedPeerTopics.clear();
258
+ try {
259
+ clearPeerPWA();
260
+ }
261
+ catch (err) {
262
+ console.error('clearPeerPWA failed during tombstone handling:', err);
263
+ }
264
+ this.emit('tombstoned', { oldPublicKey });
265
+ }
266
+ startTombstonePolling() {
267
+ if (this.tombstonePollTimer)
268
+ return;
269
+ this.tombstonePollTimer = setInterval(() => {
270
+ // Errors and 'absent' are silent — treated as no-op, same as the existing
271
+ // runTombstoneCheck behaviour. We only act on verified tombstones.
272
+ void this.runTombstoneCheck();
273
+ }, AgentConnection.TOMBSTONE_POLL_MS);
274
+ // Don't block process shutdown on the polling timer.
275
+ this.tombstonePollTimer.unref?.();
276
+ }
277
+ stopTombstonePolling() {
278
+ if (this.tombstonePollTimer) {
279
+ clearInterval(this.tombstonePollTimer);
280
+ this.tombstonePollTimer = null;
281
+ }
68
282
  }
69
283
  async handleDataMessage(data, from) {
70
284
  try {
@@ -106,6 +320,14 @@ export class AgentConnection extends EventEmitter {
106
320
  * Handle key exchange message
107
321
  */
108
322
  async handleKeyExchange(message, from) {
323
+ // Closed state gate: once we've self-destructed from a tombstone, refuse
324
+ // any handshake until an operator runs `quicksave pair` (which calls
325
+ // `unlockPairing()`). Sourced from the persisted `config.closed` flag.
326
+ if (this.getState() === 'closed') {
327
+ console.error('Agent is in closed state; refusing key exchange until `quicksave pair` is run');
328
+ this.emit('error', new Error('Agent closed after tombstone; run `quicksave pair` to re-enable'));
329
+ return;
330
+ }
109
331
  // Verify timestamp for replay protection
110
332
  const age = Date.now() - message.timestamp;
111
333
  if (age > AgentConnection.KEY_EXCHANGE_MAX_AGE_MS) {
@@ -119,6 +341,56 @@ export class AgentConnection extends EventEmitter {
119
341
  this.emit('error', new Error('Key exchange timestamp invalid'));
120
342
  return;
121
343
  }
344
+ // Proof-of-possession: the PWA must sign the canonical key-exchange body
345
+ // with the group's shared Ed25519 key. On the first successful handshake
346
+ // we TOFU-pin that key; after that, sigPubkey must match the pinned one.
347
+ if (!message.sigPubkey || !message.signature) {
348
+ console.error('Key exchange missing sigPubkey/signature — rejecting pre-TOFU legacy peer');
349
+ this.emit('error', new Error('Key exchange missing signature'));
350
+ return;
351
+ }
352
+ const sigValid = verifyKeyExchangeV2Signature({
353
+ agentId: this.config.agentId,
354
+ encryptedDEK: message.encryptedDEK,
355
+ timestamp: message.timestamp,
356
+ sigPubkey: message.sigPubkey,
357
+ signature: message.signature,
358
+ decodeBase64,
359
+ });
360
+ if (!sigValid) {
361
+ console.error('Key exchange signature verification failed');
362
+ this.emit('error', new Error('Key exchange signature invalid'));
363
+ return;
364
+ }
365
+ const config = loadConfig();
366
+ if (config && isPaired(config)) {
367
+ if (message.sigPubkey !== config.peerPWASignPublicKey) {
368
+ console.error('Key exchange sigPubkey does not match pinned peer — rejecting');
369
+ this.emit('error', new Error('Key exchange sigPubkey mismatch (peer not the pinned PWA group)'));
370
+ return;
371
+ }
372
+ }
373
+ else {
374
+ // Unpaired: TOFU. Pin the claimed signing key (and the PWA's X25519
375
+ // pubkey, derived from the routed address — `pwa:{publicKey}`) for
376
+ // all future handshakes.
377
+ const peerPWAPublicKey = (from ?? '').replace(/^pwa:/, '');
378
+ if (peerPWAPublicKey && config) {
379
+ try {
380
+ pinPeerPWA(peerPWAPublicKey, message.sigPubkey);
381
+ console.log(`TOFU: pinned peer PWA pubkey ${peerPWAPublicKey.slice(0, 12)}... ` +
382
+ `sig ${message.sigPubkey.slice(0, 12)}...`);
383
+ // Now that we have a pinned mailbox, start listening for pushed
384
+ // tombstones on it. Idempotent.
385
+ this.resubscribeIfPaired();
386
+ }
387
+ catch (err) {
388
+ console.error('TOFU pin failed:', err);
389
+ this.emit('error', err instanceof Error ? err : new Error('TOFU pin failed'));
390
+ return;
391
+ }
392
+ }
393
+ }
122
394
  // Decrypt the session DEK
123
395
  try {
124
396
  const sessionDEK = decryptDEK(message.encryptedDEK, this.keyPair.secretKey);
@@ -199,6 +471,7 @@ export class AgentConnection extends EventEmitter {
199
471
  console.log('Peer disconnected, waiting for new connection...');
200
472
  }
201
473
  disconnect() {
474
+ this.stopTombstonePolling();
202
475
  this.signaling.disconnect();
203
476
  }
204
477
  getPublicKey() {