forkoff 1.0.17 → 1.0.18

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 (156) hide show
  1. package/dist/approval.d.ts +1 -0
  2. package/dist/approval.js +9 -0
  3. package/dist/config.d.ts +3 -0
  4. package/dist/config.js +62 -16
  5. package/dist/crypto/e2eeManager.d.ts +49 -52
  6. package/dist/crypto/e2eeManager.js +256 -181
  7. package/dist/crypto/encryption.d.ts +8 -10
  8. package/dist/crypto/encryption.js +29 -94
  9. package/dist/crypto/index.d.ts +10 -0
  10. package/dist/crypto/index.js +22 -0
  11. package/dist/crypto/keyExchange.d.ts +6 -20
  12. package/dist/crypto/keyExchange.js +18 -110
  13. package/dist/crypto/keyGeneration.d.ts +2 -13
  14. package/dist/crypto/keyGeneration.js +14 -88
  15. package/dist/crypto/keyStorage.d.ts +32 -5
  16. package/dist/crypto/keyStorage.js +152 -8
  17. package/dist/crypto/sessionPersistence.d.ts +7 -13
  18. package/dist/crypto/sessionPersistence.js +108 -33
  19. package/dist/crypto/types.d.ts +24 -3
  20. package/dist/crypto/types.js +2 -1
  21. package/dist/crypto/websocketE2EE.d.ts +6 -17
  22. package/dist/crypto/websocketE2EE.js +21 -38
  23. package/dist/index.js +203 -280
  24. package/dist/integration.d.ts +0 -1
  25. package/dist/integration.js +2 -4
  26. package/dist/logger.d.ts +15 -0
  27. package/dist/logger.js +209 -1
  28. package/dist/server.d.ts +30 -0
  29. package/dist/server.js +162 -0
  30. package/dist/startup.js +15 -6
  31. package/dist/terminal.d.ts +1 -0
  32. package/dist/terminal.js +94 -1
  33. package/dist/tools/claude-process.d.ts +8 -0
  34. package/dist/tools/claude-process.js +199 -26
  35. package/dist/tools/claude-sessions.d.ts +1 -0
  36. package/dist/tools/claude-sessions.js +36 -10
  37. package/dist/tools/detector.js +11 -3
  38. package/dist/tools/permission-hook.js +94 -27
  39. package/dist/tools/permission-ipc.d.ts +1 -0
  40. package/dist/tools/permission-ipc.js +61 -14
  41. package/dist/transcript-streamer.d.ts +1 -0
  42. package/dist/transcript-streamer.js +18 -4
  43. package/dist/usage-tracker.d.ts +45 -0
  44. package/dist/usage-tracker.js +243 -0
  45. package/dist/websocket.d.ts +43 -12
  46. package/dist/websocket.js +418 -214
  47. package/package.json +4 -3
  48. package/dist/__tests__/cli-commands.test.d.ts +0 -6
  49. package/dist/__tests__/cli-commands.test.d.ts.map +0 -1
  50. package/dist/__tests__/cli-commands.test.js +0 -213
  51. package/dist/__tests__/cli-commands.test.js.map +0 -1
  52. package/dist/__tests__/crypto/e2e-integration.test.d.ts +0 -17
  53. package/dist/__tests__/crypto/e2e-integration.test.d.ts.map +0 -1
  54. package/dist/__tests__/crypto/e2e-integration.test.js +0 -338
  55. package/dist/__tests__/crypto/e2e-integration.test.js.map +0 -1
  56. package/dist/__tests__/crypto/e2eeManager.test.d.ts +0 -2
  57. package/dist/__tests__/crypto/e2eeManager.test.d.ts.map +0 -1
  58. package/dist/__tests__/crypto/e2eeManager.test.js +0 -242
  59. package/dist/__tests__/crypto/e2eeManager.test.js.map +0 -1
  60. package/dist/__tests__/crypto/encryption.test.d.ts +0 -2
  61. package/dist/__tests__/crypto/encryption.test.d.ts.map +0 -1
  62. package/dist/__tests__/crypto/encryption.test.js +0 -116
  63. package/dist/__tests__/crypto/encryption.test.js.map +0 -1
  64. package/dist/__tests__/crypto/keyExchange.test.d.ts +0 -2
  65. package/dist/__tests__/crypto/keyExchange.test.d.ts.map +0 -1
  66. package/dist/__tests__/crypto/keyExchange.test.js +0 -84
  67. package/dist/__tests__/crypto/keyExchange.test.js.map +0 -1
  68. package/dist/__tests__/crypto/keyGeneration.test.d.ts +0 -2
  69. package/dist/__tests__/crypto/keyGeneration.test.d.ts.map +0 -1
  70. package/dist/__tests__/crypto/keyGeneration.test.js +0 -61
  71. package/dist/__tests__/crypto/keyGeneration.test.js.map +0 -1
  72. package/dist/__tests__/crypto/keyStorage.test.d.ts +0 -2
  73. package/dist/__tests__/crypto/keyStorage.test.d.ts.map +0 -1
  74. package/dist/__tests__/crypto/keyStorage.test.js +0 -133
  75. package/dist/__tests__/crypto/keyStorage.test.js.map +0 -1
  76. package/dist/__tests__/crypto/websocketIntegration.test.d.ts +0 -2
  77. package/dist/__tests__/crypto/websocketIntegration.test.d.ts.map +0 -1
  78. package/dist/__tests__/crypto/websocketIntegration.test.js +0 -259
  79. package/dist/__tests__/crypto/websocketIntegration.test.js.map +0 -1
  80. package/dist/__tests__/startup.test.d.ts +0 -11
  81. package/dist/__tests__/startup.test.d.ts.map +0 -1
  82. package/dist/__tests__/startup.test.js +0 -241
  83. package/dist/__tests__/startup.test.js.map +0 -1
  84. package/dist/__tests__/tools/claude-process.test.d.ts +0 -8
  85. package/dist/__tests__/tools/claude-process.test.d.ts.map +0 -1
  86. package/dist/__tests__/tools/claude-process.test.js +0 -430
  87. package/dist/__tests__/tools/claude-process.test.js.map +0 -1
  88. package/dist/__tests__/tools/permission-hook.test.d.ts +0 -17
  89. package/dist/__tests__/tools/permission-hook.test.d.ts.map +0 -1
  90. package/dist/__tests__/tools/permission-hook.test.js +0 -616
  91. package/dist/__tests__/tools/permission-hook.test.js.map +0 -1
  92. package/dist/__tests__/tools/permission-ipc.test.d.ts +0 -11
  93. package/dist/__tests__/tools/permission-ipc.test.d.ts.map +0 -1
  94. package/dist/__tests__/tools/permission-ipc.test.js +0 -612
  95. package/dist/__tests__/tools/permission-ipc.test.js.map +0 -1
  96. package/dist/__tests__/websocket.test.d.ts +0 -13
  97. package/dist/__tests__/websocket.test.d.ts.map +0 -1
  98. package/dist/__tests__/websocket.test.js +0 -204
  99. package/dist/__tests__/websocket.test.js.map +0 -1
  100. package/dist/api.d.ts +0 -44
  101. package/dist/api.d.ts.map +0 -1
  102. package/dist/api.js +0 -76
  103. package/dist/api.js.map +0 -1
  104. package/dist/approval.d.ts.map +0 -1
  105. package/dist/approval.js.map +0 -1
  106. package/dist/config.d.ts.map +0 -1
  107. package/dist/config.js.map +0 -1
  108. package/dist/crypto/e2eeManager.d.ts.map +0 -1
  109. package/dist/crypto/e2eeManager.js.map +0 -1
  110. package/dist/crypto/encryption.d.ts.map +0 -1
  111. package/dist/crypto/encryption.js.map +0 -1
  112. package/dist/crypto/keyExchange.d.ts.map +0 -1
  113. package/dist/crypto/keyExchange.js.map +0 -1
  114. package/dist/crypto/keyGeneration.d.ts.map +0 -1
  115. package/dist/crypto/keyGeneration.js.map +0 -1
  116. package/dist/crypto/keyStorage.d.ts.map +0 -1
  117. package/dist/crypto/keyStorage.js.map +0 -1
  118. package/dist/crypto/sessionPersistence.d.ts.map +0 -1
  119. package/dist/crypto/sessionPersistence.js.map +0 -1
  120. package/dist/crypto/types.d.ts.map +0 -1
  121. package/dist/crypto/types.js.map +0 -1
  122. package/dist/crypto/websocketE2EE.d.ts.map +0 -1
  123. package/dist/crypto/websocketE2EE.js.map +0 -1
  124. package/dist/index.d.ts.map +0 -1
  125. package/dist/index.js.map +0 -1
  126. package/dist/integration.d.ts.map +0 -1
  127. package/dist/integration.js.map +0 -1
  128. package/dist/logger.d.ts.map +0 -1
  129. package/dist/logger.js.map +0 -1
  130. package/dist/startup.d.ts.map +0 -1
  131. package/dist/startup.js.map +0 -1
  132. package/dist/terminal.d.ts.map +0 -1
  133. package/dist/terminal.js.map +0 -1
  134. package/dist/tools/__tests__/claude-sessions.test.d.ts +0 -2
  135. package/dist/tools/__tests__/claude-sessions.test.d.ts.map +0 -1
  136. package/dist/tools/__tests__/claude-sessions.test.js +0 -306
  137. package/dist/tools/__tests__/claude-sessions.test.js.map +0 -1
  138. package/dist/tools/claude-hooks.d.ts.map +0 -1
  139. package/dist/tools/claude-hooks.js.map +0 -1
  140. package/dist/tools/claude-process.d.ts.map +0 -1
  141. package/dist/tools/claude-process.js.map +0 -1
  142. package/dist/tools/claude-sessions.d.ts.map +0 -1
  143. package/dist/tools/claude-sessions.js.map +0 -1
  144. package/dist/tools/detector.d.ts.map +0 -1
  145. package/dist/tools/detector.js.map +0 -1
  146. package/dist/tools/index.d.ts.map +0 -1
  147. package/dist/tools/index.js.map +0 -1
  148. package/dist/tools/permission-hook.d.ts.map +0 -1
  149. package/dist/tools/permission-hook.js.map +0 -1
  150. package/dist/tools/permission-ipc.d.ts.map +0 -1
  151. package/dist/tools/permission-ipc.js.map +0 -1
  152. package/dist/transcript-streamer.d.ts.map +0 -1
  153. package/dist/transcript-streamer.js.map +0 -1
  154. package/dist/websocket.d.ts.map +0 -1
  155. package/dist/websocket.js.map +0 -1
  156. package/jest.config.js +0 -18
