forkoff 1.0.17 → 1.0.19
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/LICENSE +11 -7
- package/README.md +77 -118
- package/dist/approval.d.ts +1 -0
- package/dist/approval.js +9 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +62 -16
- package/dist/crypto/e2eeManager.d.ts +49 -52
- package/dist/crypto/e2eeManager.js +256 -181
- package/dist/crypto/encryption.d.ts +8 -10
- package/dist/crypto/encryption.js +29 -94
- package/dist/crypto/index.d.ts +10 -0
- package/dist/crypto/index.js +22 -0
- package/dist/crypto/keyExchange.d.ts +6 -20
- package/dist/crypto/keyExchange.js +18 -110
- package/dist/crypto/keyGeneration.d.ts +2 -13
- package/dist/crypto/keyGeneration.js +14 -88
- package/dist/crypto/keyStorage.d.ts +32 -5
- package/dist/crypto/keyStorage.js +152 -8
- package/dist/crypto/sessionPersistence.d.ts +7 -13
- package/dist/crypto/sessionPersistence.js +108 -33
- package/dist/crypto/types.d.ts +24 -3
- package/dist/crypto/types.js +2 -1
- package/dist/crypto/websocketE2EE.d.ts +6 -17
- package/dist/crypto/websocketE2EE.js +21 -38
- package/dist/index.js +203 -280
- package/dist/integration.d.ts +0 -1
- package/dist/integration.js +2 -4
- package/dist/logger.d.ts +15 -0
- package/dist/logger.js +209 -1
- package/dist/server.d.ts +30 -0
- package/dist/server.js +162 -0
- package/dist/startup.js +15 -6
- package/dist/terminal.d.ts +1 -0
- package/dist/terminal.js +94 -1
- package/dist/tools/claude-process.d.ts +8 -0
- package/dist/tools/claude-process.js +199 -26
- package/dist/tools/claude-sessions.d.ts +1 -0
- package/dist/tools/claude-sessions.js +36 -10
- package/dist/tools/detector.js +11 -3
- package/dist/tools/permission-hook.js +94 -27
- package/dist/tools/permission-ipc.d.ts +1 -0
- package/dist/tools/permission-ipc.js +61 -14
- package/dist/transcript-streamer.d.ts +1 -0
- package/dist/transcript-streamer.js +18 -4
- package/dist/usage-tracker.d.ts +45 -0
- package/dist/usage-tracker.js +243 -0
- package/dist/websocket.d.ts +43 -12
- package/dist/websocket.js +418 -214
- package/package.json +5 -4
- package/dist/__tests__/cli-commands.test.d.ts +0 -6
- package/dist/__tests__/cli-commands.test.d.ts.map +0 -1
- package/dist/__tests__/cli-commands.test.js +0 -213
- package/dist/__tests__/cli-commands.test.js.map +0 -1
- package/dist/__tests__/crypto/e2e-integration.test.d.ts +0 -17
- package/dist/__tests__/crypto/e2e-integration.test.d.ts.map +0 -1
- package/dist/__tests__/crypto/e2e-integration.test.js +0 -338
- package/dist/__tests__/crypto/e2e-integration.test.js.map +0 -1
- package/dist/__tests__/crypto/e2eeManager.test.d.ts +0 -2
- package/dist/__tests__/crypto/e2eeManager.test.d.ts.map +0 -1
- package/dist/__tests__/crypto/e2eeManager.test.js +0 -242
- package/dist/__tests__/crypto/e2eeManager.test.js.map +0 -1
- package/dist/__tests__/crypto/encryption.test.d.ts +0 -2
- package/dist/__tests__/crypto/encryption.test.d.ts.map +0 -1
- package/dist/__tests__/crypto/encryption.test.js +0 -116
- package/dist/__tests__/crypto/encryption.test.js.map +0 -1
- package/dist/__tests__/crypto/keyExchange.test.d.ts +0 -2
- package/dist/__tests__/crypto/keyExchange.test.d.ts.map +0 -1
- package/dist/__tests__/crypto/keyExchange.test.js +0 -84
- package/dist/__tests__/crypto/keyExchange.test.js.map +0 -1
- package/dist/__tests__/crypto/keyGeneration.test.d.ts +0 -2
- package/dist/__tests__/crypto/keyGeneration.test.d.ts.map +0 -1
- package/dist/__tests__/crypto/keyGeneration.test.js +0 -61
- package/dist/__tests__/crypto/keyGeneration.test.js.map +0 -1
- package/dist/__tests__/crypto/keyStorage.test.d.ts +0 -2
- package/dist/__tests__/crypto/keyStorage.test.d.ts.map +0 -1
- package/dist/__tests__/crypto/keyStorage.test.js +0 -133
- package/dist/__tests__/crypto/keyStorage.test.js.map +0 -1
- package/dist/__tests__/crypto/websocketIntegration.test.d.ts +0 -2
- package/dist/__tests__/crypto/websocketIntegration.test.d.ts.map +0 -1
- package/dist/__tests__/crypto/websocketIntegration.test.js +0 -259
- package/dist/__tests__/crypto/websocketIntegration.test.js.map +0 -1
- package/dist/__tests__/startup.test.d.ts +0 -11
- package/dist/__tests__/startup.test.d.ts.map +0 -1
- package/dist/__tests__/startup.test.js +0 -241
- package/dist/__tests__/startup.test.js.map +0 -1
- package/dist/__tests__/tools/claude-process.test.d.ts +0 -8
- package/dist/__tests__/tools/claude-process.test.d.ts.map +0 -1
- package/dist/__tests__/tools/claude-process.test.js +0 -430
- package/dist/__tests__/tools/claude-process.test.js.map +0 -1
- package/dist/__tests__/tools/permission-hook.test.d.ts +0 -17
- package/dist/__tests__/tools/permission-hook.test.d.ts.map +0 -1
- package/dist/__tests__/tools/permission-hook.test.js +0 -616
- package/dist/__tests__/tools/permission-hook.test.js.map +0 -1
- package/dist/__tests__/tools/permission-ipc.test.d.ts +0 -11
- package/dist/__tests__/tools/permission-ipc.test.d.ts.map +0 -1
- package/dist/__tests__/tools/permission-ipc.test.js +0 -612
- package/dist/__tests__/tools/permission-ipc.test.js.map +0 -1
- package/dist/__tests__/websocket.test.d.ts +0 -13
- package/dist/__tests__/websocket.test.d.ts.map +0 -1
- package/dist/__tests__/websocket.test.js +0 -204
- package/dist/__tests__/websocket.test.js.map +0 -1
- package/dist/api.d.ts +0 -44
- package/dist/api.d.ts.map +0 -1
- package/dist/api.js +0 -76
- package/dist/api.js.map +0 -1
- package/dist/approval.d.ts.map +0 -1
- package/dist/approval.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/crypto/e2eeManager.d.ts.map +0 -1
- package/dist/crypto/e2eeManager.js.map +0 -1
- package/dist/crypto/encryption.d.ts.map +0 -1
- package/dist/crypto/encryption.js.map +0 -1
- package/dist/crypto/keyExchange.d.ts.map +0 -1
- package/dist/crypto/keyExchange.js.map +0 -1
- package/dist/crypto/keyGeneration.d.ts.map +0 -1
- package/dist/crypto/keyGeneration.js.map +0 -1
- package/dist/crypto/keyStorage.d.ts.map +0 -1
- package/dist/crypto/keyStorage.js.map +0 -1
- package/dist/crypto/sessionPersistence.d.ts.map +0 -1
- package/dist/crypto/sessionPersistence.js.map +0 -1
- package/dist/crypto/types.d.ts.map +0 -1
- package/dist/crypto/types.js.map +0 -1
- package/dist/crypto/websocketE2EE.d.ts.map +0 -1
- package/dist/crypto/websocketE2EE.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integration.d.ts.map +0 -1
- package/dist/integration.js.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/startup.d.ts.map +0 -1
- package/dist/startup.js.map +0 -1
- package/dist/terminal.d.ts.map +0 -1
- package/dist/terminal.js.map +0 -1
- package/dist/tools/__tests__/claude-sessions.test.d.ts +0 -2
- package/dist/tools/__tests__/claude-sessions.test.d.ts.map +0 -1
- package/dist/tools/__tests__/claude-sessions.test.js +0 -306
- package/dist/tools/__tests__/claude-sessions.test.js.map +0 -1
- package/dist/tools/claude-hooks.d.ts.map +0 -1
- package/dist/tools/claude-hooks.js.map +0 -1
- package/dist/tools/claude-process.d.ts.map +0 -1
- package/dist/tools/claude-process.js.map +0 -1
- package/dist/tools/claude-sessions.d.ts.map +0 -1
- package/dist/tools/claude-sessions.js.map +0 -1
- package/dist/tools/detector.d.ts.map +0 -1
- package/dist/tools/detector.js.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/permission-hook.d.ts.map +0 -1
- package/dist/tools/permission-hook.js.map +0 -1
- package/dist/tools/permission-ipc.d.ts.map +0 -1
- package/dist/tools/permission-ipc.js.map +0 -1
- package/dist/transcript-streamer.d.ts.map +0 -1
- package/dist/transcript-streamer.js.map +0 -1
- package/dist/websocket.d.ts.map +0 -1
- package/dist/websocket.js.map +0 -1
- package/jest.config.js +0 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forkoff",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.19",
|
|
4
4
|
"description": "CLI tool to connect your AI coding tools to mobile | Open Beta - Download the app: https://testflight.apple.com/join/dhh5FrN7",
|
|
5
5
|
"main": "dist/integration.js",
|
|
6
6
|
"types": "dist/integration.d.ts",
|
|
@@ -48,9 +48,8 @@
|
|
|
48
48
|
"email": "support@forkoff.app",
|
|
49
49
|
"url": "https://forkoff.app"
|
|
50
50
|
},
|
|
51
|
-
"license": "
|
|
51
|
+
"license": "MIT",
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"axios": "^1.13.2",
|
|
54
53
|
"chalk": "^4.1.2",
|
|
55
54
|
"chokidar": "^3.6.0",
|
|
56
55
|
"commander": "^14.0.2",
|
|
@@ -60,7 +59,9 @@
|
|
|
60
59
|
"node-machine-id": "^1.1.12",
|
|
61
60
|
"ora": "^5.4.1",
|
|
62
61
|
"qrcode-terminal": "^0.12.0",
|
|
63
|
-
"socket.io
|
|
62
|
+
"socket.io": "^4.8.3",
|
|
63
|
+
"tweetnacl": "^1.0.3",
|
|
64
|
+
"tweetnacl-util": "^0.15.1",
|
|
64
65
|
"uuid": "^8.3.2"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli-commands.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli-commands.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Tests for CLI commands: help, unknown command, version
|
|
4
|
-
* Uses createProgram() exported from index.ts
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
// Mock all heavy dependencies so importing index.ts doesn't trigger real connections
|
|
8
|
-
jest.mock('../config', () => ({
|
|
9
|
-
config: {
|
|
10
|
-
deviceId: null,
|
|
11
|
-
deviceName: 'test',
|
|
12
|
-
apiUrl: 'http://localhost:3000',
|
|
13
|
-
wsUrl: 'ws://localhost:3000',
|
|
14
|
-
pairingCode: null,
|
|
15
|
-
pairedAt: null,
|
|
16
|
-
userId: null,
|
|
17
|
-
isPaired: false,
|
|
18
|
-
startupEnabled: null,
|
|
19
|
-
startupBinaryPath: null,
|
|
20
|
-
getPath: () => '/tmp/config.json',
|
|
21
|
-
reset: jest.fn(),
|
|
22
|
-
},
|
|
23
|
-
}));
|
|
24
|
-
jest.mock('../api', () => ({
|
|
25
|
-
api: {
|
|
26
|
-
healthCheck: jest.fn(),
|
|
27
|
-
registerDevice: jest.fn(),
|
|
28
|
-
refreshPairingCode: jest.fn(),
|
|
29
|
-
checkPairingStatus: jest.fn(),
|
|
30
|
-
reportConnectedTools: jest.fn(),
|
|
31
|
-
},
|
|
32
|
-
}));
|
|
33
|
-
jest.mock('../websocket', () => ({
|
|
34
|
-
wsClient: {
|
|
35
|
-
connect: jest.fn(),
|
|
36
|
-
disconnect: jest.fn(),
|
|
37
|
-
isConnected: false,
|
|
38
|
-
on: jest.fn(),
|
|
39
|
-
sendTerminalOutput: jest.fn(),
|
|
40
|
-
sendTerminalCwd: jest.fn(),
|
|
41
|
-
sendClaudeSessionUpdate: jest.fn(),
|
|
42
|
-
sendClaudeSessions: jest.fn(),
|
|
43
|
-
sendToolStatusUpdate: jest.fn(),
|
|
44
|
-
sendDirectoryListResponse: jest.fn(),
|
|
45
|
-
sendReadFileResponse: jest.fn(),
|
|
46
|
-
sendTranscriptHistory: jest.fn(),
|
|
47
|
-
sendTranscriptUpdate: jest.fn(),
|
|
48
|
-
sendClaudeApprovalRequest: jest.fn(),
|
|
49
|
-
sendToolActivity: jest.fn(),
|
|
50
|
-
sendPermissionPrompt: jest.fn(),
|
|
51
|
-
sendClaudeSessionEvent: jest.fn(),
|
|
52
|
-
sendRpcResponse: jest.fn(),
|
|
53
|
-
sendPendingPermissionsSync: jest.fn(),
|
|
54
|
-
sendThinkingContent: jest.fn(),
|
|
55
|
-
sendTokenUsage: jest.fn(),
|
|
56
|
-
sendTaskProgress: jest.fn(),
|
|
57
|
-
},
|
|
58
|
-
}));
|
|
59
|
-
jest.mock('../terminal', () => ({
|
|
60
|
-
terminalManager: {
|
|
61
|
-
on: jest.fn(),
|
|
62
|
-
createSession: jest.fn(),
|
|
63
|
-
executeCommand: jest.fn(),
|
|
64
|
-
},
|
|
65
|
-
}));
|
|
66
|
-
jest.mock('../approval', () => ({
|
|
67
|
-
approvalManager: {
|
|
68
|
-
on: jest.fn(),
|
|
69
|
-
handleApprovalResponse: jest.fn(),
|
|
70
|
-
},
|
|
71
|
-
}));
|
|
72
|
-
jest.mock('../tools', () => ({
|
|
73
|
-
toolDetector: { detectAll: jest.fn(), watchToolStatus: jest.fn() },
|
|
74
|
-
claudeHooksManager: { canConfigure: jest.fn(), installHooks: jest.fn(), uninstallHooks: jest.fn(), isHookConfigured: jest.fn() },
|
|
75
|
-
claudeSessionDetector: {
|
|
76
|
-
isClaudeInstalled: jest.fn().mockReturnValue(false),
|
|
77
|
-
scanSessions: jest.fn().mockReturnValue([]),
|
|
78
|
-
getSessions: jest.fn().mockReturnValue([]),
|
|
79
|
-
startWatching: jest.fn(),
|
|
80
|
-
stopWatching: jest.fn(),
|
|
81
|
-
seedKnownSessions: jest.fn(),
|
|
82
|
-
on: jest.fn(),
|
|
83
|
-
},
|
|
84
|
-
claudeProcessManager: {
|
|
85
|
-
isClaudeSession: jest.fn(),
|
|
86
|
-
sendInput: jest.fn(),
|
|
87
|
-
registerSession: jest.fn(),
|
|
88
|
-
markTakenOver: jest.fn(),
|
|
89
|
-
isTakenOver: jest.fn(),
|
|
90
|
-
startSession: jest.fn(),
|
|
91
|
-
startAndSendMessage: jest.fn(),
|
|
92
|
-
handleApprovalResponse: jest.fn(),
|
|
93
|
-
handlePermissionResponse: jest.fn(),
|
|
94
|
-
updatePermissionRules: jest.fn(),
|
|
95
|
-
clearAllTakenOver: jest.fn(),
|
|
96
|
-
autoAllowAllPendingPrompts: jest.fn(),
|
|
97
|
-
cleanupAllPermissionState: jest.fn(),
|
|
98
|
-
getAllPendingPrompts: jest.fn().mockReturnValue([]),
|
|
99
|
-
on: jest.fn(),
|
|
100
|
-
},
|
|
101
|
-
PermissionIpcManager: {
|
|
102
|
-
cleanupStaleTempFiles: jest.fn(),
|
|
103
|
-
},
|
|
104
|
-
}));
|
|
105
|
-
jest.mock('../transcript-streamer', () => ({
|
|
106
|
-
transcriptStreamer: {
|
|
107
|
-
fetchHistory: jest.fn(),
|
|
108
|
-
subscribeToUpdates: jest.fn(),
|
|
109
|
-
unsubscribeFromUpdates: jest.fn(),
|
|
110
|
-
cleanup: jest.fn(),
|
|
111
|
-
on: jest.fn(),
|
|
112
|
-
},
|
|
113
|
-
}));
|
|
114
|
-
jest.mock('../logger', () => ({
|
|
115
|
-
setQuiet: jest.fn(),
|
|
116
|
-
createSpinner: jest.fn(() => ({
|
|
117
|
-
start: jest.fn().mockReturnThis(),
|
|
118
|
-
stop: jest.fn(),
|
|
119
|
-
succeed: jest.fn(),
|
|
120
|
-
fail: jest.fn(),
|
|
121
|
-
info: jest.fn(),
|
|
122
|
-
warn: jest.fn(),
|
|
123
|
-
text: '',
|
|
124
|
-
})),
|
|
125
|
-
}));
|
|
126
|
-
jest.mock('chalk', () => {
|
|
127
|
-
const handler = {
|
|
128
|
-
get: () => new Proxy((s) => s, handler),
|
|
129
|
-
apply: (_target, _thisArg, args) => args[0],
|
|
130
|
-
};
|
|
131
|
-
return new Proxy((s) => s, handler);
|
|
132
|
-
});
|
|
133
|
-
jest.mock('qrcode-terminal', () => ({
|
|
134
|
-
generate: jest.fn(),
|
|
135
|
-
}));
|
|
136
|
-
jest.mock('../startup', () => ({
|
|
137
|
-
enableStartup: jest.fn(),
|
|
138
|
-
disableStartup: jest.fn(),
|
|
139
|
-
isStartupRegistered: jest.fn().mockReturnValue(false),
|
|
140
|
-
getBinaryPath: jest.fn().mockReturnValue('/usr/local/bin/forkoff'),
|
|
141
|
-
}));
|
|
142
|
-
const index_1 = require("../index");
|
|
143
|
-
describe('CLI commands', () => {
|
|
144
|
-
let consoleLogSpy;
|
|
145
|
-
let consoleErrorSpy;
|
|
146
|
-
beforeEach(() => {
|
|
147
|
-
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
|
|
148
|
-
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
149
|
-
process.exitCode = undefined;
|
|
150
|
-
});
|
|
151
|
-
afterEach(() => {
|
|
152
|
-
consoleLogSpy.mockRestore();
|
|
153
|
-
consoleErrorSpy.mockRestore();
|
|
154
|
-
process.exitCode = undefined;
|
|
155
|
-
});
|
|
156
|
-
describe('help command', () => {
|
|
157
|
-
it('outputs available commands', async () => {
|
|
158
|
-
const program = (0, index_1.createProgram)();
|
|
159
|
-
// Prevent commander from calling process.exit on help
|
|
160
|
-
program.exitOverride();
|
|
161
|
-
let helpOutput = '';
|
|
162
|
-
program.configureOutput({
|
|
163
|
-
writeOut: (str) => { helpOutput += str; },
|
|
164
|
-
writeErr: (str) => { helpOutput += str; },
|
|
165
|
-
});
|
|
166
|
-
try {
|
|
167
|
-
await program.parseAsync(['node', 'forkoff', 'help']);
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
// Commander throws on exitOverride
|
|
171
|
-
}
|
|
172
|
-
// The help action calls program.outputHelp(), check console.log calls
|
|
173
|
-
const allOutput = helpOutput + consoleLogSpy.mock.calls.map((c) => c.join(' ')).join('\n');
|
|
174
|
-
expect(allOutput).toContain('pair');
|
|
175
|
-
expect(allOutput).toContain('connect');
|
|
176
|
-
expect(allOutput).toContain('disconnect');
|
|
177
|
-
expect(allOutput).toContain('status');
|
|
178
|
-
expect(allOutput).toContain('startup');
|
|
179
|
-
expect(allOutput).toContain('config');
|
|
180
|
-
expect(allOutput).toContain('tools');
|
|
181
|
-
expect(allOutput).toContain('help');
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
describe('--version flag', () => {
|
|
185
|
-
it('shows version from package.json', async () => {
|
|
186
|
-
const program = (0, index_1.createProgram)();
|
|
187
|
-
program.exitOverride();
|
|
188
|
-
let versionOutput = '';
|
|
189
|
-
program.configureOutput({
|
|
190
|
-
writeOut: (str) => { versionOutput += str; },
|
|
191
|
-
writeErr: (str) => { versionOutput += str; },
|
|
192
|
-
});
|
|
193
|
-
try {
|
|
194
|
-
await program.parseAsync(['node', 'forkoff', '--version']);
|
|
195
|
-
}
|
|
196
|
-
catch {
|
|
197
|
-
// Commander throws on exitOverride
|
|
198
|
-
}
|
|
199
|
-
const pkg = require('../../package.json');
|
|
200
|
-
expect(versionOutput).toContain(pkg.version);
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
describe('unknown command', () => {
|
|
204
|
-
it('sets process.exitCode = 1 and shows error message', async () => {
|
|
205
|
-
const program = (0, index_1.createProgram)();
|
|
206
|
-
await program.parseAsync(['node', 'forkoff', 'gibberish']);
|
|
207
|
-
expect(process.exitCode).toBe(1);
|
|
208
|
-
const errorOutput = consoleErrorSpy.mock.calls.map((c) => c.join(' ')).join('\n');
|
|
209
|
-
expect(errorOutput).toContain('Unknown command: gibberish');
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
//# sourceMappingURL=cli-commands.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli-commands.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-commands.test.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAEH,qFAAqF;AACrF,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5B,MAAM,EAAE;QACN,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,MAAM;QAClB,MAAM,EAAE,uBAAuB;QAC/B,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,KAAK;QACf,cAAc,EAAE,IAAI;QACpB,iBAAiB,EAAE,IAAI;QACvB,OAAO,EAAE,GAAG,EAAE,CAAC,kBAAkB;QACjC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;KACjB;CACF,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACzB,GAAG,EAAE;QACH,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE;QACtB,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;QACzB,kBAAkB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC7B,kBAAkB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC7B,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE;KAChC;CACF,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/B,QAAQ,EAAE;QACR,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE;QAClB,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE;QACrB,WAAW,EAAE,KAAK;QAClB,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;QACb,kBAAkB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC7B,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE;QAC1B,uBAAuB,EAAE,IAAI,CAAC,EAAE,EAAE;QAClC,kBAAkB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC7B,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC/B,yBAAyB,EAAE,IAAI,CAAC,EAAE,EAAE;QACpC,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC/B,qBAAqB,EAAE,IAAI,CAAC,EAAE,EAAE;QAChC,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC/B,yBAAyB,EAAE,IAAI,CAAC,EAAE,EAAE;QACpC,gBAAgB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC3B,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC/B,sBAAsB,EAAE,IAAI,CAAC,EAAE,EAAE;QACjC,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE;QAC1B,0BAA0B,EAAE,IAAI,CAAC,EAAE,EAAE;QACrC,mBAAmB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC9B,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;QACzB,gBAAgB,EAAE,IAAI,CAAC,EAAE,EAAE;KAC5B;CACF,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9B,eAAe,EAAE;QACf,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;QACb,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE;QACxB,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;KAC1B;CACF,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9B,eAAe,EAAE;QACf,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;QACb,sBAAsB,EAAE,IAAI,CAAC,EAAE,EAAE;KAClC;CACF,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3B,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE;IAClE,kBAAkB,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE;IAChI,qBAAqB,EAAE;QACrB,iBAAiB,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC;QACnD,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;QAC3C,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;QAC1C,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE;QACxB,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE;QACvB,iBAAiB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC5B,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;KACd;IACD,oBAAoB,EAAE;QACpB,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE;QAC1B,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE;QACpB,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE;QAC1B,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE;QACxB,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE;QACtB,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE;QACvB,mBAAmB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC9B,sBAAsB,EAAE,IAAI,CAAC,EAAE,EAAE;QACjC,wBAAwB,EAAE,IAAI,CAAC,EAAE,EAAE;QACnC,qBAAqB,EAAE,IAAI,CAAC,EAAE,EAAE;QAChC,iBAAiB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC5B,0BAA0B,EAAE,IAAI,CAAC,EAAE,EAAE;QACrC,yBAAyB,EAAE,IAAI,CAAC,EAAE,EAAE;QACpC,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC;QACnD,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;KACd;IACD,oBAAoB,EAAE;QACpB,qBAAqB,EAAE,IAAI,CAAC,EAAE,EAAE;KACjC;CACF,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,GAAG,EAAE,CAAC,CAAC;IACzC,kBAAkB,EAAE;QAClB,YAAY,EAAE,IAAI,CAAC,EAAE,EAAE;QACvB,kBAAkB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC7B,sBAAsB,EAAE,IAAI,CAAC,EAAE,EAAE;QACjC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE;QAClB,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;KACd;CACF,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5B,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE;IACnB,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5B,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,cAAc,EAAE;QACjC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;QACf,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE;QAClB,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;QACf,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;QACf,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;QACf,IAAI,EAAE,EAAE;KACT,CAAC,CAAC;CACJ,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;IACtB,MAAM,OAAO,GAAsB;QACjC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC;QAC/C,KAAK,EAAE,CAAC,OAAY,EAAE,QAAa,EAAE,IAAW,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;KAC7D,CAAC;IACF,OAAO,IAAI,KAAK,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC;IAClC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE;CACpB,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7B,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE;IACxB,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;IACzB,mBAAmB,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC;IACrD,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,wBAAwB,CAAC;CACnE,CAAC,CAAC,CAAC;AAEJ,oCAAyC;AAEzC,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAI,aAA+B,CAAC;IACpC,IAAI,eAAiC,CAAC;IAEtC,UAAU,CAAC,GAAG,EAAE;QACd,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,EAAE,CAAC;QAChE,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,EAAE,CAAC;QACpE,OAAO,CAAC,QAAQ,GAAG,SAAgB,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,WAAW,EAAE,CAAC;QAC5B,eAAe,CAAC,WAAW,EAAE,CAAC;QAC9B,OAAO,CAAC,QAAQ,GAAG,SAAgB,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,OAAO,GAAG,IAAA,qBAAa,GAAE,CAAC;YAChC,sDAAsD;YACtD,OAAO,CAAC,YAAY,EAAE,CAAC;YAEvB,IAAI,UAAU,GAAG,EAAE,CAAC;YACpB,OAAO,CAAC,eAAe,CAAC;gBACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,UAAU,IAAI,GAAG,CAAC,CAAC,CAAC;gBACzC,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,UAAU,IAAI,GAAG,CAAC,CAAC,CAAC;aAC1C,CAAC,CAAC;YAEH,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;YACxD,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;YAED,sEAAsE;YACtE,MAAM,SAAS,GAAG,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClG,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YAC1C,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACrC,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,OAAO,GAAG,IAAA,qBAAa,GAAE,CAAC;YAChC,OAAO,CAAC,YAAY,EAAE,CAAC;YAEvB,IAAI,aAAa,GAAG,EAAE,CAAC;YACvB,OAAO,CAAC,eAAe,CAAC;gBACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,aAAa,IAAI,GAAG,CAAC,CAAC,CAAC;gBAC5C,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,aAAa,IAAI,GAAG,CAAC,CAAC,CAAC;aAC7C,CAAC,CAAC;YAEH,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;YAC7D,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;YAED,MAAM,GAAG,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;YAC1C,MAAM,CAAC,aAAa,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;QAC/B,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,OAAO,GAAG,IAAA,qBAAa,GAAE,CAAC;YAEhC,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;YAE3D,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzF,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* End-to-End Integration Test for E2EE
|
|
3
|
-
*
|
|
4
|
-
* Simulates the complete flow:
|
|
5
|
-
* 1. Mobile generates keys → uploads public key
|
|
6
|
-
* 2. CLI generates keys → uploads public key
|
|
7
|
-
* 3. Mobile initiates key exchange with CLI
|
|
8
|
-
* 4. CLI completes key exchange
|
|
9
|
-
* 5. Mobile encrypts message → sends to CLI
|
|
10
|
-
* 6. CLI receives → decrypts → verifies content matches
|
|
11
|
-
* 7. CLI encrypts reply → sends to Mobile
|
|
12
|
-
* 8. Mobile receives → decrypts → verifies content matches
|
|
13
|
-
*
|
|
14
|
-
* This test verifies the complete encrypted communication flow.
|
|
15
|
-
*/
|
|
16
|
-
export {};
|
|
17
|
-
//# sourceMappingURL=e2e-integration.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"e2e-integration.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/crypto/e2e-integration.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* End-to-End Integration Test for E2EE
|
|
4
|
-
*
|
|
5
|
-
* Simulates the complete flow:
|
|
6
|
-
* 1. Mobile generates keys → uploads public key
|
|
7
|
-
* 2. CLI generates keys → uploads public key
|
|
8
|
-
* 3. Mobile initiates key exchange with CLI
|
|
9
|
-
* 4. CLI completes key exchange
|
|
10
|
-
* 5. Mobile encrypts message → sends to CLI
|
|
11
|
-
* 6. CLI receives → decrypts → verifies content matches
|
|
12
|
-
* 7. CLI encrypts reply → sends to Mobile
|
|
13
|
-
* 8. Mobile receives → decrypts → verifies content matches
|
|
14
|
-
*
|
|
15
|
-
* This test verifies the complete encrypted communication flow.
|
|
16
|
-
*/
|
|
17
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
-
if (k2 === undefined) k2 = k;
|
|
19
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
-
}
|
|
23
|
-
Object.defineProperty(o, k2, desc);
|
|
24
|
-
}) : (function(o, m, k, k2) {
|
|
25
|
-
if (k2 === undefined) k2 = k;
|
|
26
|
-
o[k2] = m[k];
|
|
27
|
-
}));
|
|
28
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
-
}) : function(o, v) {
|
|
31
|
-
o["default"] = v;
|
|
32
|
-
});
|
|
33
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
-
var ownKeys = function(o) {
|
|
35
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
-
var ar = [];
|
|
37
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
-
return ar;
|
|
39
|
-
};
|
|
40
|
-
return ownKeys(o);
|
|
41
|
-
};
|
|
42
|
-
return function (mod) {
|
|
43
|
-
if (mod && mod.__esModule) return mod;
|
|
44
|
-
var result = {};
|
|
45
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
-
__setModuleDefault(result, mod);
|
|
47
|
-
return result;
|
|
48
|
-
};
|
|
49
|
-
})();
|
|
50
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
51
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
52
|
-
};
|
|
53
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
-
const e2eeManager_1 = require("../../crypto/e2eeManager");
|
|
55
|
-
const keyStorage = __importStar(require("../../crypto/keyStorage"));
|
|
56
|
-
// Mock keytar
|
|
57
|
-
jest.mock('keytar');
|
|
58
|
-
// Mock axios
|
|
59
|
-
jest.mock('axios');
|
|
60
|
-
const axios_1 = __importDefault(require("axios"));
|
|
61
|
-
const mockAxios = axios_1.default;
|
|
62
|
-
describe('E2EE End-to-End Integration Test', () => {
|
|
63
|
-
let mobileManager;
|
|
64
|
-
let cliManager;
|
|
65
|
-
const mobileDeviceId = 'mobile-device-123';
|
|
66
|
-
const cliDeviceId = 'cli-device-456';
|
|
67
|
-
const apiUrl = 'https://api.forkoff.app/api';
|
|
68
|
-
const sessionId = 'test-session-abc';
|
|
69
|
-
// Mock axios instance
|
|
70
|
-
const mockAxiosInstance = {
|
|
71
|
-
put: jest.fn(),
|
|
72
|
-
get: jest.fn(),
|
|
73
|
-
};
|
|
74
|
-
beforeEach(async () => {
|
|
75
|
-
jest.clearAllMocks();
|
|
76
|
-
keyStorage.clearSessionKeys();
|
|
77
|
-
// Mock axios.create
|
|
78
|
-
mockAxios.create = jest.fn().mockReturnValue(mockAxiosInstance);
|
|
79
|
-
// Mock successful public key uploads
|
|
80
|
-
mockAxiosInstance.put.mockResolvedValue({ data: { success: true, keyVersion: 1 } });
|
|
81
|
-
// Mock public key retrieval - return the actual public keys generated by each manager
|
|
82
|
-
let mobilePublicKey;
|
|
83
|
-
let cliPublicKey;
|
|
84
|
-
const devicePublicKeys = new Map();
|
|
85
|
-
mockAxiosInstance.get.mockImplementation((url) => {
|
|
86
|
-
// Extract device ID from URL
|
|
87
|
-
const match = url.match(/devices\/([^/]+)\/public-key/);
|
|
88
|
-
if (match) {
|
|
89
|
-
const deviceId = match[1];
|
|
90
|
-
if (deviceId === cliDeviceId && cliPublicKey) {
|
|
91
|
-
return Promise.resolve({
|
|
92
|
-
data: { publicKey: cliPublicKey, keyVersion: 1 },
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
else if (deviceId === mobileDeviceId && mobilePublicKey) {
|
|
96
|
-
return Promise.resolve({
|
|
97
|
-
data: { publicKey: mobilePublicKey, keyVersion: 1 },
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
else if (devicePublicKeys.has(deviceId)) {
|
|
101
|
-
return Promise.resolve({
|
|
102
|
-
data: { publicKey: devicePublicKeys.get(deviceId), keyVersion: 1 },
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
// For unknown devices, return a mock public key
|
|
107
|
-
return Promise.resolve({
|
|
108
|
-
data: { publicKey: 'BAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ=', keyVersion: 1 },
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
// Mock key storage for both devices
|
|
112
|
-
jest.spyOn(keyStorage, 'getPrivateKey').mockResolvedValue(null);
|
|
113
|
-
jest.spyOn(keyStorage, 'storePrivateKey').mockResolvedValue();
|
|
114
|
-
// Initialize Mobile E2EE Manager
|
|
115
|
-
mobileManager = new e2eeManager_1.E2EEManager(mobileDeviceId, apiUrl, 'mobile-token');
|
|
116
|
-
await mobileManager.initialize();
|
|
117
|
-
// Capture mobile's public key
|
|
118
|
-
const mobileInitCall = mockAxiosInstance.put.mock.calls.find((call) => call[0].includes(mobileDeviceId));
|
|
119
|
-
mobilePublicKey = mobileInitCall?.[1]?.publicKey;
|
|
120
|
-
// Initialize CLI E2EE Manager
|
|
121
|
-
cliManager = new e2eeManager_1.E2EEManager(cliDeviceId, apiUrl, 'cli-token');
|
|
122
|
-
await cliManager.initialize();
|
|
123
|
-
// Capture CLI's public key
|
|
124
|
-
const cliInitCall = mockAxiosInstance.put.mock.calls.find((call) => call[0].includes(cliDeviceId));
|
|
125
|
-
cliPublicKey = cliInitCall?.[1]?.publicKey;
|
|
126
|
-
});
|
|
127
|
-
afterEach(() => {
|
|
128
|
-
mobileManager.cleanup();
|
|
129
|
-
cliManager.cleanup();
|
|
130
|
-
});
|
|
131
|
-
describe('Complete E2EE Flow', () => {
|
|
132
|
-
it('completes full bidirectional encrypted communication flow', async () => {
|
|
133
|
-
// ============================================================
|
|
134
|
-
// STEP 1: Mobile initiates key exchange with CLI
|
|
135
|
-
// ============================================================
|
|
136
|
-
console.log('\n[TEST] Step 1: Mobile initiates key exchange with CLI');
|
|
137
|
-
const mobileInitPayload = await mobileManager.initiateKeyExchange(cliDeviceId);
|
|
138
|
-
expect(mobileInitPayload).toHaveProperty('senderDeviceId', mobileDeviceId);
|
|
139
|
-
expect(mobileInitPayload).toHaveProperty('ephemeralPublicKey');
|
|
140
|
-
console.log('[TEST] ✓ Mobile generated ephemeral key pair and initiated exchange');
|
|
141
|
-
// ============================================================
|
|
142
|
-
// STEP 2: CLI receives key exchange init and sends ack
|
|
143
|
-
// ============================================================
|
|
144
|
-
console.log('\n[TEST] Step 2: CLI receives key exchange init and sends ack');
|
|
145
|
-
const cliAckPayload = await cliManager.handleKeyExchangeInit(mobileDeviceId, mobileInitPayload.ephemeralPublicKey);
|
|
146
|
-
expect(cliAckPayload).toHaveProperty('recipientDeviceId', cliDeviceId);
|
|
147
|
-
expect(cliAckPayload).toHaveProperty('ephemeralPublicKey');
|
|
148
|
-
expect(cliManager.hasSessionKey(mobileDeviceId)).toBe(true);
|
|
149
|
-
console.log('[TEST] ✓ CLI derived session key and sent ack');
|
|
150
|
-
// ============================================================
|
|
151
|
-
// STEP 3: Mobile receives ack and completes key exchange
|
|
152
|
-
// ============================================================
|
|
153
|
-
console.log('\n[TEST] Step 3: Mobile receives ack and completes key exchange');
|
|
154
|
-
await mobileManager.handleKeyExchangeAck(cliDeviceId, cliAckPayload.ephemeralPublicKey);
|
|
155
|
-
expect(mobileManager.hasSessionKey(cliDeviceId)).toBe(true);
|
|
156
|
-
console.log('[TEST] ✓ Mobile completed key exchange and derived session key');
|
|
157
|
-
// ============================================================
|
|
158
|
-
// STEP 4: Mobile encrypts message and sends to CLI
|
|
159
|
-
// ============================================================
|
|
160
|
-
console.log('\n[TEST] Step 4: Mobile encrypts message and sends to CLI');
|
|
161
|
-
const mobileMessage = 'Hello from mobile! This is a secret message. 🔒';
|
|
162
|
-
const encryptedFromMobile = mobileManager.encryptMessage(mobileMessage, cliDeviceId, sessionId);
|
|
163
|
-
expect(encryptedFromMobile.payload.ciphertext).toBeDefined();
|
|
164
|
-
expect(encryptedFromMobile.payload.ciphertext).not.toContain(mobileMessage);
|
|
165
|
-
expect(encryptedFromMobile.messageCounter).toBe(0);
|
|
166
|
-
console.log('[TEST] ✓ Mobile encrypted message (counter: 0)');
|
|
167
|
-
// ============================================================
|
|
168
|
-
// STEP 5: CLI receives and decrypts mobile's message
|
|
169
|
-
// ============================================================
|
|
170
|
-
console.log('\n[TEST] Step 5: CLI receives and decrypts mobile\'s message');
|
|
171
|
-
const decryptedAtCli = cliManager.decryptMessage(encryptedFromMobile, mobileDeviceId);
|
|
172
|
-
expect(decryptedAtCli).toBe(mobileMessage);
|
|
173
|
-
console.log('[TEST] ✓ CLI successfully decrypted: "' + decryptedAtCli + '"');
|
|
174
|
-
// ============================================================
|
|
175
|
-
// STEP 6: CLI encrypts reply and sends to Mobile
|
|
176
|
-
// ============================================================
|
|
177
|
-
console.log('\n[TEST] Step 6: CLI encrypts reply and sends to Mobile');
|
|
178
|
-
const cliReply = 'Hello from CLI! Message received and understood. ✅';
|
|
179
|
-
const encryptedFromCli = cliManager.encryptMessage(cliReply, mobileDeviceId, sessionId);
|
|
180
|
-
expect(encryptedFromCli.payload.ciphertext).toBeDefined();
|
|
181
|
-
expect(encryptedFromCli.payload.ciphertext).not.toContain(cliReply);
|
|
182
|
-
expect(encryptedFromCli.messageCounter).toBe(0);
|
|
183
|
-
console.log('[TEST] ✓ CLI encrypted reply (counter: 0)');
|
|
184
|
-
// ============================================================
|
|
185
|
-
// STEP 7: Mobile receives and decrypts CLI's reply
|
|
186
|
-
// ============================================================
|
|
187
|
-
console.log('\n[TEST] Step 7: Mobile receives and decrypts CLI\'s reply');
|
|
188
|
-
const decryptedAtMobile = mobileManager.decryptMessage(encryptedFromCli, cliDeviceId);
|
|
189
|
-
expect(decryptedAtMobile).toBe(cliReply);
|
|
190
|
-
console.log('[TEST] ✓ Mobile successfully decrypted: "' + decryptedAtMobile + '"');
|
|
191
|
-
// ============================================================
|
|
192
|
-
// STEP 8: Verify bidirectional communication continues
|
|
193
|
-
// ============================================================
|
|
194
|
-
console.log('\n[TEST] Step 8: Verify bidirectional communication continues');
|
|
195
|
-
const mobileMessage2 = 'Second message from mobile';
|
|
196
|
-
const encrypted2FromMobile = mobileManager.encryptMessage(mobileMessage2, cliDeviceId, sessionId);
|
|
197
|
-
expect(encrypted2FromMobile.messageCounter).toBe(1); // Counter incremented
|
|
198
|
-
const decrypted2AtCli = cliManager.decryptMessage(encrypted2FromMobile, mobileDeviceId);
|
|
199
|
-
expect(decrypted2AtCli).toBe(mobileMessage2);
|
|
200
|
-
console.log('[TEST] ✓ Second message successfully encrypted and decrypted (counter: 1)');
|
|
201
|
-
console.log('\n[TEST] ========================================');
|
|
202
|
-
console.log('[TEST] ✅ FULL E2EE FLOW COMPLETED SUCCESSFULLY');
|
|
203
|
-
console.log('[TEST] ========================================\n');
|
|
204
|
-
});
|
|
205
|
-
it('preserves unicode and emoji in encrypted messages', async () => {
|
|
206
|
-
// Set up E2EE session
|
|
207
|
-
const initPayload = await mobileManager.initiateKeyExchange(cliDeviceId);
|
|
208
|
-
const ackPayload = await cliManager.handleKeyExchangeInit(mobileDeviceId, initPayload.ephemeralPublicKey);
|
|
209
|
-
await mobileManager.handleKeyExchangeAck(cliDeviceId, ackPayload.ephemeralPublicKey);
|
|
210
|
-
// Test unicode and emoji
|
|
211
|
-
const unicodeMessage = 'Hello 世界 🌍 Привет мир 🚀 مرحبا بالعالم ✨';
|
|
212
|
-
const encrypted = mobileManager.encryptMessage(unicodeMessage, cliDeviceId, sessionId);
|
|
213
|
-
const decrypted = cliManager.decryptMessage(encrypted, mobileDeviceId);
|
|
214
|
-
expect(decrypted).toBe(unicodeMessage);
|
|
215
|
-
});
|
|
216
|
-
it('handles large messages (10KB)', async () => {
|
|
217
|
-
// Set up E2EE session
|
|
218
|
-
const initPayload = await mobileManager.initiateKeyExchange(cliDeviceId);
|
|
219
|
-
const ackPayload = await cliManager.handleKeyExchangeInit(mobileDeviceId, initPayload.ephemeralPublicKey);
|
|
220
|
-
await mobileManager.handleKeyExchangeAck(cliDeviceId, ackPayload.ephemeralPublicKey);
|
|
221
|
-
// Test large message
|
|
222
|
-
const largeMessage = 'A'.repeat(10 * 1024); // 10KB
|
|
223
|
-
const encrypted = mobileManager.encryptMessage(largeMessage, cliDeviceId, sessionId);
|
|
224
|
-
const decrypted = cliManager.decryptMessage(encrypted, mobileDeviceId);
|
|
225
|
-
expect(decrypted).toBe(largeMessage);
|
|
226
|
-
expect(decrypted.length).toBe(10 * 1024);
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
describe('Security Properties', () => {
|
|
230
|
-
beforeEach(async () => {
|
|
231
|
-
// Set up E2EE session for security tests
|
|
232
|
-
const initPayload = await mobileManager.initiateKeyExchange(cliDeviceId);
|
|
233
|
-
const ackPayload = await cliManager.handleKeyExchangeInit(mobileDeviceId, initPayload.ephemeralPublicKey);
|
|
234
|
-
await mobileManager.handleKeyExchangeAck(cliDeviceId, ackPayload.ephemeralPublicKey);
|
|
235
|
-
});
|
|
236
|
-
it('rejects replayed messages (replay attack protection)', () => {
|
|
237
|
-
const message1 = 'First message';
|
|
238
|
-
const message2 = 'Second message';
|
|
239
|
-
const encrypted1 = mobileManager.encryptMessage(message1, cliDeviceId, sessionId);
|
|
240
|
-
const encrypted2 = mobileManager.encryptMessage(message2, cliDeviceId, sessionId);
|
|
241
|
-
// Decrypt in order
|
|
242
|
-
cliManager.decryptMessage(encrypted1, mobileDeviceId);
|
|
243
|
-
cliManager.decryptMessage(encrypted2, mobileDeviceId);
|
|
244
|
-
// Try to replay message 1 - should fail
|
|
245
|
-
expect(() => cliManager.decryptMessage(encrypted1, mobileDeviceId)).toThrow(/counter/i);
|
|
246
|
-
});
|
|
247
|
-
it('detects tampered ciphertext', () => {
|
|
248
|
-
const message = 'Secret message';
|
|
249
|
-
const encrypted = mobileManager.encryptMessage(message, cliDeviceId, sessionId);
|
|
250
|
-
// Tamper with ciphertext
|
|
251
|
-
const tamperedCiphertext = Buffer.from(encrypted.payload.ciphertext, 'base64');
|
|
252
|
-
tamperedCiphertext[0] ^= 0xFF;
|
|
253
|
-
encrypted.payload.ciphertext = tamperedCiphertext.toString('base64');
|
|
254
|
-
// Should fail on decryption
|
|
255
|
-
expect(() => cliManager.decryptMessage(encrypted, mobileDeviceId)).toThrow();
|
|
256
|
-
});
|
|
257
|
-
it('detects tampered nonce', () => {
|
|
258
|
-
const message = 'Secret message';
|
|
259
|
-
const encrypted = mobileManager.encryptMessage(message, cliDeviceId, sessionId);
|
|
260
|
-
// Tamper with nonce
|
|
261
|
-
const tamperedNonce = Buffer.from(encrypted.payload.nonce, 'base64');
|
|
262
|
-
tamperedNonce[0] ^= 0xFF;
|
|
263
|
-
encrypted.payload.nonce = tamperedNonce.toString('base64');
|
|
264
|
-
// Should fail on decryption
|
|
265
|
-
expect(() => cliManager.decryptMessage(encrypted, mobileDeviceId)).toThrow();
|
|
266
|
-
});
|
|
267
|
-
it('detects tampered auth tag', () => {
|
|
268
|
-
const message = 'Secret message';
|
|
269
|
-
const encrypted = mobileManager.encryptMessage(message, cliDeviceId, sessionId);
|
|
270
|
-
// Tamper with auth tag
|
|
271
|
-
const tamperedAuthTag = Buffer.from(encrypted.payload.authTag, 'base64');
|
|
272
|
-
tamperedAuthTag[0] ^= 0xFF;
|
|
273
|
-
encrypted.payload.authTag = tamperedAuthTag.toString('base64');
|
|
274
|
-
// Should fail on decryption
|
|
275
|
-
expect(() => cliManager.decryptMessage(encrypted, mobileDeviceId)).toThrow();
|
|
276
|
-
});
|
|
277
|
-
it('prevents message decryption with wrong session key', async () => {
|
|
278
|
-
// Create a third device (attacker)
|
|
279
|
-
const attackerManager = new e2eeManager_1.E2EEManager('attacker-device', apiUrl, 'attacker-token');
|
|
280
|
-
await attackerManager.initialize();
|
|
281
|
-
// Mobile sends encrypted message to CLI
|
|
282
|
-
const message = 'Secret message';
|
|
283
|
-
const encrypted = mobileManager.encryptMessage(message, cliDeviceId, sessionId);
|
|
284
|
-
// Attacker tries to set up their own session with mobile
|
|
285
|
-
const attackerInit = await attackerManager.initiateKeyExchange(mobileDeviceId);
|
|
286
|
-
const attackerAck = await mobileManager.handleKeyExchangeInit('attacker-device', attackerInit.ephemeralPublicKey);
|
|
287
|
-
await attackerManager.handleKeyExchangeAck(mobileDeviceId, attackerAck.ephemeralPublicKey);
|
|
288
|
-
// Attacker intercepts message meant for CLI and tries to decrypt
|
|
289
|
-
// This should fail because the message was encrypted with CLI's session key
|
|
290
|
-
expect(() => attackerManager.decryptMessage(encrypted, mobileDeviceId)).toThrow();
|
|
291
|
-
attackerManager.cleanup();
|
|
292
|
-
});
|
|
293
|
-
});
|
|
294
|
-
describe('Multi-device Support', () => {
|
|
295
|
-
it('maintains multiple concurrent E2EE sessions independently', async () => {
|
|
296
|
-
// Simulate having two separate conversations:
|
|
297
|
-
// 1. Mobile ↔ CLI (already set up)
|
|
298
|
-
// 2. Mobile ↔ Another CLI instance
|
|
299
|
-
// First session: Mobile ↔ CLI
|
|
300
|
-
const init1 = await mobileManager.initiateKeyExchange(cliDeviceId);
|
|
301
|
-
const ack1 = await cliManager.handleKeyExchangeInit(mobileDeviceId, init1.ephemeralPublicKey);
|
|
302
|
-
await mobileManager.handleKeyExchangeAck(cliDeviceId, ack1.ephemeralPublicKey);
|
|
303
|
-
// Verify first session is active
|
|
304
|
-
expect(mobileManager.hasSessionKey(cliDeviceId)).toBe(true);
|
|
305
|
-
expect(cliManager.hasSessionKey(mobileDeviceId)).toBe(true);
|
|
306
|
-
// Simulate a second CLI device (using a fake device ID)
|
|
307
|
-
const cli2DeviceId = 'cli-device-second';
|
|
308
|
-
// Since we can't easily mock a third device with our current setup,
|
|
309
|
-
// let's just verify that the manager can track multiple session keys
|
|
310
|
-
// by checking the state after establishing one session
|
|
311
|
-
// Verify mobileManager is tracking the CLI session
|
|
312
|
-
expect(mobileManager.hasSessionKey(cliDeviceId)).toBe(true);
|
|
313
|
-
// Verify it doesn't have a session with a non-existent device
|
|
314
|
-
expect(mobileManager.hasSessionKey('non-existent-device')).toBe(false);
|
|
315
|
-
// Verify we can send multiple messages to the same device
|
|
316
|
-
const message1 = 'First message to CLI';
|
|
317
|
-
const message2 = 'Second message to CLI';
|
|
318
|
-
const message3 = 'Third message to CLI';
|
|
319
|
-
const encrypted1 = mobileManager.encryptMessage(message1, cliDeviceId, sessionId);
|
|
320
|
-
const encrypted2 = mobileManager.encryptMessage(message2, cliDeviceId, sessionId);
|
|
321
|
-
const encrypted3 = mobileManager.encryptMessage(message3, cliDeviceId, sessionId);
|
|
322
|
-
// Verify message counters increment
|
|
323
|
-
expect(encrypted1.messageCounter).toBe(0);
|
|
324
|
-
expect(encrypted2.messageCounter).toBe(1);
|
|
325
|
-
expect(encrypted3.messageCounter).toBe(2);
|
|
326
|
-
// Verify all messages can be decrypted in order
|
|
327
|
-
const decrypted1 = cliManager.decryptMessage(encrypted1, mobileDeviceId);
|
|
328
|
-
const decrypted2 = cliManager.decryptMessage(encrypted2, mobileDeviceId);
|
|
329
|
-
const decrypted3 = cliManager.decryptMessage(encrypted3, mobileDeviceId);
|
|
330
|
-
expect(decrypted1).toBe(message1);
|
|
331
|
-
expect(decrypted2).toBe(message2);
|
|
332
|
-
expect(decrypted3).toBe(message3);
|
|
333
|
-
// This demonstrates that the session is maintained correctly
|
|
334
|
-
// and can handle multiple sequential messages
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
//# sourceMappingURL=e2e-integration.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"e2e-integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/crypto/e2e-integration.test.ts"],"names":[],"mappings":"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"}
|