testmog / server.ts
wuhp's picture
Update server.ts
26f3861 verified
import express from "express";
import { createServer as createViteServer } from "vite";
import path from "path";
import { fileURLToPath } from "url";
import { createServer } from "http";
import { WebSocketServer, WebSocket } from "ws";
import { spawn } from "child_process";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
let assignedTunnelUrl = "";
function startTunnel(port: number) {
console.log(`[TUNNEL] Attempting to start bore tunnel for port ${port}...`);
try {
const bore = spawn("bore", ["local", port.toString(), "--to", "bore.pub"]);
bore.stdout.on("data", (data) => {
const output = data.toString();
// Regex for bore.pub:XXXXX
const match = output.match(/bore\.pub:(\d+)/);
if (match) {
assignedTunnelUrl = `https://bore.pub:${match[1]}`;
console.log(`[TUNNEL] Public URL assigned: ${assignedTunnelUrl}`);
}
});
bore.on("error", (err) => {
console.error("[TUNNEL_ERR] Bore binary not found or failed to start. Ensure 'bore' is installed.");
});
bore.on("close", (code) => {
if (code !== 0) console.log(`[TUNNEL] Process exited with code ${code}. Restarting in 10s...`);
setTimeout(() => startTunnel(port), 10000);
});
} catch (e) {
console.error("[TUNNEL_CRIT] Failed to spawn tunnel process.");
}
}
async function startServer() {
const app = express();
const PORT = Number(process.env.PORT) || 3000;
const server = createServer(app);
// Start the tunnel if not in production or if requested
if (process.env.NODE_ENV !== "production" || process.env.ENABLE_TUNNEL === "true") {
startTunnel(PORT);
}
app.use(express.json({ limit: '10mb' }));
// API to get the assigned tunnel URL
app.get("/api/tunnel-info", (req, res) => {
res.json({ url: assignedTunnelUrl || null });
});
// In-memory log storage
const exfiltratedLogs: any[] = [];
// WebSocket Signaling for OBS
const wss = new WebSocketServer({ server, path: '/stream' });
const clients = new Map<string, WebSocket>();
let broadcaster: WebSocket | null = null;
wss.on('connection', (ws, req) => {
const url = new URL(req.url || '', `http://${req.headers.host}`);
const role = url.searchParams.get('role');
const clientId = Math.random().toString(36).substr(2, 9);
console.log(`[STREAM] New connection: ${role} (${clientId})`);
if (role === 'broadcaster') {
if (broadcaster) {
console.log(`[STREAM] Replacing existing broadcaster (${clientId})`);
// We don't close it, just replace the reference. The old one will eventually heartbeat out.
}
broadcaster = ws;
console.log(`[STREAM] Broadcaster established: ${clientId}`);
// Notify all current viewers that a broadcaster is now available
clients.forEach((client, id) => {
if (client.readyState === WebSocket.OPEN) {
console.log(`[STREAM] Pushing online signal to viewer: ${id}`);
client.send(JSON.stringify({ type: 'broadcast_online' }));
}
});
ws.on('close', () => {
if (broadcaster === ws) {
broadcaster = null;
console.log(`[STREAM] Active broadcaster ${clientId} disconnected`);
}
});
} else {
clients.set(clientId, ws);
console.log(`[STREAM] Viewer connected: ${clientId}. Total: ${clients.size}`);
// If a broadcaster exists already, tell this new viewer immediately
if (broadcaster && broadcaster.readyState === WebSocket.OPEN) {
console.log(`[STREAM] New viewer ${clientId} notified of active broadcaster`);
ws.send(JSON.stringify({ type: 'broadcast_online' }));
}
ws.on('close', () => {
clients.delete(clientId);
console.log(`[STREAM] Viewer disconnected: ${clientId}. Remaining: ${clients.size}`);
});
}
ws.on('message', (data) => {
try {
const msg = JSON.parse(data.toString());
if (role === 'broadcaster') {
// Broadcaster says: here is info for viewer X
if (msg.viewerId && clients.has(msg.viewerId)) {
console.log(`[SIG] Broadcaster -> Viewer (${msg.viewerId}): ${msg.type}`);
clients.get(msg.viewerId)?.send(JSON.stringify(msg));
} else if (!msg.viewerId) {
console.log(`[SIG] Broadcast from Broadcaster: ${msg.type}`);
clients.forEach(client => client.send(JSON.stringify(msg)));
}
} else {
// Viewer says: here is my offer (ID is attached by server)
if (broadcaster && broadcaster.readyState === WebSocket.OPEN) {
console.log(`[SIG] Viewer (${clientId}) -> Broadcaster: ${msg.type}`);
broadcaster.send(JSON.stringify({ ...msg, viewerId: clientId }));
} else {
console.warn(`[SIG] Viewer (${clientId}) message dropped: No Broadcaster`);
if (msg.type === 'offer') {
ws.send(JSON.stringify({ type: 'error', message: 'No active broadcaster found' }));
}
}
}
} catch (e) {
console.error("[STREAM] Message parse error");
}
});
// Special: notify broadcaster when a new viewer joins
if (role === 'viewer' && broadcaster && broadcaster.readyState === WebSocket.OPEN) {
broadcaster.send(JSON.stringify({ type: 'viewer_joined', viewerId: clientId }));
}
// Keepalive
const interval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: 'ping' }));
else clearInterval(interval);
}, 30000);
});
// Exfiltration endpoint
app.post("/api/webhook", (req, res) => {
const data = req.body;
if (data.type === 'sys_purge') {
exfiltratedLogs.length = 0;
return res.json({ status: "purged" });
}
console.log("[BRIDGE] Received exfiltration payload:", data.type);
const entry = {
id: Math.random().toString(36).substr(2, 9),
timestamp: Date.now(),
...data
};
exfiltratedLogs.unshift(entry);
if (exfiltratedLogs.length > 50) exfiltratedLogs.pop();
res.json({ status: "captured", timestamp: Date.now() });
});
// Logs endpoint for the React app
app.get("/api/logs", (req, res) => {
res.json(exfiltratedLogs);
});
// Optimization feedback endpoint
app.get("/api/optimization-status", (req, res) => {
const lastReport = exfiltratedLogs.find(l => ['report', 'api_intercept', 'internal_metrics'].includes(l.type));
if (lastReport) {
let overall = 0;
if (lastReport.type === 'internal_metrics') {
overall = lastReport.payload.cloaked.overall;
} else {
overall = lastReport.payload?.statsJson?.overall || lastReport.payload?.overall || 0;
}
let recommendation = "Apply more 'Refine' intensity to sharp jawline.";
if (overall > 7) recommendation = "Increase Hunter Eyes simulation to 45%.";
if (overall > 9) recommendation = "Almost perfect. Slight symmetry adjustment needed.";
res.json({
lastScore: overall,
status: overall >= 10 ? "perfect" : "optimizing",
message: overall >= 10 ? "Optimization Complete. 10/10 Reached." : recommendation,
timestamp: lastReport.timestamp
});
} else {
res.json({ status: "idle", message: "Connect Tampermonkey or start feed to begin optimization." });
}
});
// Vite middleware for development
if (process.env.NODE_ENV !== "production") {
const vite = await createViteServer({
server: { middlewareMode: true },
appType: "spa",
});
app.use(vite.middlewares);
} else {
// Production static serving
const distPath = path.join(process.cwd(), "dist");
console.log(`[SYSTEM] Serving static files from: ${distPath}`);
app.use(express.static(distPath));
// Fallback for SPA routing
app.get("*", (req: express.Request, res: express.Response) => {
res.sendFile(path.join(distPath, "index.html"));
});
}
server.listen(PORT, "0.0.0.0", () => {
console.log(`[SYSTEM] Full-stack server active on port ${PORT}`);
});
}
startServer();