@@ -1,111 +1,46 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
35
5
  Object.defineProperty(exports, "__esModule", { value: true });
36
6
  exports.encrypt = encrypt;
37
7
  exports.decrypt = decrypt;
38
- const crypto = __importStar(require("crypto"));
39
- const ALGORITHM = 'aes-256-gcm';
40
- const NONCE_LENGTH = 12; // 96 bits for AES-GCM
41
- const AUTH_TAG_LENGTH = 16; // 128 bits for AES-GCM
42
8
  /**
43
- * Encrypts plaintext using AES-256-GCM
44
- *
45
- * @param plaintext - Text to encrypt
46
- * @param key - 32-byte encryption key (AES-256)
47
- * @returns EncryptedPayload with Base64-encoded ciphertext, nonce, and authTag
9
+ * Encryption/Decryption Service
10
+ * Uses NaCl secretbox (XSalsa20-Poly1305) for symmetric encryption.
11
+ * Compatible with mobile app's tweetnacl implementation.
12
+ */
13
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
14
+ const tweetnacl_util_1 = require("tweetnacl-util");
15
+ /**
16
+ * Encrypt a plaintext string using NaCl secretbox.
17
+ * @param plaintext - The message to encrypt
18
+ * @param key - 32-byte shared secret key
19
+ * @returns EncryptedPayload with Base64-encoded ciphertext and nonce
48
20
  */
