@zeph-to/cli 1.13.0 → 1.13.2
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/crypto.d.ts.map +1 -1
- package/dist/crypto.js +7 -1
- package/dist/listener.d.ts +2 -0
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +8 -5
- package/package.json +1 -1
package/dist/crypto.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA2JH;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAsE5E,CAAC;
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA2JH;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAsE5E,CAAC;AA2CF,eAAO,MAAM,UAAU,QAAO,aAAa,GAAG,IAAqB,CAAC;AACpE,eAAO,MAAM,YAAY,QAAO,MAAM,GAAG,IAA+B,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,EACtD,uBAAuB,MAAM,KAC5B,OAAO,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,IAAI,CAAC;CACnB,CAeA,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,GACjC,OAAO;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,KACrD,OAAO,CAAC;IACT,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,IAAI,CAAC;CACnB,CAaA,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,MAAM,EACf,uBAAuB,MAAM,KAC5B,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CASlE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,MAAM,KACd,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAQlE,CAAC"}
|
package/dist/crypto.js
CHANGED
|
@@ -212,13 +212,19 @@ const fetchServerKeys = async (apiKey, baseUrl) => {
|
|
|
212
212
|
return null;
|
|
213
213
|
}
|
|
214
214
|
};
|
|
215
|
+
// SECURITY: only the PUBLIC key is ever sent to the server. The server
|
|
216
|
+
// rejects private-key uploads outright (per-device E2E — escrow removed),
|
|
217
|
+
// and a private key must never leave this host. Sending the full
|
|
218
|
+
// ExportedKeyPair previously leaked the private key onto the wire on every
|
|
219
|
+
// init and the rejection was swallowed silently. The per-device migration
|
|
220
|
+
// (see ADR-0007) reworks this path; until then, register the public key only.
|
|
215
221
|
const uploadServerKeys = async (keys, apiKey, baseUrl) => {
|
|
216
222
|
try {
|
|
217
223
|
const url = `${(baseUrl ?? 'https://api.zeph.to/v1').replace(/\/$/, '')}/users/me/keys`;
|
|
218
224
|
await fetch(url, {
|
|
219
225
|
method: 'PUT',
|
|
220
226
|
headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
|
|
221
|
-
body: JSON.stringify(keys),
|
|
227
|
+
body: JSON.stringify({ publicKey: keys.publicKey }),
|
|
222
228
|
});
|
|
223
229
|
}
|
|
224
230
|
catch { /* non-critical */ }
|
package/dist/listener.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ interface AgentSession {
|
|
|
31
31
|
createdAt?: string;
|
|
32
32
|
lastActivityAt?: string;
|
|
33
33
|
}
|
|
34
|
+
export declare const AUTH_FAILURE_CODES: ReadonlySet<number>;
|
|
34
35
|
export declare const checkRateLimit: (session: string, now?: number) => boolean;
|
|
35
36
|
/** Read the foreground command in the named tmux session's active pane. */
|
|
36
37
|
export declare const paneCurrentCommand: (session: string) => string | null;
|
|
@@ -141,6 +142,7 @@ export declare const gcAttachments: (now?: number, dir?: string, ttl?: number) =
|
|
|
141
142
|
* encrypted pushes, normal text/link/file notifications) is ignored.
|
|
142
143
|
*/
|
|
143
144
|
export declare const handlePush: (push: PushItem, deps?: HandlePushDeps) => Promise<boolean>;
|
|
145
|
+
export declare const computeBackoff: (attempt: number) => number;
|
|
144
146
|
/**
|
|
145
147
|
* Stable per-host device id for the listener. We hash the OS hostname so
|
|
146
148
|
* the same machine reuses the same DeviceRecord across listener restarts
|
package/dist/listener.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAmCH,KAAK,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAG/C,UAAU,YAAY;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"}
|
package/dist/listener.js
CHANGED
|
@@ -25,7 +25,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
25
25
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
26
26
|
};
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
-
exports.handleListener = exports.computeListenerDeviceId = exports.handlePush = exports.gcAttachments = exports.setAttachmentContext = exports.collectSessions = exports.collectSessionsVerbose = exports.detectClaudeSessionId = exports.parseSessionName = exports.invalidateTmuxSocketCache = exports.paneCurrentCommand = exports.checkRateLimit = void 0;
|
|
28
|
+
exports.handleListener = exports.computeListenerDeviceId = exports.computeBackoff = exports.handlePush = exports.gcAttachments = exports.setAttachmentContext = exports.collectSessions = exports.collectSessionsVerbose = exports.detectClaudeSessionId = exports.parseSessionName = exports.invalidateTmuxSocketCache = exports.paneCurrentCommand = exports.checkRateLimit = exports.AUTH_FAILURE_CODES = void 0;
|
|
29
29
|
const child_process_1 = require("child_process");
|
|
30
30
|
const crypto_1 = require("crypto");
|
|
31
31
|
const fs_1 = require("fs");
|
|
@@ -63,7 +63,7 @@ const RATE_LIMIT_WINDOW_MS = 60_000;
|
|
|
63
63
|
const SHELL_COMMANDS = new Set(['bash', 'zsh', 'fish', 'sh', 'dash', 'ksh', 'tcsh', 'csh', 'pwsh']);
|
|
64
64
|
// Auth-failure close codes: retrying with the same bad credentials hammers
|
|
65
65
|
// the server forever, so the listener exits instead.
|
|
66
|
-
|
|
66
|
+
exports.AUTH_FAILURE_CODES = new Set([4001, 4002, 4003]);
|
|
67
67
|
const buckets = new Map();
|
|
68
68
|
// Evict idle buckets older than this so the Map can't grow without bound
|
|
69
69
|
// under attack. Two refill windows past full refill = bucket is at cap
|
|
@@ -679,7 +679,9 @@ const fetchAttachmentBytes = async (fileKey, ctx) => {
|
|
|
679
679
|
const meta = await fetch(metaUrl, { headers: { 'X-API-Key': ctx.apiKey } });
|
|
680
680
|
if (!meta.ok)
|
|
681
681
|
throw new Error(`metadata ${meta.status}`);
|
|
682
|
-
|
|
682
|
+
// Server wraps responses as { data: { downloadUrl } } (see lib/response ok()).
|
|
683
|
+
const body = (await meta.json());
|
|
684
|
+
const downloadUrl = body.data?.downloadUrl ?? body.downloadUrl;
|
|
683
685
|
if (!downloadUrl)
|
|
684
686
|
throw new Error('response had no downloadUrl');
|
|
685
687
|
// The presigned URL is self-authenticating — no API key header.
|
|
@@ -810,6 +812,7 @@ const computeBackoff = (attempt) => {
|
|
|
810
812
|
const jitter = base * RECONNECT_JITTER_RATIO * (Math.random() * 2 - 1);
|
|
811
813
|
return Math.max(0, base + jitter);
|
|
812
814
|
};
|
|
815
|
+
exports.computeBackoff = computeBackoff;
|
|
813
816
|
/**
|
|
814
817
|
* Stable per-host device id for the listener. We hash the OS hostname so
|
|
815
818
|
* the same machine reuses the same DeviceRecord across listener restarts
|
|
@@ -1137,14 +1140,14 @@ const handleListener = async (args) => {
|
|
|
1137
1140
|
activeHandle = streamSession(wsUrl, apiKey);
|
|
1138
1141
|
const result = await activeHandle.done;
|
|
1139
1142
|
activeHandle = null;
|
|
1140
|
-
if (AUTH_FAILURE_CODES.has(result.closeCode ?? -1)) {
|
|
1143
|
+
if (exports.AUTH_FAILURE_CODES.has(result.closeCode ?? -1)) {
|
|
1141
1144
|
console.error(`zeph listener: auth failure (${result.closeCode} ${result.reason}). Check API key.`);
|
|
1142
1145
|
removeListenerPid();
|
|
1143
1146
|
return 3;
|
|
1144
1147
|
}
|
|
1145
1148
|
if (shuttingDown)
|
|
1146
1149
|
break;
|
|
1147
|
-
const delay = computeBackoff(attempt);
|
|
1150
|
+
const delay = (0, exports.computeBackoff)(attempt);
|
|
1148
1151
|
log(`disconnected (code=${result.closeCode}) — reconnect in ${Math.round(delay / 1000)}s`);
|
|
1149
1152
|
await sleep(delay);
|
|
1150
1153
|
attempt = Math.min(attempt + 1, 10);
|