forkoff 1.1.2 → 1.1.4

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.
@@ -118,7 +118,8 @@ class CloudRelayClient extends events_1.EventEmitter {
118
118
  });
119
119
  // Handle mobile connected notification from relay
120
120
  this.socket.on('mobile_connected', (data) => {
121
- console.log(`[CloudRelay] Mobile connected: ${data.deviceId || 'unknown'}`);
121
+ const id = data.deviceId || 'unknown';
122
+ console.log(`[CloudRelay] Mobile connected: ${id.length > 8 ? id.substring(0, 8) + '...' : id}`);
122
123
  this.emit('mobile_connected', { deviceId: data.deviceId || data.mobileDeviceId });
123
124
  });
124
125
  // Handle mobile disconnected notification from relay
@@ -200,10 +200,7 @@ class E2EEManager {
200
200
  const rawSharedKey = (0, keyExchange_1.computeSharedKey)(ephemeral.privateKey, init.ephemeralPublicKey);
201
201
  // Derive directional send/receive keys via HKDF
202
202
  const { sendKey, receiveKey } = (0, keyExchange_1.deriveSessionKeys)(rawSharedKey, this.deviceId, init.senderDeviceId);
203
- // Log key fingerprint for debugging key mismatch
204
- const sendKeyFP = (0, tweetnacl_util_1.encodeBase64)(sendKey).substring(0, 12);
205
- const recvKeyFP = (0, tweetnacl_util_1.encodeBase64)(receiveKey).substring(0, 12);
206
- console.log(`[E2EE] Init: sendKey=${sendKeyFP}, recvKey=${recvKeyFP}, peer=${init.senderDeviceId}, myEphPub=${ephemeral.publicKey.substring(0, 12)}, peerEphPub=${init.ephemeralPublicKey.substring(0, 12)}`);
203
+ console.log(`[E2EE] Key exchange init processed session established with peer ${init.senderDeviceId.substring(0, 8)}...`);
207
204
  // Store session
208
205
  const sessionId = `session-${init.senderDeviceId}-${this.deviceId}-${Date.now()}`;
209
206
  this.sessions.set(init.senderDeviceId, {
@@ -249,7 +246,7 @@ class E2EEManager {
249
246
  // If there's exactly one pending exchange, use it regardless of key.
250
247
  if (!pendingEntry && this.pendingExchanges.size === 1) {
251
248
  const [fallbackKey, fallbackEntry] = this.pendingExchanges.entries().next().value;
252
- console.log(`[E2EE] Pending exchange not found for ${peerId}, falling back to ${fallbackKey}`);
249
+ console.log(`[E2EE] Pending exchange not found for ${peerId.substring(0, 8)}..., using fallback`);
253
250
  pendingEntry = fallbackEntry;
254
251
  pendingKey = fallbackKey;
255
252
  }
@@ -262,10 +259,7 @@ class E2EEManager {
262
259
  const rawSharedKey = (0, keyExchange_1.computeSharedKey)(pending.privateKey, ack.ephemeralPublicKey);
263
260
  // Derive directional send/receive keys via HKDF
264
261
  const { sendKey, receiveKey } = (0, keyExchange_1.deriveSessionKeys)(rawSharedKey, this.deviceId, peerId);
265
- // Log key fingerprint for debugging key mismatch
266
- const sendKeyFP = (0, tweetnacl_util_1.encodeBase64)(sendKey).substring(0, 12);
267
- const recvKeyFP = (0, tweetnacl_util_1.encodeBase64)(receiveKey).substring(0, 12);
268
- console.log(`[E2EE] Ack: sendKey=${sendKeyFP}, recvKey=${recvKeyFP}, peer=${peerId}, myEphPub=${pending.publicKey.substring(0, 12)}, peerEphPub=${ack.ephemeralPublicKey.substring(0, 12)}`);
262
+ console.log(`[E2EE] Key exchange ack processed session established with peer ${peerId.substring(0, 8)}...`);
269
263
  // Store session
270
264
  const sessionId = `session-${this.deviceId}-${peerId}-${Date.now()}`;
271
265
  this.sessions.set(peerId, {
@@ -338,10 +332,8 @@ class E2EEManager {
338
332
  }
339
333
  const payload = (0, encryption_1.encrypt)(plaintext, session.sendKey);
340
334
  session.outgoingCounter++;
341
- // Log encryption key fingerprint (first message only to avoid spam)
342
335
  if (session.outgoingCounter === 1) {
343
- const keyFP = (0, tweetnacl_util_1.encodeBase64)(session.sendKey).substring(0, 12);
344
- console.log(`[E2EE] Encrypting first message with sendKey fingerprint=${keyFP}, recipient=${recipientDeviceId}`);
336
+ console.log(`[E2EE] First encrypted message sent to ${recipientDeviceId.substring(0, 8)}...`);
345
337
  }
346
338
  return {
347
339
  senderDeviceId: this.deviceId,
@@ -374,7 +366,7 @@ class E2EEManager {
374
366
  session.lastReceivedCounter = message.messageCounter;
375
367
  // Check expiry AFTER decrypting — valid messages still get through, but warn caller
376
368
  if (this.isSessionExpired(senderDeviceId)) {
377
- console.warn(`[E2EE] Session with ${senderDeviceId} has expired after decryption — re-key required`);
369
+ console.warn(`[E2EE] Session with ${senderDeviceId.substring(0, 8)}... has expired — re-key required`);
378
370
  }
379
371
  return plaintext;
380
372
  }
package/dist/server.js CHANGED
@@ -71,7 +71,8 @@ class EmbeddedRelayServer extends events_1.EventEmitter {
71
71
  next();
72
72
  });
73
73
  this.io.on('connection', (socket) => {
74
- console.log(`[Server] Mobile connected: ${socket.data.deviceId}`);
74
+ const devId = socket.data.deviceId || 'unknown';
75
+ console.log(`[Server] Mobile connected: ${devId.length > 8 ? devId.substring(0, 8) + '...' : devId}`);
75
76
  // Track the mobile socket (only one active connection)
76
77
  if (this.mobileSocket) {
77
78
  console.log(`[Server] Replacing existing mobile connection`);
package/dist/websocket.js CHANGED
@@ -158,7 +158,7 @@ class WebSocketClient extends events_1.EventEmitter {
158
158
  return;
159
159
  // When mobile connects, emit connected + start heartbeat + initiate E2EE
160
160
  this.server.on('mobile_connected', (data) => {
161
- console.log(`[WS] Mobile connected: ${data.deviceId}`);
161
+ console.log(`[WS] Mobile connected: ${data.deviceId?.substring(0, 8)}...`);
162
162
  this.emit('connected');
163
163
  this.startHeartbeat();
164
164
  // SECURITY: Clear stale E2EE peer state on every mobile connect.
@@ -167,7 +167,7 @@ class WebSocketClient extends events_1.EventEmitter {
167
167
  // that mobile can't decrypt, causing "No session established" errors.
168
168
  // A fresh key exchange will re-establish the session after debounce.
169
169
  if (this.e2eePeerDeviceId) {
170
- console.log(`[E2EE] Clearing stale peer state for ${this.e2eePeerDeviceId} (mobile reconnected)`);
170
+ console.log(`[E2EE] Clearing stale peer state (mobile reconnected)`);
171
171
  this.e2eeManager?.clearSession(this.e2eePeerDeviceId);
172
172
  this.e2eePeerDeviceId = null;
173
173
  }
@@ -188,7 +188,7 @@ class WebSocketClient extends events_1.EventEmitter {
188
188
  return;
189
189
  try {
190
190
  this._keyExchangePending = true;
191
- console.log(`[E2EE] Initiating key exchange with ${targetId} (after debounce)`);
191
+ console.log(`[E2EE] Initiating key exchange with ${targetId.substring(0, 8)}...`);
192
192
  this.e2eeManager.clearSession(targetId);
193
193
  const initPayload = this.e2eeManager.createKeyExchangeInit(targetId);
194
194
  this.server?.emitToMobile('encrypted_key_exchange_init', {
@@ -249,7 +249,7 @@ class WebSocketClient extends events_1.EventEmitter {
249
249
  return;
250
250
  }
251
251
  try {
252
- console.log(`[E2EE] Received key exchange init from ${data.senderDeviceId}`);
252
+ console.log(`[E2EE] Received key exchange init from ${data.senderDeviceId.substring(0, 8)}...`);
253
253
  const ack = this.e2eeManager.handleKeyExchangeInit(data);
254
254
  this.e2eePeerDeviceId = data.senderDeviceId;
255
255
  this.server?.emitToMobile('encrypted_key_exchange_ack', {
@@ -270,11 +270,11 @@ class WebSocketClient extends events_1.EventEmitter {
270
270
  if (!this.e2eeManager)
271
271
  return;
272
272
  try {
273
- console.log(`[E2EE] Received key exchange ack from ${data.senderDeviceId}`);
273
+ console.log(`[E2EE] Received key exchange ack from ${data.senderDeviceId.substring(0, 8)}...`);
274
274
  this.e2eeManager.handleKeyExchangeAck(data);
275
275
  this._keyExchangePending = false;
276
276
  this.e2eePeerDeviceId = data.senderDeviceId;
277
- console.log(`[E2EE] Key exchange complete — session established with ${data.senderDeviceId}`);
277
+ console.log(`[E2EE] Key exchange complete — session established`);
278
278
  this.emit('e2ee_established', { peerDeviceId: data.senderDeviceId });
279
279
  this.flushSensitiveQueue();
280
280
  this.sendAllUsageStats();
@@ -283,7 +283,7 @@ class WebSocketClient extends events_1.EventEmitter {
283
283
  const msg = err instanceof Error ? err.message : String(err);
284
284
  // Only suppress if it's truly a duplicate ack (pending exchange already consumed)
285
285
  if (msg.includes('No pending key exchange')) {
286
- console.log(`[E2EE] Duplicate ack from ${data.senderDeviceId} — ignored`);
286
+ console.log(`[E2EE] Duplicate ack — ignored`);
287
287
  }
288
288
  else {
289
289
  console.error(`[E2EE] Key exchange ack failed: ${msg}`);
@@ -520,7 +520,7 @@ class WebSocketClient extends events_1.EventEmitter {
520
520
  if (sessions.length > 0) {
521
521
  const peer = this.e2eePeerDeviceId;
522
522
  const hasE2EE = peer ? this.e2eeManager?.hasSessionKey(peer) : false;
523
- console.log(`[WS] sendClaudeSessions: ${sessions.length} sessions, peer=${peer || 'none'}, e2ee=${hasE2EE}, queue=${this.pendingSensitiveMessages.length}`);
523
+ console.log(`[WS] sendClaudeSessions: ${sessions.length} sessions, e2ee=${hasE2EE}`);
524
524
  const withDeviceId = sessions.map(s => ({ ...s, deviceId: config_1.config.deviceId }));
525
525
  this.emitSensitive('claude_session_batch_update', { sessions: withDeviceId }, peer ?? undefined);
526
526
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forkoff",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "CLI tool to connect Claude Code to the ForkOff mobile app for remote monitoring and approvals",
5
5
  "main": "dist/integration.js",
6
6
  "types": "dist/integration.d.ts",