Skip to content

Commit 1436ff1

Browse files
committed
feat: Augmented test to be able to accept live config updates.
1 parent bf1c5e0 commit 1436ff1

File tree

1 file changed

+79
-1
lines changed

1 file changed

+79
-1
lines changed

src/connect/socket-server.ts

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { IPty } from '@homebridge/node-pty-prebuilt-multiarch';
2+
import * as fs from 'node:fs/promises';
23
import { Server as HttpServer, IncomingMessage } from 'node:http';
4+
import os from 'node:os';
5+
import path from 'node:path';
36
import { Duplex } from 'node:stream';
47
import { v4 as uuid } from 'uuid';
58
import WebSocket, { WebSocketServer } from 'ws';
@@ -122,10 +125,17 @@ export class SocketServer {
122125
this.mainConnections.set(clientId, ws);
123126
ws.send(JSON.stringify({ key: 'opened', data: { clientId, startTimestamp: this.startTimestamp.toISOString() } }));
124127

125-
ws.on('message', (message) => {
128+
ws.on('message', async (message) => {
126129
const data = JSON.parse(message.toString('utf8'));
130+
127131
if (data.key === 'terminate') {
128132
process.exit(0);
133+
return;
134+
}
135+
136+
if (data.key === 'update-config') {
137+
await this.handleConfigUpdate(ws, data);
138+
return;
129139
}
130140
});
131141

@@ -134,6 +144,74 @@ export class SocketServer {
134144
})
135145
}
136146

147+
private async handleConfigUpdate(ws: WebSocket, data: { sessionId: string; config: string }) {
148+
try {
149+
const { sessionId, config: configContent } = data;
150+
151+
if (!sessionId || !configContent) {
152+
ws.send(JSON.stringify({
153+
key: 'update-config-response',
154+
success: false,
155+
sessionId,
156+
error: 'Missing sessionId or config'
157+
}));
158+
return;
159+
}
160+
161+
const session = this.sessions.get(sessionId);
162+
if (!session) {
163+
ws.send(JSON.stringify({
164+
key: 'update-config-response',
165+
success: false,
166+
sessionId,
167+
error: 'Session not found'
168+
}));
169+
return;
170+
}
171+
172+
const filePath = session.additionalData.filePath as string | undefined;
173+
if (!filePath) {
174+
ws.send(JSON.stringify({
175+
key: 'update-config-response',
176+
success: false,
177+
sessionId,
178+
error: 'File path not found in session'
179+
}));
180+
return;
181+
}
182+
183+
// Security: Ensure file path is in temp directory
184+
const tmpDir = os.tmpdir();
185+
const resolvedPath = path.resolve(filePath);
186+
if (!resolvedPath.startsWith(tmpDir)) {
187+
console.error('Security: Attempted to write outside temp directory', filePath);
188+
ws.send(JSON.stringify({
189+
key: 'update-config-response',
190+
success: false,
191+
sessionId,
192+
error: 'Invalid file path'
193+
}));
194+
return;
195+
}
196+
197+
await fs.writeFile(filePath, configContent, 'utf8');
198+
199+
ws.send(JSON.stringify({
200+
key: 'update-config-response',
201+
success: true,
202+
sessionId
203+
}));
204+
} catch (error) {
205+
console.error('Error updating config:', error);
206+
ws.send(JSON.stringify({
207+
key: 'update-config-response',
208+
success: false,
209+
sessionId: data.sessionId,
210+
error: error instanceof Error ? error.message : 'Unknown error'
211+
}));
212+
}
213+
}
214+
137215
private validateOrigin = (origin: string): boolean =>
138216
config.corsAllowedOrigins.includes(origin)
139217

0 commit comments

Comments
 (0)