import { Router } from "express"; import type { Request, Response } from "express"; import { fetchSubscription, authorizeSession, closeSession, recordTraffic, VpnError, } from "./vpn.service"; import { SUBSCRIPTION_UPDATE_INTERVAL_HOURS } from "./vpn.config"; function handleVpnError(res: Response, err: unknown): void { if (err instanceof VpnError) { res.status(403).type("text/plain").send(err.message); return; } console.error("[VPN API] error:", err); res.status(500).type("text/plain").send("Internal error"); } export function registerVpnRoutes(router: Router): void { // Subscription endpoint used by olcbox clients router.get("/api/vpn/sub/:token", async (req: Request, res: Response) => { try { const token = req.params.token; const hwid = req.headers["x-hwid"] as string | undefined; const uri = await fetchSubscription(token, hwid); res.setHeader("profile-update-interval", String(SUBSCRIPTION_UPDATE_INTERVAL_HOURS)); res.setHeader("Content-Type", "text/plain; charset=utf-8"); res.send(uri); } catch (err) { handleVpnError(res, err); } }); // olrtc srv AuthHook router.post("/api/vpn/olrtc/auth", async (req: Request, res: Response) => { try { const { device_id, room_url } = req.body || {}; if (!device_id || !room_url) { res.status(400).json({ success: false, error: "missing device_id or room_url" }); return; } const result = await authorizeSession(room_url, device_id); res.json({ success: true, session_id: result.sessionId }); } catch (err) { if (err instanceof VpnError) { res.status(403).json({ success: false, error: err.message }); return; } console.error("[VPN Auth] error:", err); res.status(500).json({ success: false, error: "internal error" }); } }); // olrtc srv OnSessionClose router.post("/api/vpn/olrtc/close", async (req: Request, res: Response) => { try { const { session_id, room_url } = req.body || {}; if (!session_id || !room_url) { res.status(400).json({ success: false, error: "missing fields" }); return; } await closeSession(room_url, session_id); res.json({ success: true }); } catch (err) { console.error("[VPN Close] error:", err); res.status(500).json({ success: false, error: "internal error" }); } }); // olrtc srv OnTraffic router.post("/api/vpn/olrtc/traffic", async (req: Request, res: Response) => { try { const { session_id, room_url, bytes_in, bytes_out } = req.body || {}; if (!session_id || !room_url || typeof bytes_in !== "number" || typeof bytes_out !== "number") { res.status(400).json({ success: false, error: "missing fields" }); return; } await recordTraffic(room_url, session_id, bytes_in, bytes_out); res.json({ success: true }); } catch (err) { console.error("[VPN Traffic] error:", err); res.status(500).json({ success: false, error: "internal error" }); } }); }