import express from 'express'; import path from 'path'; import crypto from 'crypto'; import './db.js'; // Initialize database import subscriptionsRouter from './routes/subscriptions.js'; import nodesRouter from './routes/nodes.js'; import rulesRouter from './routes/rules.js'; import surgeRouter from './routes/surge.js'; import db from './db.js'; import { generateSurgeConfig } from './services/generator.js'; // Ensure surge_token exists function ensureSurgeToken(): string { const row = db.prepare("SELECT value FROM config WHERE key = 'surge_token'").get() as any; if (row?.value) return row.value; const token = crypto.randomUUID(); db.prepare("INSERT OR REPLACE INTO config (key, value) VALUES ('surge_token', ?)").run(token); return token; } ensureSurgeToken(); const app = express(); const PORT = parseInt(process.env.PORT || '3456', 10); app.use(express.json()); // Surge endpoint (no auth, token-protected path) app.get('/surge/:token', (req, res) => { const row = db.prepare("SELECT value FROM config WHERE key = 'surge_token'").get() as any; if (!row?.value || req.params.token !== row.value) { return res.status(404).send('Not Found'); } const host = req.headers.host || 'localhost:3456'; const protocol = req.secure ? 'https' : 'http'; const hostUrl = `${protocol}://${host}/surge/${row.value}`; const config = generateSurgeConfig(hostUrl); res.set({ 'Content-Type': 'text/plain; charset=utf-8', 'Content-Disposition': 'attachment; filename=IPLC.MAX.conf', }); res.send(config); }); // Auth routes (no auth required) app.post('/api/auth/login', (req, res) => { const { password } = req.body; const configRow = db.prepare("SELECT value FROM config WHERE key = 'password'").get() as any; if (!configRow?.value) { db.prepare("INSERT OR REPLACE INTO config (key, value) VALUES ('password', ?)").run(password); return res.json({ ok: true }); } if (password === configRow.value) { return res.json({ ok: true }); } res.status(401).json({ error: 'wrong password' }); }); app.get('/api/auth/status', (_req, res) => { const configRow = db.prepare("SELECT value FROM config WHERE key = 'password'").get() as any; res.json({ hasPassword: !!configRow?.value }); }); // Auth middleware for other /api routes app.use('/api', (req, res, next) => { const configRow = db.prepare("SELECT value FROM config WHERE key = 'password'").get() as any; if (!configRow?.value) return next(); const authHeader = req.headers.authorization; if (!authHeader || authHeader !== `Bearer ${configRow.value}`) { return res.status(401).json({ error: 'unauthorized' }); } next(); }); // API routes app.use('/api/subscriptions', subscriptionsRouter); app.use('/api/nodes', nodesRouter); app.use('/api/rules', rulesRouter); app.use('/api/config', surgeRouter); // Stats endpoint app.get('/api/stats', (_req, res) => { const subs = db.prepare('SELECT COUNT(*) as count FROM subscriptions WHERE enabled = 1').get() as any; const fetchedEnabled = db.prepare('SELECT COUNT(*) as count FROM fetched_nodes WHERE enabled = 1').get() as any; const fetchedTotal = db.prepare('SELECT COUNT(*) as count FROM fetched_nodes').get() as any; const staticEnabled = db.prepare('SELECT COUNT(*) as count FROM static_nodes WHERE enabled = 1').get() as any; const staticTotal = db.prepare('SELECT COUNT(*) as count FROM static_nodes').get() as any; const rulesCount = db.prepare('SELECT COUNT(*) as count FROM rules WHERE enabled = 1').get() as any; res.json({ subscriptions: subs.count, nodes: { fetched: { enabled: fetchedEnabled.count, total: fetchedTotal.count }, static: { enabled: staticEnabled.count, total: staticTotal.count }, }, rules: rulesCount.count, }); }); // Serve static frontend files const webDist = path.join(__dirname, '..', '..', 'web', 'dist'); app.use(express.static(webDist)); app.get('*', (req, res, next) => { if (req.path.startsWith('/api') || req.path.startsWith('/surge')) return next(); res.sendFile(path.join(webDist, 'index.html')); }); app.listen(PORT, () => { const token = ensureSurgeToken(); console.log(`Sub Router running at http://127.0.0.1:${PORT}`); console.log(`Surge subscription: http://127.0.0.1:${PORT}/surge/${token}`); console.log(`Admin panel: http://127.0.0.1:${PORT}`); });