49
21
  function encrypt(plaintext, key) {
50
- if (key.length !== 32) {
51
- throw new Error('Encryption key must be 32 bytes (256 bits)');
52
- }
53
- // Generate random nonce (12 bytes)
54
- const nonce = crypto.randomBytes(NONCE_LENGTH);
55
- // Create cipher
56
- const cipher = crypto.createCipheriv(ALGORITHM, key, nonce);
57
- // Encrypt
58
- const ciphertext = Buffer.concat([
59
- cipher.update(plaintext, 'utf8'),
60
- cipher.final(),
61
- ]);
62
- // Get authentication tag
63
- const authTag = cipher.getAuthTag();
64
- if (authTag.length !== AUTH_TAG_LENGTH) {
65
- throw new Error('Auth tag must be 16 bytes');
66
- }
22
+ const nonce = tweetnacl_1.default.randomBytes(tweetnacl_1.default.secretbox.nonceLength); // 24 bytes
23
+ const messageBytes = (0, tweetnacl_util_1.decodeUTF8)(plaintext);
24
+ const ciphertext = tweetnacl_1.default.secretbox(messageBytes, nonce, key);
67
25
  return {
68
- ciphertext: ciphertext.toString('base64'),
69
- nonce: nonce.toString('base64'),
70
- authTag: authTag.toString('base64'),
26
+ ciphertext: (0, tweetnacl_util_1.encodeBase64)(ciphertext),
27
+ nonce: (0, tweetnacl_util_1.encodeBase64)(nonce),
71
28
  };
72
29
  }
