@zeph-to/cli 1.27.0 → 1.27.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.
- package/dist/crypto.d.ts +12 -0
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +18 -1
- package/dist/zeph-hook.d.ts +13 -0
- package/dist/zeph-hook.d.ts.map +1 -1
- package/dist/zeph-hook.js +29 -1
- package/package.json +1 -1
package/dist/crypto.d.ts
CHANGED
|
@@ -42,6 +42,18 @@ interface EncryptedPayload {
|
|
|
42
42
|
export declare const initCrypto: (apiKey?: string, baseUrl?: string) => Promise<string>;
|
|
43
43
|
export declare const getKeyPair: () => CryptoKeyPair | null;
|
|
44
44
|
export declare const getPublicKey: () => string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Drop the cached keys so every later send goes out as plaintext.
|
|
47
|
+
*
|
|
48
|
+
* Callers use this when the server rejects an encrypted send with
|
|
49
|
+
* `PRO_REQUIRED` (ADR-0008): E2E is a Pro feature, and a long-lived process
|
|
50
|
+
* that initialized crypto before a downgrade would otherwise 403 on every push.
|
|
51
|
+
* Same end state as the "server says encryption disabled" branch in initCrypto.
|
|
52
|
+
* Keys on disk are left alone, but this process will not pick them up again:
|
|
53
|
+
* `initCrypto` is memoized on `initPromise` and `ZephHook.ensureCrypto` short-
|
|
54
|
+
* circuits on `cryptoInitialized`. A restart after an upgrade re-adopts them.
|
|
55
|
+
*/
|
|
56
|
+
export declare const disableCrypto: () => void;
|
|
45
57
|
/**
|
|
46
58
|
* Encrypt push body for a recipient.
|
|
47
59
|
* Returns fields ready to merge into the sendPush payload.
|
package/dist/crypto.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AA+EH,UAAU,gBAAgB;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AA6ED;;;;;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;AAWF;;;;GAIG;AACH,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE,eAAe,EAAE,MAAM,CAAC;CACzB;AAsBD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAO,OAAO,CAAC,MAAM,CAoBjD,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAO,MAAM,GAAG,IAA+B,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,WAAW,MAAM,EACjB,uBAAuB,MAAM,KAC5B,OAAO,CAAC,yBAAyB,CAKnC,CAAC"}
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AA+EH,UAAU,gBAAgB;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AA6ED;;;;;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;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,QAAO,IAIhC,CAAC;AAEF;;;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;AAWF;;;;GAIG;AACH,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE,eAAe,EAAE,MAAM,CAAC;CACzB;AAsBD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAO,OAAO,CAAC,MAAM,CAoBjD,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAO,MAAM,GAAG,IAA+B,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,WAAW,MAAM,EACjB,uBAAuB,MAAM,KAC5B,OAAO,CAAC,yBAAyB,CAKnC,CAAC"}
|
package/dist/crypto.js
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* sensitive-but-not-secret.
|
|
30
30
|
*/
|
|
31
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
-
exports.encryptEphemeral = exports.getDevicePublicKey = exports.initDeviceCrypto = exports.encryptFileForSelf = exports.encryptFileForRecipient = exports.encryptPushBodyForSelf = exports.encryptPushBody = exports.getPublicKey = exports.getKeyPair = exports.initCrypto = void 0;
|
|
32
|
+
exports.encryptEphemeral = exports.getDevicePublicKey = exports.initDeviceCrypto = exports.encryptFileForSelf = exports.encryptFileForRecipient = exports.encryptPushBodyForSelf = exports.encryptPushBody = exports.disableCrypto = exports.getPublicKey = exports.getKeyPair = exports.initCrypto = void 0;
|
|
33
33
|
/// <reference lib="dom" />
|
|
34
34
|
const fs_1 = require("fs");
|
|
35
35
|
const os_1 = require("os");
|
|
@@ -239,6 +239,23 @@ const getKeyPair = () => cachedKeyPair;
|
|
|
239
239
|
exports.getKeyPair = getKeyPair;
|
|
240
240
|
const getPublicKey = () => cachedExportedPublicKey;
|
|
241
241
|
exports.getPublicKey = getPublicKey;
|
|
242
|
+
/**
|
|
243
|
+
* Drop the cached keys so every later send goes out as plaintext.
|
|
244
|
+
*
|
|
245
|
+
* Callers use this when the server rejects an encrypted send with
|
|
246
|
+
* `PRO_REQUIRED` (ADR-0008): E2E is a Pro feature, and a long-lived process
|
|
247
|
+
* that initialized crypto before a downgrade would otherwise 403 on every push.
|
|
248
|
+
* Same end state as the "server says encryption disabled" branch in initCrypto.
|
|
249
|
+
* Keys on disk are left alone, but this process will not pick them up again:
|
|
250
|
+
* `initCrypto` is memoized on `initPromise` and `ZephHook.ensureCrypto` short-
|
|
251
|
+
* circuits on `cryptoInitialized`. A restart after an upgrade re-adopts them.
|
|
252
|
+
*/
|
|
253
|
+
const disableCrypto = () => {
|
|
254
|
+
cachedKeyPair = null;
|
|
255
|
+
cachedExportedPublicKey = null;
|
|
256
|
+
cachedOwnPublicKey = null;
|
|
257
|
+
};
|
|
258
|
+
exports.disableCrypto = disableCrypto;
|
|
242
259
|
/**
|
|
243
260
|
* Encrypt push body for a recipient.
|
|
244
261
|
* Returns fields ready to merge into the sendPush payload.
|
package/dist/zeph-hook.d.ts
CHANGED
|
@@ -6,7 +6,20 @@ export declare class ZephHook {
|
|
|
6
6
|
private cryptoInitialized;
|
|
7
7
|
constructor(options: ZephOptions);
|
|
8
8
|
private ensureCrypto;
|
|
9
|
+
/**
|
|
10
|
+
* A push must not be lost because E2E turned out to be unavailable.
|
|
11
|
+
*
|
|
12
|
+
* E2E is Pro-only (ADR-0008) and the server rejects `isEncrypted` from a free
|
|
13
|
+
* account with 403 `PRO_REQUIRED`. This process may have initialized crypto
|
|
14
|
+
* while still Pro — a long-lived listener outlives a downgrade — so the
|
|
15
|
+
* rejection is only visible at send time. Drop the keys and run the send
|
|
16
|
+
* again from the top: the retry re-encodes the payload as plaintext and, on
|
|
17
|
+
* the file path, re-uploads the file unencrypted (a payload patch would leave
|
|
18
|
+
* an undecryptable blob in S3). The first, encrypted object stays orphaned —
|
|
19
|
+
* accepted cost; the upload endpoint has no quota counter to burn.
|
|
20
|
+
*/
|
|
9
21
|
notify(payload: NotifyPayload): Promise<NotifyResult>;
|
|
22
|
+
private notifyOnce;
|
|
10
23
|
private notifyWithFile;
|
|
11
24
|
requestUpload(params: {
|
|
12
25
|
fileName: string;
|
package/dist/zeph-hook.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zeph-hook.d.ts","sourceRoot":"","sources":["../src/zeph-hook.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAY,gBAAgB,EAAE,gBAAgB,EAAoB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAoCxL,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,OAAO,EAAE,WAAW;YASlB,YAAY;
|
|
1
|
+
{"version":3,"file":"zeph-hook.d.ts","sourceRoot":"","sources":["../src/zeph-hook.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAY,gBAAgB,EAAE,gBAAgB,EAAoB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAoCxL,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,OAAO,EAAE,WAAW;YASlB,YAAY;IAY1B;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;YAgB7C,UAAU;YAqCV,cAAc;IAsDtB,aAAa,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAK7G,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrF,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAmB9C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAKlD,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAK7C;;;;OAIG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;YASxF,OAAO;IAiCrB,OAAO,CAAC,UAAU;CASnB"}
|
package/dist/zeph-hook.js
CHANGED
|
@@ -63,12 +63,40 @@ class ZephHook {
|
|
|
63
63
|
return false;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* A push must not be lost because E2E turned out to be unavailable.
|
|
68
|
+
*
|
|
69
|
+
* E2E is Pro-only (ADR-0008) and the server rejects `isEncrypted` from a free
|
|
70
|
+
* account with 403 `PRO_REQUIRED`. This process may have initialized crypto
|
|
71
|
+
* while still Pro — a long-lived listener outlives a downgrade — so the
|
|
72
|
+
* rejection is only visible at send time. Drop the keys and run the send
|
|
73
|
+
* again from the top: the retry re-encodes the payload as plaintext and, on
|
|
74
|
+
* the file path, re-uploads the file unencrypted (a payload patch would leave
|
|
75
|
+
* an undecryptable blob in S3). The first, encrypted object stays orphaned —
|
|
76
|
+
* accepted cost; the upload endpoint has no quota counter to burn.
|
|
77
|
+
*/
|
|
66
78
|
async notify(payload) {
|
|
79
|
+
// Resolved once for both attempts: the lookup shells out to tmux, and a
|
|
80
|
+
// retry milliseconds later cannot land in a different session.
|
|
81
|
+
const agentCtx = agentSessionContext();
|
|
82
|
+
try {
|
|
83
|
+
return await this.notifyOnce(payload, agentCtx);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
// Held keys are what proves this send was encrypted, and dropping them is
|
|
87
|
+
// also the recursion guard — the retry has none, so a second 403 propagates.
|
|
88
|
+
if (!(err instanceof errors_js_1.ZephError) || err.code !== 'PRO_REQUIRED' || !(0, crypto_js_1.getKeyPair)())
|
|
89
|
+
throw err;
|
|
90
|
+
(0, crypto_js_1.disableCrypto)();
|
|
91
|
+
console.error('[Crypto] End-to-end encryption requires Zeph Pro — resending as plaintext.');
|
|
92
|
+
return this.notifyOnce(payload, agentCtx);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async notifyOnce(payload, agentCtx) {
|
|
67
96
|
// Attach the stable session key when in a tmux agent session so the push
|
|
68
97
|
// joins the agent chat. Merged into `payload` here so both the inline and
|
|
69
98
|
// file-upload (notifyWithFile) paths — which each spread `...payload` —
|
|
70
99
|
// carry it. Explicit caller values win.
|
|
71
|
-
const agentCtx = agentSessionContext();
|
|
72
100
|
if (agentCtx)
|
|
73
101
|
payload = { ...agentCtx, ...payload };
|
|
74
102
|
const canEncrypt = await this.ensureCrypto();
|