import express from 'express'; import https from 'https'; import cors from 'cors'; import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs'; import { execSync } from 'child_process'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import { initRules } from './signing.js'; import proxyRouter from './proxy.js'; import downloadRouter from './download.js'; import galleryRouter from './gallery.js'; import hlsRouter from './hls.js'; import settingsRouter from './settings.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const app = express(); const PORT = process.env.PORT || 3001; const HTTPS_PORT = process.env.HTTPS_PORT || 3443; app.use(cors()); // Parse DRM license request bodies as raw binary BEFORE global JSON parser // (express.json can interfere with reading the raw body stream) app.use('/api/drm-license', express.raw({ type: '*/*', limit: '1mb' })); app.use(express.json()); // API routes app.use(proxyRouter); app.use(downloadRouter); app.use(galleryRouter); app.use(hlsRouter); app.use(settingsRouter); // Serve static client build in production const clientDist = join(__dirname, '..', 'client', 'dist'); if (existsSync(clientDist)) { app.use(express.static(clientDist)); app.get('*', (req, res) => { if (req.path.startsWith('/api/')) return res.status(404).json({ error: 'Not found' }); res.sendFile(join(clientDist, 'index.html')); }); } // Error handler app.use((err, req, res, _next) => { console.error('[server] Error:', err.message); res.status(500).json({ error: err.message || 'Internal server error' }); }); async function start() { try { await initRules(); } catch (err) { console.error('[server] Failed to load signing rules:', err.message); console.error('[server] Signing will not work until rules are available'); } app.listen(PORT, () => { console.log(`[server] Listening on http://localhost:${PORT}`); }); // Start HTTPS server for DRM/EME support (requires secure context) try { const certDir = '/data/certs'; const certPath = `${certDir}/server.crt`; const keyPath = `${certDir}/server.key`; if (!existsSync(certPath) || !existsSync(keyPath)) { mkdirSync(certDir, { recursive: true }); execSync(`openssl req -x509 -newkey rsa:2048 -keyout ${keyPath} -out ${certPath} -days 3650 -nodes -subj '/CN=ofapp'`); console.log('[server] Generated self-signed HTTPS certificate'); } const httpsServer = https.createServer({ key: readFileSync(keyPath), cert: readFileSync(certPath), }, app); httpsServer.listen(HTTPS_PORT, () => { console.log(`[server] HTTPS listening on https://localhost:${HTTPS_PORT}`); }); } catch (err) { console.error('[server] HTTPS setup failed:', err.message); console.error('[server] DRM video playback will not work without HTTPS'); } } start();