@cello-protocol/daemon 0.0.49 → 0.0.51
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/bin/cello-daemon.js +13 -0
- package/dist/bin/cello-daemon.js.map +1 -1
- package/dist/connect-or-start.d.ts +11 -11
- package/dist/connect-or-start.d.ts.map +1 -1
- package/dist/connect-or-start.js +97 -39
- package/dist/connect-or-start.js.map +1 -1
- package/dist/daemon.d.ts +11 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +127 -26
- package/dist/daemon.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/ipc-server.d.ts.map +1 -1
- package/dist/ipc-server.js +79 -13
- package/dist/ipc-server.js.map +1 -1
- package/dist/lock-file.d.ts +12 -0
- package/dist/lock-file.d.ts.map +1 -1
- package/dist/lock-file.js +36 -1
- package/dist/lock-file.js.map +1 -1
- package/dist/park-envelope.d.ts +93 -0
- package/dist/park-envelope.d.ts.map +1 -0
- package/dist/park-envelope.js +172 -0
- package/dist/park-envelope.js.map +1 -0
- package/dist/retry-queue.d.ts.map +1 -1
- package/dist/retry-queue.js +13 -1
- package/dist/retry-queue.js.map +1 -1
- package/dist/session-node-manager.d.ts +31 -13
- package/dist/session-node-manager.d.ts.map +1 -1
- package/dist/session-node-manager.js +104 -26
- package/dist/session-node-manager.js.map +1 -1
- package/dist/singleton-lock.d.ts +85 -0
- package/dist/singleton-lock.d.ts.map +1 -0
- package/dist/singleton-lock.js +208 -0
- package/dist/singleton-lock.js.map +1 -0
- package/dist/sqlcipher-db.d.ts +28 -0
- package/dist/sqlcipher-db.d.ts.map +1 -1
- package/dist/sqlcipher-db.js +6 -1
- package/dist/sqlcipher-db.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export type { Logger, LockFileContent, IpcRequest, IpcResponse, IpcResponseOk, IpcResponseError, IpcNotification, IpcFrame, AgentState, AgentInfo, ConnectionStatus, ConnectionInfo, DirectorySignalingState, DaemonStatusResponse, DaemonConfig, IManifestProvider, IManifestVersionStore, IManifestPollScheduler, IDirectoryChallengeVerifier, } from "./types.js";
|
|
2
2
|
export { ErrorCodes } from "./types.js";
|
|
3
3
|
export { startDaemon, type DaemonHandle } from "./daemon.js";
|
|
4
|
-
export { readLock, acquireLock, removeLock, isProcessAlive } from "./lock-file.js";
|
|
4
|
+
export { readLock, acquireLock, removeLock, removeLockIfOwned, isProcessAlive } from "./lock-file.js";
|
|
5
|
+
export { acquireSingletonLock, probeSingletonLock, DaemonAlreadyRunningError, SINGLETON_LOCK_FILENAME, type SingletonLock, } from "./singleton-lock.js";
|
|
5
6
|
export { loadAgents, type LoadedAgent, type FailedAgent, type AgentLoadResult } from "./agent-loader.js";
|
|
6
7
|
export { createIpcServer, type IpcServer, type IpcHandler, type IpcServerConfig, type IpcDisconnectHandler } from "./ipc-server.js";
|
|
7
8
|
export { connectToDaemon, type IpcClient, IpcError } from "./ipc-client.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,MAAM,EACN,eAAe,EACf,UAAU,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,uBAAuB,EACvB,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,MAAM,EACN,eAAe,EACf,UAAU,EACV,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,uBAAuB,EACvB,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,2BAA2B,GAC5B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACtG,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,EACvB,KAAK,aAAa,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACpI,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACvH,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGpE,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,eAAe,EACf,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC/F,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,kCAAkC,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AAK7G,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { ErrorCodes } from "./types.js";
|
|
2
2
|
export { startDaemon } from "./daemon.js";
|
|
3
|
-
export { readLock, acquireLock, removeLock, isProcessAlive } from "./lock-file.js";
|
|
3
|
+
export { readLock, acquireLock, removeLock, removeLockIfOwned, isProcessAlive } from "./lock-file.js";
|
|
4
|
+
export { acquireSingletonLock, probeSingletonLock, DaemonAlreadyRunningError, SINGLETON_LOCK_FILENAME, } from "./singleton-lock.js";
|
|
4
5
|
export { loadAgents } from "./agent-loader.js";
|
|
5
6
|
export { createIpcServer } from "./ipc-server.js";
|
|
6
7
|
export { connectToDaemon, IpcError } from "./ipc-client.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,WAAW,EAAqB,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,WAAW,EAAqB,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACtG,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,yBAAyB,EACzB,uBAAuB,GAExB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAA4D,MAAM,mBAAmB,CAAC;AACzG,OAAO,EAAE,eAAe,EAAoF,MAAM,iBAAiB,CAAC;AACpI,OAAO,EAAE,eAAe,EAAkB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAsB,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAA0D,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACvH,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEpE,qFAAqF;AACrF,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,eAAe,EACf,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AASjC,+DAA+D;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC/F,OAAO,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,kCAAkC,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC;AAE7G,6FAA6F;AAC7F,+FAA+F;AAC/F,4EAA4E;AAC5E,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,GAGjB,MAAM,iBAAiB,CAAC"}
|
package/dist/ipc-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../src/ipc-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAA2B,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEjH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;AAElE,MAAM,WAAW,SAAS;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,kBAAkB,IAAI,MAAM,CAAC;IAC7B,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD,qFAAqF;IACrF,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,GAAG,OAAO,CAAC;IAC/E,wCAAwC;IACxC,gBAAgB,IAAI,MAAM,EAAE,CAAC;CAC9B;AASD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GAChC,SAAS,
|
|
1
|
+
{"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../src/ipc-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAA2B,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEjH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;AAElE,MAAM,WAAW,SAAS;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,kBAAkB,IAAI,MAAM,CAAC;IAC7B,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD,qFAAqF;IACrF,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,GAAG,OAAO,CAAC;IAC/E,wCAAwC;IACxC,gBAAgB,IAAI,MAAM,EAAE,CAAC;CAC9B;AASD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GAChC,SAAS,CA6TX"}
|
package/dist/ipc-server.js
CHANGED
|
@@ -28,13 +28,42 @@
|
|
|
28
28
|
* e. Unlink socket file
|
|
29
29
|
*/
|
|
30
30
|
import { createServer } from "node:net";
|
|
31
|
-
import { chmod, unlink } from "node:fs/promises";
|
|
31
|
+
import { chmod, stat, unlink } from "node:fs/promises";
|
|
32
32
|
import { randomUUID } from "node:crypto";
|
|
33
33
|
export function createIpcServer(config, handlers) {
|
|
34
34
|
const { socketPath, maxConnections, logger } = config;
|
|
35
35
|
let server = null;
|
|
36
36
|
const connections = new Map();
|
|
37
37
|
let stopping = false;
|
|
38
|
+
// DOD-DAEMON-CLEANUP-1 (AC2): the identity — not the path — of the socket THIS server created.
|
|
39
|
+
// dev+ino is the only thing that survives another daemon rebinding the same path.
|
|
40
|
+
let createdSocket = null;
|
|
41
|
+
/**
|
|
42
|
+
* What is sitting at socketPath right now?
|
|
43
|
+
* "ours" — the socket this server created; we may remove it.
|
|
44
|
+
* "gone" — nothing there; nothing to do.
|
|
45
|
+
* "foreign" — a DIFFERENT socket. Another daemon rebound the path. Hands off.
|
|
46
|
+
*
|
|
47
|
+
* The distinction is by inode, not by path. A path tells you a file exists; only the inode tells
|
|
48
|
+
* you it is the same file you made.
|
|
49
|
+
*/
|
|
50
|
+
async function socketOwnership() {
|
|
51
|
+
let current;
|
|
52
|
+
try {
|
|
53
|
+
current = await stat(socketPath);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Nothing at the path (ENOENT is the only realistic case) — there is nothing to own.
|
|
57
|
+
return "gone";
|
|
58
|
+
}
|
|
59
|
+
if (createdSocket === null) {
|
|
60
|
+
// Unreachable: stop() returns early unless the server is listening, and a listening server has
|
|
61
|
+
// been through start(), which sets this or throws. Say so rather than inventing an answer —
|
|
62
|
+
// guessing here is what the whole unit is about.
|
|
63
|
+
throw new Error("ipc server: socket identity unknown — stop() ran without a completed start()");
|
|
64
|
+
}
|
|
65
|
+
return current.dev === createdSocket.dev && current.ino === createdSocket.ino ? "ours" : "foreign";
|
|
66
|
+
}
|
|
38
67
|
let disconnectHandler = null;
|
|
39
68
|
function handleConnection(socket) {
|
|
40
69
|
if (stopping) {
|
|
@@ -186,6 +215,18 @@ export function createIpcServer(config, handlers) {
|
|
|
186
215
|
});
|
|
187
216
|
// SI-001: Set socket permissions to owner-only
|
|
188
217
|
await chmod(socketPath, 0o600);
|
|
218
|
+
// DOD-DAEMON-CLEANUP-1 (AC2): remember WHICH socket we created, by identity — not merely that
|
|
219
|
+
// a file exists at this path. If another daemon later rebinds the path, its listen() replaces
|
|
220
|
+
// the file with a different inode, and stop() must be able to tell the two apart so it does not
|
|
221
|
+
// unlink a socket it does not own.
|
|
222
|
+
//
|
|
223
|
+
// No fallback here, deliberately. Swallowing this stat and leaving the identity unknown would
|
|
224
|
+
// make stop() treat our OWN socket as foreign: it would then never close the server, so the
|
|
225
|
+
// daemon would go on accepting IPC connections into a torn-down handler stack after stop()
|
|
226
|
+
// returned, and would leave its socket behind. A daemon that cannot identify the socket it just
|
|
227
|
+
// bound has no business coming up — and startup failure is already handled cleanly.
|
|
228
|
+
const created = await stat(socketPath);
|
|
229
|
+
createdSocket = { dev: created.dev, ino: created.ino };
|
|
189
230
|
},
|
|
190
231
|
async stop() {
|
|
191
232
|
stopping = true;
|
|
@@ -221,19 +262,44 @@ export function createIpcServer(config, handlers) {
|
|
|
221
262
|
// Connection may already be closed
|
|
222
263
|
}
|
|
223
264
|
}
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
265
|
+
// DOD-DAEMON-CLEANUP-1 (AC2): decide ownership BEFORE closing, because close() is itself a
|
|
266
|
+
// blind unlink.
|
|
267
|
+
//
|
|
268
|
+
// Node's server.close() removes the unix socket path it bound — by PATH, with no check on what
|
|
269
|
+
// is actually there now. If another daemon has since rebound this path, closing our server
|
|
270
|
+
// deletes THEIR socket, and they are left alive, serving, and unreachable. Guarding our own
|
|
271
|
+
// explicit unlink is not enough; the close would already have done the damage.
|
|
272
|
+
const ownership = await socketOwnership();
|
|
273
|
+
if (ownership === "foreign") {
|
|
274
|
+
// We must not close: that would unlink the healthy daemon's socket out from under it. Drop
|
|
275
|
+
// the handle from the event loop instead and let process exit reclaim the fd. The listening
|
|
276
|
+
// socket is already inert — its path was taken from it, so nothing can reach it. Leaking an
|
|
277
|
+
// unreachable fd for the last moments of a dying process is a trade we make happily against
|
|
278
|
+
// disarming a live peer.
|
|
279
|
+
logger.info("daemon.ipc.socket.not_ours", { socketPath, ourIno: createdSocket?.ino ?? null });
|
|
280
|
+
server.unref();
|
|
230
281
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
282
|
+
else {
|
|
283
|
+
await new Promise((resolve) => {
|
|
284
|
+
server.close(() => resolve());
|
|
285
|
+
});
|
|
286
|
+
// close() normally unlinks the path for us. Re-check rather than assume: only remove the file
|
|
287
|
+
// if it is STILL the socket we created. Between the close and here, the singleton lock is
|
|
288
|
+
// still held (the daemon releases it after this returns), so no successor can have bound the
|
|
289
|
+
// path — but the cost of re-checking is one stat, and the cost of being wrong is the bug this
|
|
290
|
+
// whole unit exists to kill.
|
|
291
|
+
if (await socketOwnership() === "ours") {
|
|
292
|
+
try {
|
|
293
|
+
await unlink(socketPath);
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
if (err.code !== "ENOENT") {
|
|
297
|
+
logger.warn("daemon.ipc.socket.unlink.failed", {
|
|
298
|
+
socketPath,
|
|
299
|
+
error: err instanceof Error ? err.message : String(err),
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
237
303
|
}
|
|
238
304
|
}
|
|
239
305
|
server = null;
|
package/dist/ipc-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ipc-server.js","sourceRoot":"","sources":["../src/ipc-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,YAAY,EAA4B,MAAM,UAAU,CAAC;AAClE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ipc-server.js","sourceRoot":"","sources":["../src/ipc-server.ts"],"names":[],"mappings":"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"}
|
package/dist/lock-file.d.ts
CHANGED
|
@@ -23,5 +23,17 @@ import type { LockFileContent, Logger } from "./types.js";
|
|
|
23
23
|
export declare function readLock(lockPath: string): Promise<LockFileContent | null>;
|
|
24
24
|
export declare function acquireLock(lockPath: string, content: LockFileContent): Promise<void>;
|
|
25
25
|
export declare function removeLock(lockPath: string, logger: Logger): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* DOD-DAEMON-CLEANUP-1 (AC1) — remove the lock ONLY if it is still ours.
|
|
28
|
+
*
|
|
29
|
+
* An exiting daemon must not disarm a daemon it does not own. By the time we shut down, a DIFFERENT
|
|
30
|
+
* daemon may have written this lock; deleting it would leave that healthy daemon unreachable
|
|
31
|
+
* (`cello logout` reports "No daemon running") and the next `cello login` would spawn a third beside
|
|
32
|
+
* it. That is the cascade — the obvious recovery action, killing the orphan, propagates the bug.
|
|
33
|
+
*
|
|
34
|
+
* `removeLock` (unconditional) is still correct for the CLI's stale-lock cleanup, where the lock
|
|
35
|
+
* belongs to a process that is provably gone. It is NOT correct on the way out of a live daemon.
|
|
36
|
+
*/
|
|
37
|
+
export declare function removeLockIfOwned(lockPath: string, ownPid: number, logger: Logger): Promise<void>;
|
|
26
38
|
export declare function isProcessAlive(pid: number): boolean;
|
|
27
39
|
//# sourceMappingURL=lock-file.d.ts.map
|
package/dist/lock-file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock-file.d.ts","sourceRoot":"","sources":["../src/lock-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAwBhF;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAU3F;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD"}
|
|
1
|
+
{"version":3,"file":"lock-file.d.ts","sourceRoot":"","sources":["../src/lock-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAwBhF;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAU3F;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWhF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAwBf;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD"}
|
package/dist/lock-file.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* 4. removeLock(path):
|
|
20
20
|
* - Unlink the file, ignoring ENOENT
|
|
21
21
|
*/
|
|
22
|
-
import { readFile, writeFile, rename, unlink } from "node:fs/promises";
|
|
22
|
+
import { readFile, writeFile, rename, stat, unlink } from "node:fs/promises";
|
|
23
23
|
export async function readLock(lockPath) {
|
|
24
24
|
let raw;
|
|
25
25
|
try {
|
|
@@ -72,6 +72,41 @@ export async function removeLock(lockPath, logger) {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* DOD-DAEMON-CLEANUP-1 (AC1) — remove the lock ONLY if it is still ours.
|
|
77
|
+
*
|
|
78
|
+
* An exiting daemon must not disarm a daemon it does not own. By the time we shut down, a DIFFERENT
|
|
79
|
+
* daemon may have written this lock; deleting it would leave that healthy daemon unreachable
|
|
80
|
+
* (`cello logout` reports "No daemon running") and the next `cello login` would spawn a third beside
|
|
81
|
+
* it. That is the cascade — the obvious recovery action, killing the orphan, propagates the bug.
|
|
82
|
+
*
|
|
83
|
+
* `removeLock` (unconditional) is still correct for the CLI's stale-lock cleanup, where the lock
|
|
84
|
+
* belongs to a process that is provably gone. It is NOT correct on the way out of a live daemon.
|
|
85
|
+
*/
|
|
86
|
+
export async function removeLockIfOwned(lockPath, ownPid, logger) {
|
|
87
|
+
const lock = await readLock(lockPath);
|
|
88
|
+
if (lock === null) {
|
|
89
|
+
// readLock returns null for BOTH "absent" and "unparseable" — so this is the one place that
|
|
90
|
+
// cannot tell "nothing to do" from "something is wrong". Distinguish them: a lock file that
|
|
91
|
+
// exists but cannot be read (truncated by a full disk, a partial write) is left alone, because we
|
|
92
|
+
// cannot prove it is ours — but it is said out loud rather than passed over in silence.
|
|
93
|
+
try {
|
|
94
|
+
await stat(lockPath);
|
|
95
|
+
logger.warn("daemon.lock.unreadable", { ownPid, lockPath });
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Genuinely absent. Nothing to remove, nothing to report.
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (lock.pid !== ownPid) {
|
|
103
|
+
// SI: a daemon that declines to remove a lock says so. Silence here is what made the live
|
|
104
|
+
// incident so hard to see.
|
|
105
|
+
logger.info("daemon.lock.not_ours", { ownPid, lockPid: lock.pid, lockPath });
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
await removeLock(lockPath, logger);
|
|
109
|
+
}
|
|
75
110
|
export function isProcessAlive(pid) {
|
|
76
111
|
try {
|
|
77
112
|
process.kill(pid, 0);
|
package/dist/lock-file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock-file.js","sourceRoot":"","sources":["../src/lock-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"lock-file.js","sourceRoot":"","sources":["../src/lock-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type KeyProvider } from "@cello-protocol/crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Compare an identity key (raw bytes) against a stored hex pubkey — on BYTES, never on the hex
|
|
4
|
+
* strings.
|
|
5
|
+
*
|
|
6
|
+
* Review M1: `sessions.counterparty_pubkey` is persisted VERBATIM from the IPC `target_pubkey`
|
|
7
|
+
* string with no normalization, so an uppercase or mixed-case pubkey is a perfectly functional
|
|
8
|
+
* session (Buffer.from(hex) is case-insensitive, so dialing, sealing and the direct content path all
|
|
9
|
+
* work) — but a `toString("hex") !== stored` comparison would then refuse EVERY parked recovery for
|
|
10
|
+
* that session as `signer_not_counterparty`, i.e. permanent store-and-forward mail loss reported as
|
|
11
|
+
* an attack. Comparing bytes makes the check independent of how the hex was cased on the way in.
|
|
12
|
+
*
|
|
13
|
+
* Length-guarded because timingSafeEqual throws on a length mismatch, and the input is
|
|
14
|
+
* attacker-controlled (a forged envelope can carry a short/long pubkey).
|
|
15
|
+
*/
|
|
16
|
+
export declare function pubkeyMatchesHex(pubkey: Uint8Array, storedHex: string | undefined): boolean;
|
|
17
|
+
/** Current envelope version. v1 (unsigned) is decodable but NEVER acceptable — see authenticate(). */
|
|
18
|
+
export declare const PARK_ENVELOPE_VERSION = 2;
|
|
19
|
+
export interface ParkEnvelope {
|
|
20
|
+
/** 1 = legacy/unsigned (bare content or the pre-SEC-1 shape). 2 = signed. */
|
|
21
|
+
version: number;
|
|
22
|
+
content: Uint8Array;
|
|
23
|
+
/** DOD-MSG-4 ordering record — optional; absent on the crash-backstop path. */
|
|
24
|
+
structure1Cbor?: Uint8Array;
|
|
25
|
+
structure2Cbor?: Uint8Array;
|
|
26
|
+
/** SEC-1 — the sender's identity key. Present only on v2. */
|
|
27
|
+
senderPubkey?: Uint8Array;
|
|
28
|
+
/** SEC-1 — Ed25519 over buildParkContentTbs(...). Present only on v2. */
|
|
29
|
+
parkSig?: Uint8Array;
|
|
30
|
+
}
|
|
31
|
+
export type ParkAuthFailure = "unsigned_envelope" | "bad_signature" | "signer_not_counterparty" | "counterparty_unknown";
|
|
32
|
+
export type ParkAuthVerdict = {
|
|
33
|
+
ok: true;
|
|
34
|
+
} | {
|
|
35
|
+
ok: false;
|
|
36
|
+
reason: ParkAuthFailure;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* SEC-1: encode a SIGNED park envelope. `senderPubkey` and `parkSig` are REQUIRED — the type system
|
|
40
|
+
* is the enforcement point, so no call site can construct an unsigned envelope by omission (the
|
|
41
|
+
* exact drift that made this a downgrade attack: verification existed, but was opt-in).
|
|
42
|
+
*/
|
|
43
|
+
export declare function encodeParkEnvelope(args: {
|
|
44
|
+
content: Uint8Array;
|
|
45
|
+
senderPubkey: Uint8Array;
|
|
46
|
+
parkSig: Uint8Array;
|
|
47
|
+
structure1Cbor?: Uint8Array;
|
|
48
|
+
structure2Cbor?: Uint8Array;
|
|
49
|
+
}): Uint8Array;
|
|
50
|
+
/**
|
|
51
|
+
* SEC-1 — THE ONLY PRODUCER. Sign the entry as the sending agent, wrap it in a v2 envelope, and seal
|
|
52
|
+
* it to the recipient. Both park sites (the live hook and the crash backstop) call THIS, so the
|
|
53
|
+
* to-be-signed arguments are constructed in exactly one place.
|
|
54
|
+
*
|
|
55
|
+
* Review (hollow-test finding): while the two call sites each built their own signature, a producer
|
|
56
|
+
* that signed the WRONG TBS arguments — e.g. its own pubkey where the recipient's belongs — would
|
|
57
|
+
* emit envelopes no recipient could ever accept, and every consumer-side test would still pass. The
|
|
58
|
+
* bug would only surface as mail that silently never arrives. One producer + a round-trip test
|
|
59
|
+
* against the real consumer removes that whole class: if this function signs the wrong statement,
|
|
60
|
+
* `authenticateParkedEntry` rejects its output and the test goes red.
|
|
61
|
+
*/
|
|
62
|
+
export declare function sealParkEnvelope(args: {
|
|
63
|
+
signer: KeyProvider;
|
|
64
|
+
sessionIdHex: string;
|
|
65
|
+
recipientPubkey: Uint8Array;
|
|
66
|
+
contentHash: Uint8Array;
|
|
67
|
+
content: Uint8Array;
|
|
68
|
+
structure1Cbor?: Uint8Array;
|
|
69
|
+
structure2Cbor?: Uint8Array;
|
|
70
|
+
}): Promise<Uint8Array>;
|
|
71
|
+
/**
|
|
72
|
+
* Decode a park envelope. Legacy shapes (the pre-SEC-1 4-element v1 array, and raw non-CBOR bare
|
|
73
|
+
* content) still DECODE — deliberately, so `authenticate` can reject them with a precise reason
|
|
74
|
+
* rather than the caller seeing an opaque parse failure. Decoding is not accepting.
|
|
75
|
+
*/
|
|
76
|
+
export declare function decodeParkEnvelope(plaintext: Uint8Array): ParkEnvelope;
|
|
77
|
+
/**
|
|
78
|
+
* SEC-1: the authentication decision for a recovered parked entry. FAIL CLOSED — every path that is
|
|
79
|
+
* not a proven-good signature from THIS session's counterparty returns a failure.
|
|
80
|
+
*
|
|
81
|
+
* `counterpartyPubkeyHex` is the session's counterparty (the only principal allowed to have parked
|
|
82
|
+
* content into this session). Pass undefined when the session/counterparty is unknown: that is
|
|
83
|
+
* `counterparty_unknown` and is a REFUSAL, never a bypass — we cannot prove the signer, so we do not
|
|
84
|
+
* trust the content. (Same fail-closed stance the ordering-record check already takes.)
|
|
85
|
+
*/
|
|
86
|
+
export declare function authenticateParkedEntry(args: {
|
|
87
|
+
env: ParkEnvelope;
|
|
88
|
+
sessionIdHex: string;
|
|
89
|
+
recipientPubkey: Uint8Array;
|
|
90
|
+
contentHash: Uint8Array;
|
|
91
|
+
counterpartyPubkeyHex: string | undefined;
|
|
92
|
+
}): ParkAuthVerdict;
|
|
93
|
+
//# sourceMappingURL=park-envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"park-envelope.d.ts","sourceRoot":"","sources":["../src/park-envelope.ts"],"names":[],"mappings":"AA6BA,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGnF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAW3F;AAED,sGAAsG;AACtG,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;IACpB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,6DAA6D;IAC7D,YAAY,CAAC,EAAE,UAAU,CAAC;IAC1B,yEAAyE;IACzE,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED,MAAM,MAAM,eAAe,GACvB,mBAAmB,GACnB,eAAe,GACf,yBAAyB,GACzB,sBAAsB,CAAC;AAE3B,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC;AAEpF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,OAAO,EAAE,UAAU,CAAC;IACpB,YAAY,EAAE,UAAU,CAAC;IACzB,OAAO,EAAE,UAAU,CAAC;IACpB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B,GAAG,UAAU,CASb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,MAAM,EAAE,WAAW,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,UAAU,CAAC;IAC5B,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,EAAE,UAAU,CAAC;IACpB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,cAAc,CAAC,EAAE,UAAU,CAAC;CAC7B,GAAG,OAAO,CAAC,UAAU,CAAC,CAetB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,UAAU,GAAG,YAAY,CA0BtE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,YAAY,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,UAAU,CAAC;IAC5B,WAAW,EAAE,UAAU,CAAC;IACxB,qBAAqB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C,GAAG,eAAe,CA8BlB"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEC-1 — the relay-park content envelope, and its authentication.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. Relay deposit is unauthenticated by design (the blob is E2E-encrypted, so an open
|
|
5
|
+
* deposit cannot LEAK anything) and `sealToRecipient` is an ANONYMOUS public-key seal. Those two
|
|
6
|
+
* facts together mean anyone holding the recipient's PUBLIC key can mint a well-formed sealed entry
|
|
7
|
+
* for their mailbox. Before SEC-1 the recovery path took the sender identity from the SESSION ROW,
|
|
8
|
+
* never from the envelope — so injected content was attributed to the honest counterparty, appended
|
|
9
|
+
* as a Merkle leaf, and then NOTARIZED by the bilateral seal. The party best placed to exploit that
|
|
10
|
+
* is the RELAY ITSELF: the protocol hands it the session_id in plaintext on every deposit and the
|
|
11
|
+
* recipient pubkey is its mailbox key.
|
|
12
|
+
*
|
|
13
|
+
* Confidentiality was mistaken for the whole job. A relay that cannot READ your messages could still
|
|
14
|
+
* WRITE them for you.
|
|
15
|
+
*
|
|
16
|
+
* THE FIX. Every envelope carries a per-message SENDER SIGNATURE over a domain-separated statement
|
|
17
|
+
* bound to (session_id, recipient_pubkey, content_hash) — see `buildParkContentTbs`. It rides INSIDE
|
|
18
|
+
* the seal, so the relay can neither read, strip, nor forge it. Recovery FAILS CLOSED.
|
|
19
|
+
*
|
|
20
|
+
* Note the signature is bound to the sender's own K_local and NOT to the relay's ordering record
|
|
21
|
+
* (Structure1/2). That is deliberate: the ordering record embeds a RELAY-ASSIGNED sequence, so
|
|
22
|
+
* making authenticity depend on it would make the adversary a precondition for trusting content.
|
|
23
|
+
* It also keeps the CELLO-M7-MSG-001 crash backstop working — that path legitimately parks content
|
|
24
|
+
* with no ordering record (the durable awaiting queue does not persist one), and it can still sign.
|
|
25
|
+
*
|
|
26
|
+
* Crypto: Ed25519 (RFC 8032), SHA-256 (FIPS 180-4).
|
|
27
|
+
*/
|
|
28
|
+
import { timingSafeEqual } from "node:crypto";
|
|
29
|
+
import { encode as cborEncode, decode as cborDecode } from "cbor-x";
|
|
30
|
+
import { verify, sealToRecipient } from "@cello-protocol/crypto";
|
|
31
|
+
import { buildParkContentTbs } from "@cello-protocol/protocol-types";
|
|
32
|
+
/**
|
|
33
|
+
* Compare an identity key (raw bytes) against a stored hex pubkey — on BYTES, never on the hex
|
|
34
|
+
* strings.
|
|
35
|
+
*
|
|
36
|
+
* Review M1: `sessions.counterparty_pubkey` is persisted VERBATIM from the IPC `target_pubkey`
|
|
37
|
+
* string with no normalization, so an uppercase or mixed-case pubkey is a perfectly functional
|
|
38
|
+
* session (Buffer.from(hex) is case-insensitive, so dialing, sealing and the direct content path all
|
|
39
|
+
* work) — but a `toString("hex") !== stored` comparison would then refuse EVERY parked recovery for
|
|
40
|
+
* that session as `signer_not_counterparty`, i.e. permanent store-and-forward mail loss reported as
|
|
41
|
+
* an attack. Comparing bytes makes the check independent of how the hex was cased on the way in.
|
|
42
|
+
*
|
|
43
|
+
* Length-guarded because timingSafeEqual throws on a length mismatch, and the input is
|
|
44
|
+
* attacker-controlled (a forged envelope can carry a short/long pubkey).
|
|
45
|
+
*/
|
|
46
|
+
export function pubkeyMatchesHex(pubkey, storedHex) {
|
|
47
|
+
if (!storedHex)
|
|
48
|
+
return false;
|
|
49
|
+
let stored;
|
|
50
|
+
try {
|
|
51
|
+
stored = Buffer.from(storedHex, "hex");
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
// Buffer.from ignores trailing garbage rather than throwing, so a length check is the real guard.
|
|
57
|
+
if (stored.length === 0 || stored.length !== pubkey.length)
|
|
58
|
+
return false;
|
|
59
|
+
return timingSafeEqual(Buffer.from(pubkey), stored);
|
|
60
|
+
}
|
|
61
|
+
/** Current envelope version. v1 (unsigned) is decodable but NEVER acceptable — see authenticate(). */
|
|
62
|
+
export const PARK_ENVELOPE_VERSION = 2;
|
|
63
|
+
/**
|
|
64
|
+
* SEC-1: encode a SIGNED park envelope. `senderPubkey` and `parkSig` are REQUIRED — the type system
|
|
65
|
+
* is the enforcement point, so no call site can construct an unsigned envelope by omission (the
|
|
66
|
+
* exact drift that made this a downgrade attack: verification existed, but was opt-in).
|
|
67
|
+
*/
|
|
68
|
+
export function encodeParkEnvelope(args) {
|
|
69
|
+
return cborEncode([
|
|
70
|
+
PARK_ENVELOPE_VERSION,
|
|
71
|
+
args.content,
|
|
72
|
+
args.structure1Cbor ?? null,
|
|
73
|
+
args.structure2Cbor ?? null,
|
|
74
|
+
args.senderPubkey,
|
|
75
|
+
args.parkSig,
|
|
76
|
+
]);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* SEC-1 — THE ONLY PRODUCER. Sign the entry as the sending agent, wrap it in a v2 envelope, and seal
|
|
80
|
+
* it to the recipient. Both park sites (the live hook and the crash backstop) call THIS, so the
|
|
81
|
+
* to-be-signed arguments are constructed in exactly one place.
|
|
82
|
+
*
|
|
83
|
+
* Review (hollow-test finding): while the two call sites each built their own signature, a producer
|
|
84
|
+
* that signed the WRONG TBS arguments — e.g. its own pubkey where the recipient's belongs — would
|
|
85
|
+
* emit envelopes no recipient could ever accept, and every consumer-side test would still pass. The
|
|
86
|
+
* bug would only surface as mail that silently never arrives. One producer + a round-trip test
|
|
87
|
+
* against the real consumer removes that whole class: if this function signs the wrong statement,
|
|
88
|
+
* `authenticateParkedEntry` rejects its output and the test goes red.
|
|
89
|
+
*/
|
|
90
|
+
export async function sealParkEnvelope(args) {
|
|
91
|
+
const senderPubkey = await args.signer.getPublicKey();
|
|
92
|
+
const parkSig = await args.signer.sign(buildParkContentTbs(args.sessionIdHex, args.recipientPubkey, args.contentHash));
|
|
93
|
+
const envelope = encodeParkEnvelope({
|
|
94
|
+
content: args.content,
|
|
95
|
+
structure1Cbor: args.structure1Cbor,
|
|
96
|
+
structure2Cbor: args.structure2Cbor,
|
|
97
|
+
senderPubkey,
|
|
98
|
+
parkSig,
|
|
99
|
+
});
|
|
100
|
+
// The signature rides INSIDE the seal — the relay (the adversary) never sees it, so it can neither
|
|
101
|
+
// strip nor forge it. INV-3 is untouched: the relay still holds only ciphertext.
|
|
102
|
+
return sealToRecipient(args.recipientPubkey, envelope);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Decode a park envelope. Legacy shapes (the pre-SEC-1 4-element v1 array, and raw non-CBOR bare
|
|
106
|
+
* content) still DECODE — deliberately, so `authenticate` can reject them with a precise reason
|
|
107
|
+
* rather than the caller seeing an opaque parse failure. Decoding is not accepting.
|
|
108
|
+
*/
|
|
109
|
+
export function decodeParkEnvelope(plaintext) {
|
|
110
|
+
try {
|
|
111
|
+
const arr = cborDecode(plaintext);
|
|
112
|
+
if (Array.isArray(arr) && arr.length === 6 && arr[0] === PARK_ENVELOPE_VERSION && arr[1] instanceof Uint8Array) {
|
|
113
|
+
return {
|
|
114
|
+
version: PARK_ENVELOPE_VERSION,
|
|
115
|
+
content: arr[1],
|
|
116
|
+
structure1Cbor: arr[2] instanceof Uint8Array ? arr[2] : undefined,
|
|
117
|
+
structure2Cbor: arr[3] instanceof Uint8Array ? arr[3] : undefined,
|
|
118
|
+
senderPubkey: arr[4] instanceof Uint8Array ? arr[4] : undefined,
|
|
119
|
+
parkSig: arr[5] instanceof Uint8Array ? arr[5] : undefined,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Pre-SEC-1 v1 envelope: [1, content, s1|null, s2|null]. Decoded so it can be REFUSED by name.
|
|
123
|
+
if (Array.isArray(arr) && arr.length === 4 && arr[0] === 1 && arr[1] instanceof Uint8Array) {
|
|
124
|
+
return {
|
|
125
|
+
version: 1,
|
|
126
|
+
content: arr[1],
|
|
127
|
+
structure1Cbor: arr[2] instanceof Uint8Array ? arr[2] : undefined,
|
|
128
|
+
structure2Cbor: arr[3] instanceof Uint8Array ? arr[3] : undefined,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
/* not an envelope — fall through to raw bare content */
|
|
134
|
+
}
|
|
135
|
+
return { version: 1, content: plaintext };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* SEC-1: the authentication decision for a recovered parked entry. FAIL CLOSED — every path that is
|
|
139
|
+
* not a proven-good signature from THIS session's counterparty returns a failure.
|
|
140
|
+
*
|
|
141
|
+
* `counterpartyPubkeyHex` is the session's counterparty (the only principal allowed to have parked
|
|
142
|
+
* content into this session). Pass undefined when the session/counterparty is unknown: that is
|
|
143
|
+
* `counterparty_unknown` and is a REFUSAL, never a bypass — we cannot prove the signer, so we do not
|
|
144
|
+
* trust the content. (Same fail-closed stance the ordering-record check already takes.)
|
|
145
|
+
*/
|
|
146
|
+
export function authenticateParkedEntry(args) {
|
|
147
|
+
const { env, sessionIdHex, recipientPubkey, contentHash, counterpartyPubkeyHex } = args;
|
|
148
|
+
// 1. Unsigned (v1 envelope, or raw bare content) — the shape an attacker sends, and the shape the
|
|
149
|
+
// pre-SEC-1 daemon ingested without a single check. Refused outright.
|
|
150
|
+
if (env.version !== PARK_ENVELOPE_VERSION || !env.senderPubkey || !env.parkSig) {
|
|
151
|
+
return { ok: false, reason: "unsigned_envelope" };
|
|
152
|
+
}
|
|
153
|
+
// 2. Fail closed when there is no counterparty to bind the signer to.
|
|
154
|
+
if (!counterpartyPubkeyHex) {
|
|
155
|
+
return { ok: false, reason: "counterparty_unknown" };
|
|
156
|
+
}
|
|
157
|
+
// 3. The signature must cover THESE bytes, for THIS session, into THIS mailbox. Verified BEFORE
|
|
158
|
+
// the signer check so a forged signature is never mistaken for a wrong-principal one.
|
|
159
|
+
const tbs = buildParkContentTbs(sessionIdHex, recipientPubkey, contentHash);
|
|
160
|
+
if (!verify(env.senderPubkey, tbs, env.parkSig)) {
|
|
161
|
+
return { ok: false, reason: "bad_signature" };
|
|
162
|
+
}
|
|
163
|
+
// 4. The signer MUST be this session's counterparty. A cryptographically valid signature by any
|
|
164
|
+
// other key is still a forgery of THIS conversation. Compared on BYTES (review M1) — the stored
|
|
165
|
+
// hex is un-normalized, so a string compare would turn a mixed-case pubkey into permanent
|
|
166
|
+
// mail loss that looks exactly like an attack in the log.
|
|
167
|
+
if (!pubkeyMatchesHex(env.senderPubkey, counterpartyPubkeyHex)) {
|
|
168
|
+
return { ok: false, reason: "signer_not_counterparty" };
|
|
169
|
+
}
|
|
170
|
+
return { ok: true };
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=park-envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"park-envelope.js","sourceRoot":"","sources":["../src/park-envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry-queue.d.ts","sourceRoot":"","sources":["../src/retry-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wCAAwC;AACxC,eAAO,MAAM,eAAe,OAAO,CAAC;AAEpC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,UAAU,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+CAA+C;AAC/C,MAAM,MAAM,YAAY,GAAG;IAAE,SAAS,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,MAAM,MAAM,QAAQ,GAAG,CAAC,WAAW,EAAE,UAAU,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;sGAIkG;IAClG,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,UAAU,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8DAA8D;AAC9D,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAE1E,qBAAa,UAAU;;gBAUT,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM;IAiD9C;;;OAGG;IACH,UAAU,IAAI,IAAI;IA6FlB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,GAAG,IAAI;IA2E5E;;;;OAIG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAmExE,mDAAmD;IACnD,aAAa,IAAI,MAAM;IAQvB,gDAAgD;IAChD,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI1C,+FAA+F;IAC/F,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE;IAOvD;;;;;OAKG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,GAAG,IAAI;IA0ClH,qEAAqE;IACrE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,GAAG,IAAI;IAoBnF,iEAAiE;IACjE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAI5D,mGAAmG;IACnG,mBAAmB,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAQpE;;;;;OAKG;IACG,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"retry-queue.d.ts","sourceRoot":"","sources":["../src/retry-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wCAAwC;AACxC,eAAO,MAAM,eAAe,OAAO,CAAC;AAEpC,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,UAAU,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+CAA+C;AAC/C,MAAM,MAAM,YAAY,GAAG;IAAE,SAAS,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF,MAAM,MAAM,QAAQ,GAAG,CAAC,WAAW,EAAE,UAAU,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;sGAIkG;IAClG,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,UAAU,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,8DAA8D;AAC9D,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAC7E,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAE1E,qBAAa,UAAU;;gBAUT,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM;IAiD9C;;;OAGG;IACH,UAAU,IAAI,IAAI;IA6FlB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,GAAG,IAAI;IA2E5E;;;;OAIG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAmExE,mDAAmD;IACnD,aAAa,IAAI,MAAM;IAQvB,gDAAgD;IAChD,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAI1C,+FAA+F;IAC/F,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE;IAOvD;;;;;OAKG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,GAAG,IAAI;IA0ClH,qEAAqE;IACrE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,GAAG,IAAI;IAoBnF,iEAAiE;IACjE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAI5D,mGAAmG;IACnG,mBAAmB,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAQpE;;;;;OAKG;IACG,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CA0C/F"}
|
package/dist/retry-queue.js
CHANGED
|
@@ -444,8 +444,20 @@ export class RetryQueue {
|
|
|
444
444
|
catch (err) {
|
|
445
445
|
result = { parked: false, error: err instanceof Error ? err.message : String(err) };
|
|
446
446
|
}
|
|
447
|
-
if (!result.parked)
|
|
447
|
+
if (!result.parked) {
|
|
448
|
+
// Review M3: `result.error` used to be DISCARDED here, so every failure branch of the park
|
|
449
|
+
// target (owning_agent_not_found, no_persisted_relay_endpoint, no_counterparty,
|
|
450
|
+
// standing_receiver_unavailable, and SEC-1's new signing_key_unavailable) failed in total
|
|
451
|
+
// silence — the only trace was `parkedCount: 0`, a number with no reason. The entry is still
|
|
452
|
+
// KEPT for the next flush (AC-019); it just no longer fails quietly.
|
|
453
|
+
this.#logger.warn("content.park.failed", {
|
|
454
|
+
agentId,
|
|
455
|
+
sessionId,
|
|
456
|
+
contentHash: entry.contentHashHex,
|
|
457
|
+
error: result.error,
|
|
458
|
+
});
|
|
448
459
|
continue; // keep for next reconnect / startup flush (AC-019)
|
|
460
|
+
}
|
|
449
461
|
const idx = q.indexOf(entry);
|
|
450
462
|
if (idx !== -1)
|
|
451
463
|
q.splice(idx, 1);
|