import { Router, Request, Response } from "express"; import { spawn } from "child_process"; import path from "path"; import fs from "fs"; import archiver from "archiver"; import { getOrCreateApiKey } from "../services/networkSyncConfigService"; const router = Router(); const UPLOADS_DIR = path.resolve(process.cwd(), "uploads"); function isLanIp(ip: string): boolean { return ( /^127\./.test(ip) || /^10\./.test(ip) || /^192\.168\./.test(ip) || /^172\.(1[6-9]|2\d|3[01])\./.test(ip) ); } function checkAccess(req: Request, res: Response): boolean { // Only allow requests from the local network const ip = (req.headers["x-real-ip"] as string) || (req.headers["x-forwarded-for"] as string)?.split(",")[0].trim() || req.socket.remoteAddress || ""; if (!isLanIp(ip)) { res.status(403).json({ error: "Access restricted to local network" }); return false; } const providedKey = req.headers["x-network-backup-key"] as string | undefined; if (!providedKey) { res.status(401).json({ error: "Missing X-Network-Backup-Key header" }); return false; } const storedKey = getOrCreateApiKey(); if (providedKey !== storedKey) { res.status(401).json({ error: "Invalid API key" }); return false; } return true; } // GET /api/database-management/network-backup router.get("/network-backup", async (req: Request, res: Response): Promise => { if (!checkAccess(req, res)) return; const pg = spawn( "pg_dump", [ "--no-acl", "--no-owner", "-h", process.env.DB_HOST || "localhost", "-U", process.env.DB_USER || "postgres", process.env.DB_NAME || "dental_db", ], { env: { ...process.env, PGPASSWORD: process.env.DB_PASSWORD } } ); res.setHeader("Content-Type", "application/octet-stream"); res.setHeader( "Content-Disposition", `attachment; filename="network_backup_${Date.now()}.sql"` ); pg.stdout.pipe(res); let stderr = ""; pg.stderr.on("data", (d) => (stderr += d.toString())); pg.on("error", (err) => { if (!res.headersSent) res.status(500).json({ error: "pg_dump failed", details: err.message }); }); pg.on("close", (code) => { if (code !== 0) console.error("pg_dump for network backup failed:", stderr); }); }); // GET /api/database-management/network-backup-files router.get("/network-backup-files", (req: Request, res: Response): any => { if (!checkAccess(req, res)) return; if (!fs.existsSync(UPLOADS_DIR)) { return res.status(200).end(); } res.setHeader("Content-Type", "application/zip"); res.setHeader("Content-Disposition", `attachment; filename="network_uploads_${Date.now()}.zip"`); const archive = archiver("zip", { zlib: { level: 6 } }); archive.on("error", (err) => { if (!res.headersSent) res.status(500).json({ error: "Failed to create archive", details: err.message }); }); archive.pipe(res); archive.directory(UPLOADS_DIR, false); archive.finalize(); }); export default router;