73
30
  /**
74
- * Decrypts ciphertext using AES-256-GCM
75
- *
76
- * @param payload - EncryptedPayload with Base64-encoded ciphertext, nonce, and authTag
77
- * @param key - 32-byte encryption key (AES-256)
78
- * @returns Decrypted plaintext
31
+ * Decrypt an EncryptedPayload back to plaintext.
32
+ * @param payload - The encrypted payload (ciphertext + nonce)
33
+ * @param key - 32-byte shared secret key (must match encryption key)
34
+ * @returns Decrypted plaintext string
79
35
  * @throws Error if decryption fails (wrong key, tampered data, etc.)
80
36
  */
81
37
  function decrypt(payload, key) {
82
- if (key.length !== 32) {
83
- throw new Error('Decryption key must be 32 bytes (256 bits)');
84
- }
85
- // Decode from Base64
86
- const ciphertext = Buffer.from(payload.ciphertext, 'base64');
87
- const nonce = Buffer.from(payload.nonce, 'base64');
88
- const authTag = Buffer.from(payload.authTag, 'base64');
89
- if (nonce.length !== NONCE_LENGTH) {
90
- throw new Error('Nonce must be 12 bytes');
91
- }
92
- if (authTag.length !== AUTH_TAG_LENGTH) {
93
- throw new Error('Auth tag must be 16 bytes');
94
- }
95
- try {
96
- // Create decipher
97
- const decipher = crypto.createDecipheriv(ALGORITHM, key, nonce);
98
- // Set auth tag for verification
99
- decipher.setAuthTag(authTag);
100
- // Decrypt
101
- const plaintext = Buffer.concat([
102
- decipher.update(ciphertext),
103
- decipher.final(),
104
- ]);
105
- return plaintext.toString('utf8');
106
- }
107
- catch (error) {
108
- throw new Error(`Decryption failed: ${error instanceof Error ? error.message : 'unknown error'}`);
38
+ const ciphertext = (0, tweetnacl_util_1.decodeBase64)(payload.ciphertext);
39
+ const nonce = (0, tweetnacl_util_1.decodeBase64)(payload.nonce);
40
+ const decrypted = tweetnacl_1.default.secretbox.open(ciphertext, nonce, key);
41
+ if (!decrypted) {
42
+ throw new Error('E2EE: Decryption failed - message may be tampered or wrong key');
109
43
  }
44
+ return (0, tweetnacl_util_1.encodeUTF8)(decrypted);
110
45
  }
111
46
  //# sourceMappingURL=encryption.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * E2EE Crypto Module - Barrel Export
3
+ */
4
+ export { generateKeyPair } from './keyGeneration';
5
+ export { computeSharedKey } from './keyExchange';
6
+ export { encrypt, decrypt } from './encryption';
7
+ export { storePrivateKey, getPrivateKey, storeSessionKey, getSessionKey, clearSessionKeys } from './keyStorage';
8
+ export { E2EEManager } from './e2eeManager';
9
+ export type { E2EEKeyPair, EncryptedPayload, EncryptedMessage, SessionKeys, KeyExchangeInit, KeyExchangeAck, E2EESessionStatus, } from './types';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.E2EEManager = exports.clearSessionKeys = exports.getSessionKey = exports.storeSessionKey = exports.getPrivateKey = exports.storePrivateKey = exports.decrypt = exports.encrypt = exports.computeSharedKey = exports.generateKeyPair = void 0;
4
+ /**
5
+ * E2EE Crypto Module - Barrel Export
6
+ */
7
+ var keyGeneration_1 = require("./keyGeneration");
8
+ Object.defineProperty(exports, "generateKeyPair", { enumerable: true, get: function () { return keyGeneration_1.generateKeyPair; } });
9
+ var keyExchange_1 = require("./keyExchange");
10
+ Object.defineProperty(exports, "computeSharedKey", { enumerable: true, get: function () { return keyExchange_1.computeSharedKey; } });
11
+ var encryption_1 = require("./encryption");
12
+ Object.defineProperty(exports, "encrypt", { enumerable: true, get: function () { return encryption_1.encrypt; } });
13
+ Object.defineProperty(exports, "decrypt", { enumerable: true, get: function () { return encryption_1.decrypt; } });
14
+ var keyStorage_1 = require("./keyStorage");
15
+ Object.defineProperty(exports, "storePrivateKey", { enumerable: true, get: function () { return keyStorage_1.storePrivateKey; } });
16
+ Object.defineProperty(exports, "getPrivateKey", { enumerable: true, get: function () { return keyStorage_1.getPrivateKey; } });
17
+ Object.defineProperty(exports, "storeSessionKey", { enumerable: true, get: function () { return keyStorage_1.storeSessionKey; } });
18
+ Object.defineProperty(exports, "getSessionKey", { enumerable: true, get: function () { return keyStorage_1.getSessionKey; } });
19
+ Object.defineProperty(exports, "clearSessionKeys", { enumerable: true, get: function () { return keyStorage_1.clearSessionKeys; } });
20
+ var e2eeManager_1 = require("./e2eeManager");
21
+ Object.defineProperty(exports, "E2EEManager", { enumerable: true, get: function () { return e2eeManager_1.E2EEManager; } });
22
+ //# sourceMappingURL=index.js.map
@@ -1,24 +1,10 @@
1
1
  /**
2
- * Computes X25519 shared secret using ECDH
2
+ * Compute a shared secret key from a private key and a remote public key.
3
+ * Uses NaCl's box.before which performs X25519 ECDH + HSalsa20 key derivation.
3
4
  *
4
- * @param privateKey - Base64-encoded X25519 private key (32 bytes)
5
- * @param publicKey - Base64-encoded X25519 public key (32 bytes)
6
- * @returns Shared secret (32 bytes)
5
+ * @param myPrivateKeyB64 - Base64-encoded 32-byte private key
6
+ * @param theirPublicKeyB64 - Base64-encoded 32-byte public key
7
+ * @returns 32-byte shared key suitable for NaCl secretbox encryption
7
8
  */
8
- export declare function computeSharedSecret(privateKey: string, publicKey: string): Uint8Array;
9
- /**
10
- * Derives a session encryption key from a shared secret using HKDF
11
- *
12
- * @param sharedSecret - Shared secret from X25519 key exchange
13
- * @returns Derived session key (32 bytes for AES-256)
14
- */
15
- export declare function deriveSessionKey(sharedSecret: Uint8Array): Uint8Array;
16
- /**
17
- * Performs complete key exchange: computes shared secret and derives session key
18
- *
19
- * @param myPrivateKey - My Base64-encoded X25519 private key
20
- * @param theirPublicKey - Their Base64-encoded X25519 public key
21
- * @returns Derived session encryption key (32 bytes for AES-256-GCM)
22
- */
23
- export declare function performKeyExchange(myPrivateKey: string, theirPublicKey: string): Uint8Array;
9
+ export declare function computeSharedKey(myPrivateKeyB64: string, theirPublicKeyB64: string): Uint8Array;
24
10
  //# sourceMappingURL=keyExchange.d.ts.map
@@ -1,119 +1,27 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
35
5
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.computeSharedSecret = computeSharedSecret;
37
- exports.deriveSessionKey = deriveSessionKey;
38
- exports.performKeyExchange = performKeyExchange;
39
- const crypto = __importStar(require("crypto"));
6
+ exports.computeSharedKey = computeSharedKey;
40
7
  /**
41
- * Computes X25519 shared secret using ECDH
42
- *
43
- * @param privateKey - Base64-encoded X25519 private key (32 bytes)
44
- * @param publicKey - Base64-encoded X25519 public key (32 bytes)
45
- * @returns Shared secret (32 bytes)
46
- */
47
- function computeSharedSecret(privateKey, publicKey) {
48
- const privateKeyBytes = Buffer.from(privateKey, 'base64');
49
- const publicKeyBytes = Buffer.from(publicKey, 'base64');
50
- if (privateKeyBytes.length !== 32) {
51
- throw new Error('Private key must be 32 bytes');
52
- }
53
- if (publicKeyBytes.length !== 32) {
54
- throw new Error('Public key must be 32 bytes');
55
- }
56
- // Create X25519 private key object from raw bytes
57
- const privateKeyObject = crypto.createPrivateKey({
58
- key: Buffer.concat([
59
- // PKCS#8 header for X25519
60
- Buffer.from([
61
- 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e,
62
- 0x04, 0x22, 0x04, 0x20,
63
- ]),
64
- privateKeyBytes,
65
- ]),
66
- format: 'der',
67
- type: 'pkcs8',
68
- });
69
- // Create X25519 public key object from raw bytes
70
- const publicKeyObject = crypto.createPublicKey({
71
- key: Buffer.concat([
72
- // SPKI header for X25519
73
- Buffer.from([
74
- 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
75
- ]),
76
- publicKeyBytes,
77
- ]),
78
- format: 'der',
79
- type: 'spki',
80
- });
81
- // Perform ECDH to compute shared secret
82
- const sharedSecret = crypto.diffieHellman({
83
- privateKey: privateKeyObject,
84
- publicKey: publicKeyObject,
85
- });
86
- return new Uint8Array(sharedSecret);
87
- }
88
- /**
89
- * Derives a session encryption key from a shared secret using HKDF
90
- *
91
- * @param sharedSecret - Shared secret from X25519 key exchange
92
- * @returns Derived session key (32 bytes for AES-256)
8
+ * Key Exchange Service
9
+ * Performs X25519 Diffie-Hellman key exchange using NaCl box.before.
10
+ * Compatible with mobile app's tweetnacl implementation.
93
11
  */
94
- function deriveSessionKey(sharedSecret) {
95
- if (sharedSecret.length !== 32) {
96
- throw new Error('Shared secret must be 32 bytes');
97
- }
98
- // Use HKDF-SHA256 to derive session key
99
- // Info string provides domain separation
100
- const info = Buffer.from('forkoff-e2ee-session-key-v1', 'utf8');
101
- const salt = Buffer.alloc(0); // Empty salt (optional for HKDF)
102
- // Use synchronous HKDF (blocking but fast for 32-byte output)
103
- const derivedKey = crypto.hkdfSync('sha256', Buffer.from(sharedSecret), salt, info, 32 // Output length: 32 bytes for AES-256
104
- );
105
- return new Uint8Array(derivedKey);
106
- }
12
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
13
+ const tweetnacl_util_1 = require("tweetnacl-util");
107
14
  /**
108
- * Performs complete key exchange: computes shared secret and derives session key
15
+ * Compute a shared secret key from a private key and a remote public key.
16
+ * Uses NaCl's box.before which performs X25519 ECDH + HSalsa20 key derivation.
109
17
  *
110
- * @param myPrivateKey - My Base64-encoded X25519 private key
111
- * @param theirPublicKey - Their Base64-encoded X25519 public key
112
- * @returns Derived session encryption key (32 bytes for AES-256-GCM)
18
+ * @param myPrivateKeyB64 - Base64-encoded 32-byte private key
19
+ * @param theirPublicKeyB64 - Base64-encoded 32-byte public key
20
+ * @returns 32-byte shared key suitable for NaCl secretbox encryption
113
21
  */
114
- function performKeyExchange(myPrivateKey, theirPublicKey) {
115
- const sharedSecret = computeSharedSecret(myPrivateKey, theirPublicKey);
116
- const sessionKey = deriveSessionKey(sharedSecret);
117
- return sessionKey;
22
+ function computeSharedKey(myPrivateKeyB64, theirPublicKeyB64) {
23
+ const myPrivateKey = (0, tweetnacl_util_1.decodeBase64)(myPrivateKeyB64);
24
+ const theirPublicKey = (0, tweetnacl_util_1.decodeBase64)(theirPublicKeyB64);
25
+ return tweetnacl_1.default.box.before(theirPublicKey, myPrivateKey);
118
26
  }
119
27
  //# sourceMappingURL=keyExchange.js.map
@@ -1,18 +1,7 @@
1
1
  import { E2EEKeyPair } from './types';
2
2
  /**
3
- * Generates a random X25519 key pair for E2EE
4
- * Uses Node.js crypto module
5
- *
6
- * @returns E2EEKeyPair with Base64-encoded public and private keys (32 bytes each)
3
+ * Generate a new X25519 key pair for Diffie-Hellman key exchange.
4
+ * Uses NaCl's box keypair which generates X25519 keys.
7
5
  */
8
6
  export declare function generateKeyPair(): E2EEKeyPair;
9
- /**
10
- * Generates a deterministic X25519 key pair from a seed
11
- * Useful for testing and key derivation
12
- *
13
- * @param seed - 32-byte buffer to use as the private key seed
14
- * @returns E2EEKeyPair with Base64-encoded public and private keys
15
- * @throws Error if seed is not 32 bytes
16
- */
17
- export declare function generateKeyPairFromSeed(seed: Buffer): E2EEKeyPair;
18
7
  //# sourceMappingURL=keyGeneration.d.ts.map
@@ -1,99 +1,25 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
35
5
  Object.defineProperty(exports, "__esModule", { value: true });
36
6
  exports.generateKeyPair = generateKeyPair;
37
- exports.generateKeyPairFromSeed = generateKeyPairFromSeed;
38
- const crypto = __importStar(require("crypto"));
39
7
  /**
40
- * Generates a random X25519 key pair for E2EE
41
- * Uses Node.js crypto module
42
- *
43
- * @returns E2EEKeyPair with Base64-encoded public and private keys (32 bytes each)
8
+ * Key Generation Service
9
+ * Generates X25519 key pairs for E2EE using tweetnacl.
10
+ * Compatible with mobile app's tweetnacl implementation.
44
11
  */
45
- function generateKeyPair() {
46
- const { publicKey, privateKey } = crypto.generateKeyPairSync('x25519', {
47
- publicKeyEncoding: {
48
- type: 'spki',
49
- format: 'der',
50
- },
51
- privateKeyEncoding: {
52
- type: 'pkcs8',
53
- format: 'der',
54
- },
55
- });
56
- // Extract raw 32-byte keys from DER-encoded buffers
57
- // X25519 public key: last 32 bytes of SPKI
58
- // X25519 private key: last 32 bytes of PKCS8
59
- const rawPublicKey = publicKey.slice(-32);
60
- const rawPrivateKey = privateKey.slice(-32);
61
- return {
62
- publicKey: rawPublicKey.toString('base64'),
63
- privateKey: rawPrivateKey.toString('base64'),
64
- };
65
- }
12
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
13
+ const tweetnacl_util_1 = require("tweetnacl-util");
66
14
  /**
67
- * Generates a deterministic X25519 key pair from a seed
68
- * Useful for testing and key derivation
69
- *
70
- * @param seed - 32-byte buffer to use as the private key seed
71
- * @returns E2EEKeyPair with Base64-encoded public and private keys
72
- * @throws Error if seed is not 32 bytes
15
+ * Generate a new X25519 key pair for Diffie-Hellman key exchange.
16
+ * Uses NaCl's box keypair which generates X25519 keys.
73
17
  */
74
- function generateKeyPairFromSeed(seed) {
75
- if (seed.length !== 32) {
76
- throw new Error('Seed must be exactly 32 bytes');
77
- }
78
- // In X25519, the private key IS the seed (32 random bytes)
79
- // The public key is derived: publicKey = privateKey * basepoint
80
- const privateKeyObject = crypto.createPrivateKey({
81
- key: Buffer.concat([
82
- Buffer.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20]),
83
- seed,
84
- ]),
85
- format: 'der',
86
- type: 'pkcs8',
87
- });
88
- const publicKeyObject = crypto.createPublicKey(privateKeyObject);
89
- // Export raw keys
90
- const publicKeyDER = publicKeyObject.export({ type: 'spki', format: 'der' });
91
- const privateKeyDER = privateKeyObject.export({ type: 'pkcs8', format: 'der' });
92
- const rawPublicKey = publicKeyDER.slice(-32);
93
- const rawPrivateKey = privateKeyDER.slice(-32);
18
+ function generateKeyPair() {
19
+ const keyPair = tweetnacl_1.default.box.keyPair();
94
20
  return {
95
- publicKey: rawPublicKey.toString('base64'),
96
- privateKey: rawPrivateKey.toString('base64'),
21
+ publicKey: (0, tweetnacl_util_1.encodeBase64)(keyPair.publicKey),
22
+ privateKey: (0, tweetnacl_util_1.encodeBase64)(keyPair.secretKey),
97
23
  };
98
24
  }
99
25
  //# sourceMappingURL=keyGeneration.js.map
@@ -1,4 +1,4 @@
1
- import { SessionKeys } from './types';
1
+ import { SessionKeys, SigningKeyPair } from './types';
2
2
  /**
3
3
  * Stores private key in OS keychain
4
4
  * @param deviceId - Device ID
@@ -17,16 +17,16 @@ export declare function getPrivateKey(deviceId: string): Promise<string | null>;
17
17
  */
18
18
  export declare function deletePrivateKey(deviceId: string): Promise<void>;
19
19
  /**
20
- * Stores session encryption key in memory
20
+ * Stores session key in memory
21
21
  * Session keys are ephemeral and not persisted to disk
22
22
  *
23
23
  * @param deviceId - Target device ID
24
- * @param encryptionKey - AES-256-GCM encryption key (32 bytes)
24
+ * @param sharedKey - NaCl secretbox shared key (32 bytes)
25
25
  * @param sessionId - Unique session identifier
26
26
  */
27
- export declare function storeSessionKey(deviceId: string, encryptionKey: Uint8Array, sessionId: string): void;
27
+ export declare function storeSessionKey(deviceId: string, sharedKey: Uint8Array, sessionId: string): void;
28
28
  /**
29
- * Retrieves session encryption key from memory
29
+ * Retrieves session key from memory
30
30
  * @param deviceId - Target device ID
31
31
  * @returns SessionKeys or null if not found
32
32
  */
@@ -36,4 +36,31 @@ export declare function getSessionKey(deviceId: string): SessionKeys | null;
36
36
  * Called on disconnect or logout
37
37
  */
38
38
  export declare function clearSessionKeys(): void;
39
+ /**
40
+ * Stores the Ed25519 signing key pair in OS keychain
41
+ */
42
+ export declare function storeSigningKeyPair(deviceId: string, keyPair: SigningKeyPair): Promise<void>;
43
+ /**
44
+ * Retrieves the Ed25519 signing key pair from OS keychain
45
+ */
46
+ export declare function getSigningKeyPair(deviceId: string): Promise<SigningKeyPair | null>;
47
+ /**
48
+ * Load trusted peer keys from disk into memory.
49
+ * Called once at init time. Validates file ownership and permissions.
50
+ */
51
+ export declare function loadTrustedPeerKeys(): void;
52
+ /**
53
+ * Get the trusted identity public key for a peer device (TOFU).
54
+ * Returns null if no key is stored (first contact).
55
+ */
56
+ export declare function getTrustedPeerKey(deviceId: string): string | null;
57
+ /**
58
+ * Store a peer's identity public key (TOFU — Trust On First Use).
59
+ * Returns false if a DIFFERENT key is already stored (potential MITM).
60
+ */
61
+ export declare function trustPeerKey(deviceId: string, identityPublicKey: string): boolean;
62
+ /**
63
+ * Remove a peer's trusted identity key (used on re-pair to reset TOFU).
64
+ */
65
+ export declare function removeTrustedPeerKey(deviceId: string): void;
39
66
  //# sourceMappingURL=keyStorage.d.ts.map