avneesh123 commited on
Commit
773a2ba
Β·
verified Β·
1 Parent(s): 483e048

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +45 -34
server.js CHANGED
@@ -25,7 +25,6 @@ const ALLOWED_ORIGINS = [
25
  // ================= SECURE IFRAME LOCK =================
26
  app.use((req, res, next) => {
27
  res.removeHeader("X-Frame-Options");
28
- // Hugging Face compatibility ke liye ancestors ko allow kar rahe hain
29
  res.setHeader(
30
  "Content-Security-Policy",
31
  "frame-ancestors 'self' https://*.hf.space http://localhost:* http://127.0.0.1:*"
@@ -38,7 +37,7 @@ let viteProcess = null;
38
  let isBooting = false;
39
  let buildRetryCount = 0;
40
  const MAX_RETRIES = 3;
41
- const bgProcesses = new Map();
42
 
43
  // ================= PERSISTENT LOCK FILES =================
44
  const FOUNDATION_LOCK = path.join(process.cwd(), ".foundation_lock");
@@ -46,9 +45,9 @@ const DEPS_LOCK = path.join(process.cwd(), ".deps_lock");
46
 
47
  /* ================= BINARY FILE EXTENSIONS ================= */
48
  const BINARY_EXTS = [
49
- ".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".svg",
50
- ".pdf", ".zip", ".tar", ".gz",
51
- ".ttf", ".woff", ".woff2", ".otf", ".eot",
52
  ".mp3", ".mp4", ".wav"
53
  ];
54
 
@@ -73,7 +72,7 @@ setInterval(async () => {
73
  if (idleMs > IDLE_TIMEOUT && viteProcess) {
74
  pushLog(`[IDLE] No activity for ${Math.round(idleMs / 60000)} min β€” stopping Vite to save resources`, "warning");
75
  await killVite();
76
- bgProcesses.forEach((proc, id) => killBgProcess(id));
77
  }
78
  }, 60 * 1000);
79
 
@@ -155,12 +154,23 @@ app.get("/api/logs", (req, res) => {
155
  res.setHeader("Content-Type", "text/event-stream");
156
  res.setHeader("Cache-Control", "no-cache");
157
  res.setHeader("Connection", "keep-alive");
 
 
 
 
158
  const last = parseInt(req.query.last) || 50;
159
- logs.slice(-last).forEach(l => {
160
- res.write(`data: ${JSON.stringify(l)}\n\n`);
161
- });
 
 
 
 
162
  clients.add(res);
163
- req.on("close", () => clients.delete(res));
 
 
 
164
  });
165
 
166
  /* ================= MULTI-SERVER MANAGER ================= */
@@ -177,7 +187,6 @@ function startBgProcess(id, command, port = null) {
177
  });
178
  proc.stdout.on("data", d => pushLog(`[${id.toUpperCase()}] ${d.toString().trim()}`, "info"));
179
  proc.stderr.on("data", d => pushLog(`[${id.toUpperCase()} ERROR] ${d.toString().trim()}`, "error"));
180
-
181
  proc.on("close", code => {
182
  pushLog(`[SERVER] Process ${id} stopped (code: ${code})`, "system");
183
  bgProcesses.delete(id);
@@ -199,7 +208,6 @@ app.post("/api/process/start", (req, res) => {
199
  if (!verifyToken(req, res)) return;
200
  const { id, command, port } = req.body;
201
  if (!id || !command) return res.status(400).json({ error: "ID and command required" });
202
-
203
  const success = startBgProcess(id, command, port);
204
  res.json({ success, message: success ? "Process started" : "Process already running" });
205
  });
@@ -319,17 +327,24 @@ app.post("/api/update", async (req, res) => {
319
  for (const [p, contentObj] of Object.entries(files)) {
320
  const safePath = path.normalize(p).replace(/^(\.\.[\/\\])+/, "");
321
  const fp = path.join(PROJECT_DIR, safePath);
322
-
323
- if (!fp.startsWith(PROJECT_DIR)) continue;
 
 
324
  await fs.ensureDir(path.dirname(fp));
325
- const fileContent = typeof contentObj === 'string' ? contentObj : contentObj.content;
326
- const isBase64 = contentObj.isBase64 || isBinaryFile(safePath);
327
- if (isBase64) {
 
 
 
 
 
 
328
  await fs.writeFile(fp, Buffer.from(fileContent, "base64"));
329
  } else {
330
  await fs.writeFile(fp, fileContent, "utf-8");
331
  }
332
-
333
  updatedFiles.push(safePath);
334
  }
335
  if (!foundationAlreadyWritten) {
@@ -354,13 +369,12 @@ app.post("/api/read", async (req, res) => {
354
  try {
355
  const safePath = path.normalize(filePath).replace(/^(\.\.[\/\\])+/, "");
356
  const fp = path.join(PROJECT_DIR, safePath);
357
-
358
  if (!fp.startsWith(PROJECT_DIR)) return res.status(403).json({ error: "Path traversal blocked" });
359
  if (!fs.existsSync(fp)) return res.status(404).json({ error: "File not found" });
360
  const isBinary = isBinaryFile(safePath);
361
- const content = isBinary
362
- ? await fs.readFile(fp, "base64")
363
- : await fs.readFile(fp, "utf-8");
364
  res.json({ success: true, content, path: safePath, isBase64: isBinary });
365
  } catch (e) {
366
  res.status(500).json({ error: e.message });
@@ -416,7 +430,6 @@ app.post("/api/execute", (req, res) => {
416
  updateActivity(req);
417
  const { command, timeout = 30000 } = req.body;
418
  const isBlocked = BLOCKED_COMMANDS.some(cmd => command.includes(cmd));
419
-
420
  if (isBlocked) {
421
  pushLog(`[SECURITY] Blocked dangerous command: ${command}`, "error");
422
  return res.status(403).json({ error: "COMMAND_BLOCKED" });
@@ -462,9 +475,9 @@ app.post("/api/vite/stop", async (req, res) => {
462
  app.post("/api/reset", async (req, res) => {
463
  if (!verifyToken(req, res)) return;
464
  try {
465
- pushLog("[SYSTEM] πŸ”„ Resetting project...", "warning");
466
  await killVite();
467
- bgProcesses.forEach((proc, id) => killBgProcess(id));
468
  await fs.remove(PROJECT_DIR);
469
  fs.mkdirSync(PROJECT_DIR, { recursive: true });
470
  if (fs.existsSync(FOUNDATION_LOCK)) fs.removeSync(FOUNDATION_LOCK);
@@ -488,13 +501,10 @@ const PREVIEW_SECRET = "AUTODEV_PREVIEW_777";
488
  const ACCESS_DENIED_PAGE = `<!DOCTYPE html><html><head><title>Access Denied</title><style>body{background:#09090b;color:#fff;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;flex-direction:column;gap:16px;}.title{color:#ef4444;font-size:1.4rem;font-weight:bold;}</style></head><body><div class="title">ACCESS DENIED</div><div>This preview is protected</div></body></html>`;
489
  const BOOTING_PAGE = `<!DOCTYPE html><html><head><title>Booting...</title><style>body{background:#09090b;color:#facc15;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;}</style><script>setTimeout(()=>location.reload(), 2000)</script></head><body>⚑ AutoDev is booting up...</body></html>`;
490
 
491
- // Proxy Response Header Modification to break Iframe Locks
492
- proxy.on("proxyRes", (proxyRes, req, res) => {
493
- delete proxyRes.headers["x-frame-options"];
494
- delete proxyRes.headers["content-security-policy"];
495
- res.setHeader("Content-Security-Policy", "frame-ancestors *");
496
- res.setHeader("X-Frame-Options", "ALLOWALL");
497
- });
498
 
499
  proxy.on("error", (err, req, res) => {
500
  if (res && typeof res.writeHead === "function") {
@@ -514,6 +524,7 @@ app.use((req, res, next) => {
514
  const previewHeader = req.headers["x-autodev-preview"];
515
  const previewParam = req.query["__autodev"];
516
  if (previewHeader !== PREVIEW_SECRET && previewParam !== PREVIEW_SECRET) {
 
517
  return res.status(403).send(ACCESS_DENIED_PAGE);
518
  }
519
  }
@@ -532,13 +543,13 @@ server.on("upgrade", (req, socket, head) => proxy.ws(req, socket, head));
532
  process.on("SIGTERM", async () => {
533
  pushLog("[SYSTEM] Shutting down...", "system");
534
  await killVite();
535
- bgProcesses.forEach((proc, id) => killBgProcess(id));
536
  process.exit(0);
537
  });
538
 
539
  process.on("SIGINT", async () => {
540
  await killVite();
541
- bgProcesses.forEach((proc, id) => killBgProcess(id));
542
  process.exit(0);
543
  });
544
 
 
25
  // ================= SECURE IFRAME LOCK =================
26
  app.use((req, res, next) => {
27
  res.removeHeader("X-Frame-Options");
 
28
  res.setHeader(
29
  "Content-Security-Policy",
30
  "frame-ancestors 'self' https://*.hf.space http://localhost:* http://127.0.0.1:*"
 
37
  let isBooting = false;
38
  let buildRetryCount = 0;
39
  const MAX_RETRIES = 3;
40
+ const bgProcesses = new Map();
41
 
42
  // ================= PERSISTENT LOCK FILES =================
43
  const FOUNDATION_LOCK = path.join(process.cwd(), ".foundation_lock");
 
45
 
46
  /* ================= BINARY FILE EXTENSIONS ================= */
47
  const BINARY_EXTS = [
48
+ ".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".svg",
49
+ ".pdf", ".zip", ".tar", ".gz",
50
+ ".ttf", ".woff", ".woff2", ".otf", ".eot",
51
  ".mp3", ".mp4", ".wav"
52
  ];
53
 
 
72
  if (idleMs > IDLE_TIMEOUT && viteProcess) {
73
  pushLog(`[IDLE] No activity for ${Math.round(idleMs / 60000)} min β€” stopping Vite to save resources`, "warning");
74
  await killVite();
75
+ bgProcesses.forEach((_, id) => killBgProcess(id));
76
  }
77
  }, 60 * 1000);
78
 
 
154
  res.setHeader("Content-Type", "text/event-stream");
155
  res.setHeader("Cache-Control", "no-cache");
156
  res.setHeader("Connection", "keep-alive");
157
+ // BUG FIX #1: X-Accel-Buffering missing tha β€” HF/nginx ke peeche SSE buffer
158
+ // ho jaata tha, logs real-time nahi aate the client tak
159
+ res.setHeader("X-Accel-Buffering", "no");
160
+
161
  const last = parseInt(req.query.last) || 50;
162
+ logs.slice(-last).forEach(l => res.write(`data: ${JSON.stringify(l)}\n\n`));
163
+
164
+ // Heartbeat β€” 30s mein connection alive rakhne ke liye
165
+ const heartbeat = setInterval(() => {
166
+ try { res.write(`: heartbeat\n\n`); } catch { clearInterval(heartbeat); }
167
+ }, 30000);
168
+
169
  clients.add(res);
170
+ req.on("close", () => {
171
+ clients.delete(res);
172
+ clearInterval(heartbeat);
173
+ });
174
  });
175
 
176
  /* ================= MULTI-SERVER MANAGER ================= */
 
187
  });
188
  proc.stdout.on("data", d => pushLog(`[${id.toUpperCase()}] ${d.toString().trim()}`, "info"));
189
  proc.stderr.on("data", d => pushLog(`[${id.toUpperCase()} ERROR] ${d.toString().trim()}`, "error"));
 
190
  proc.on("close", code => {
191
  pushLog(`[SERVER] Process ${id} stopped (code: ${code})`, "system");
192
  bgProcesses.delete(id);
 
208
  if (!verifyToken(req, res)) return;
209
  const { id, command, port } = req.body;
210
  if (!id || !command) return res.status(400).json({ error: "ID and command required" });
 
211
  const success = startBgProcess(id, command, port);
212
  res.json({ success, message: success ? "Process started" : "Process already running" });
213
  });
 
327
  for (const [p, contentObj] of Object.entries(files)) {
328
  const safePath = path.normalize(p).replace(/^(\.\.[\/\\])+/, "");
329
  const fp = path.join(PROJECT_DIR, safePath);
330
+ if (!fp.startsWith(PROJECT_DIR)) {
331
+ pushLog(`[SECURITY] Blocked path traversal: ${p}`, "error");
332
+ continue;
333
+ }
334
  await fs.ensureDir(path.dirname(fp));
335
+ // BUG FIX #2: contentObj null/undefined hone par crash hota tha
336
+ // typeof check se pehle null guard lagao
337
+ const fileContent = contentObj == null
338
+ ? ""
339
+ : typeof contentObj === "string"
340
+ ? contentObj
341
+ : contentObj.content ?? "";
342
+ const isBase64 = contentObj?.isBase64 || isBinaryFile(safePath);
343
+ if (isBase64 && fileContent) {
344
  await fs.writeFile(fp, Buffer.from(fileContent, "base64"));
345
  } else {
346
  await fs.writeFile(fp, fileContent, "utf-8");
347
  }
 
348
  updatedFiles.push(safePath);
349
  }
350
  if (!foundationAlreadyWritten) {
 
369
  try {
370
  const safePath = path.normalize(filePath).replace(/^(\.\.[\/\\])+/, "");
371
  const fp = path.join(PROJECT_DIR, safePath);
 
372
  if (!fp.startsWith(PROJECT_DIR)) return res.status(403).json({ error: "Path traversal blocked" });
373
  if (!fs.existsSync(fp)) return res.status(404).json({ error: "File not found" });
374
  const isBinary = isBinaryFile(safePath);
375
+ const content = isBinary
376
+ ? await fs.readFile(fp, "base64")
377
+ : await fs.readFile(fp, "utf-8");
378
  res.json({ success: true, content, path: safePath, isBase64: isBinary });
379
  } catch (e) {
380
  res.status(500).json({ error: e.message });
 
430
  updateActivity(req);
431
  const { command, timeout = 30000 } = req.body;
432
  const isBlocked = BLOCKED_COMMANDS.some(cmd => command.includes(cmd));
 
433
  if (isBlocked) {
434
  pushLog(`[SECURITY] Blocked dangerous command: ${command}`, "error");
435
  return res.status(403).json({ error: "COMMAND_BLOCKED" });
 
475
  app.post("/api/reset", async (req, res) => {
476
  if (!verifyToken(req, res)) return;
477
  try {
478
+ pushLog("[SYSTEM] Resetting project...", "warning");
479
  await killVite();
480
+ bgProcesses.forEach((_, id) => killBgProcess(id));
481
  await fs.remove(PROJECT_DIR);
482
  fs.mkdirSync(PROJECT_DIR, { recursive: true });
483
  if (fs.existsSync(FOUNDATION_LOCK)) fs.removeSync(FOUNDATION_LOCK);
 
501
  const ACCESS_DENIED_PAGE = `<!DOCTYPE html><html><head><title>Access Denied</title><style>body{background:#09090b;color:#fff;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;flex-direction:column;gap:16px;}.title{color:#ef4444;font-size:1.4rem;font-weight:bold;}</style></head><body><div class="title">ACCESS DENIED</div><div>This preview is protected</div></body></html>`;
502
  const BOOTING_PAGE = `<!DOCTYPE html><html><head><title>Booting...</title><style>body{background:#09090b;color:#facc15;font-family:monospace;display:flex;align-items:center;justify-content:center;height:100vh;}</style><script>setTimeout(()=>location.reload(), 2000)</script></head><body>⚑ AutoDev is booting up...</body></html>`;
503
 
504
+ // BUG FIX #3: proxyRes handler WRONG tha β€” http-proxy already headers forward
505
+ // kar chuka hota hai jab proxyRes fire hota hai, toh wahan set karna useless tha.
506
+ // Sahi fix: upar wala app.use iframe middleware engine responses cover karta hai.
507
+ // proxyRes handler hata diya.
 
 
 
508
 
509
  proxy.on("error", (err, req, res) => {
510
  if (res && typeof res.writeHead === "function") {
 
524
  const previewHeader = req.headers["x-autodev-preview"];
525
  const previewParam = req.query["__autodev"];
526
  if (previewHeader !== PREVIEW_SECRET && previewParam !== PREVIEW_SECRET) {
527
+ pushLog(`[SECURITY] Preview blocked β€” direct access attempt`, "warning");
528
  return res.status(403).send(ACCESS_DENIED_PAGE);
529
  }
530
  }
 
543
  process.on("SIGTERM", async () => {
544
  pushLog("[SYSTEM] Shutting down...", "system");
545
  await killVite();
546
+ bgProcesses.forEach((_, id) => killBgProcess(id));
547
  process.exit(0);
548
  });
549
 
550
  process.on("SIGINT", async () => {
551
  await killVite();
552
+ bgProcesses.forEach((_, id) => killBgProcess(id));
553
  process.exit(0);
554
  });
555