Files
main-web/server.js
2025-10-22 17:21:44 +02:00

105 lines
2.9 KiB
JavaScript

const express = require('express');
const cors = require('cors');
const path = require('path');
const fs = require('fs').promises;
const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware');
const app = express();
app.use(cors());
app.use(express.json()); // Add JSON body parser
// Helpers
function normalizeUrl(u) {
try {
return new URL(u);
} catch {
return null;
}
}
// Env-configurable allowed origins for proxying
const RAW_ALLOWED = process.env.ALLOWED_PROXY_ORIGINS || '*';
const ALLOW_ANY = RAW_ALLOWED.trim() === '*';
const allowedOrigins = ALLOW_ANY
? ['*']
: RAW_ALLOWED.split(',')
.map((s) => s.trim())
.filter(Boolean);
if (ALLOW_ANY) {
console.log('[proxy] ALLOWED_PROXY_ORIGINS="*" (allow any http/https target)');
} else {
console.log('[proxy] Allowed proxy origins:', allowedOrigins);
}
// Generic proxy endpoint
app.use(
'/proxy',
(req, res, next) => {
const targetUrlString = req.get('x-proxy-target');
if (!targetUrlString) {
return res.status(400).send('Missing x-proxy-target header');
}
const targetUrl = normalizeUrl(targetUrlString);
if (!targetUrl) {
return res.status(400).send('Invalid x-proxy-target URL');
}
if (!ALLOW_ANY && !allowedOrigins.includes(targetUrl.origin)) {
return res.status(403).send(`Proxy target origin "${targetUrl.origin}" not allowed.`);
}
// Pass the full URL to the proxy middleware
req._proxyTarget = targetUrlString;
next();
},
createProxyMiddleware({
router: (req) => new URL(req._proxyTarget).origin,
changeOrigin: true,
pathRewrite: (_path, req) => {
const targetUrl = new URL(req._proxyTarget);
return `${targetUrl.pathname}${targetUrl.search}`;
},
secure: false,
logLevel: 'debug',
onProxyReq: fixRequestBody, // Fixes body for POST/PUT requests
})
);
// API endpoint to save config
app.post('/api/save-config', async (req, res) => {
try {
const configPath = path.join(__dirname, 'main_web/src/assets/config.json');
const configData = JSON.stringify(req.body, null, 2);
await fs.writeFile(configPath, configData, 'utf8');
console.log('Config saved successfully to:', configPath);
res.json({ success: true, message: 'Configuration saved successfully' });
} catch (error) {
console.error('Error saving config:', error);
res.status(500).json({
success: false,
message: 'Failed to save configuration',
error: error.message
});
}
});
const distPath = path.join(__dirname, 'dist');
app.use(express.static(distPath));
// Simple health check
app.get('/__health', (req, res) => res.json({ ok: true }));
// SPA fallback
app.get('*', (req, res) => {
res.sendFile(path.join(distPath, 'index.html'));
});
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});