Regalamiunsorriso/rus/facematch/server.js

115 lines
4.6 KiB
JavaScript
Raw Normal View History

2026-03-14 20:04:39 +01:00
'use strict';
require('dotenv').config();
const express = require('express');
const cookieParser = require('cookie-parser');
const fetch = require('node-fetch');
const path = require('path');
const app = express();
// ─── Configuration ────────────────────────────────────────────────────────────
// PUBLIC_BASE the public-facing prefix behind which this app is mounted
// e.g. if Nginx proxies /face_match → this app, set PUBLIC_BASE=/face_match
// JAVA_APP_INTERNAL_URL internal (loopback) URL to reach the Tomcat app
// e.g. http://localhost:8080
// LOGIN_URL where to redirect unauthenticated users (public URL of the login)
const PUBLIC_BASE = (process.env.PUBLIC_BASE || '/face_match').replace(/\/$/, '');
const JAVA_INTERNAL_URL = (process.env.JAVA_APP_INTERNAL_URL || 'http://localhost:8080').replace(/\/$/, '');
const LOGIN_URL = process.env.LOGIN_URL || 'https://www.regalamiunsorriso.it/admin/menu/Menu4.abl';
const PORT = process.env.PORT || 3001;
// ─── Middleware ───────────────────────────────────────────────────────────────
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(cookieParser());
// Strip the public base prefix so routes work both mounted and standalone
app.use((req, _res, next) => {
if (PUBLIC_BASE && req.path.startsWith(PUBLIC_BASE)) {
req.url = req.url.slice(PUBLIC_BASE.length) || '/';
}
next();
});
// ─── Session validation helper ────────────────────────────────────────────────
/**
* Calls the lightweight JSP endpoint on the main Java app, forwarding the
* browser's JSESSIONID cookie. Returns { authenticated, userId } or throws.
*
* The Java app stores the session server-side; both apps are on the same host
* so the JSESSIONID issued by Tomcat is forwarded here by the browser.
*/
async function checkJavaSession(jsessionId) {
if (!jsessionId) return { authenticated: false };
const url = `${JAVA_INTERNAL_URL}/admin/pg/checkSession.jsp`;
const response = await fetch(url, {
method: 'GET',
headers: {
Cookie: `JSESSIONID=${jsessionId}`,
},
// Don't follow redirects a redirect usually means the session expired
redirect: 'manual',
});
if (response.status === 401 || response.status >= 300) {
return { authenticated: false };
}
try {
return await response.json(); // { authenticated, userId }
} catch {
return { authenticated: false };
}
}
// ─── Auth middleware ──────────────────────────────────────────────────────────
async function requireAuth(req, res, next) {
const jsessionId = req.cookies['JSESSIONID'];
let sessionInfo;
try {
sessionInfo = await checkJavaSession(jsessionId);
} catch (err) {
console.error('Session validation request failed:', err.message);
sessionInfo = { authenticated: false };
}
if (!sessionInfo.authenticated) {
// Redirect to the main app login, passing the desired return URL
const returnUrl = encodeURIComponent(`https://www.regalamiunsorriso.it${PUBLIC_BASE}${req.path}`);
return res.redirect(`${LOGIN_URL}?returnUrl=${returnUrl}`);
}
// Attach session info for use in route handlers / views
req.sessionInfo = sessionInfo;
next();
}
// ─── Routes ───────────────────────────────────────────────────────────────────
// Main entry point protected
app.get('/', requireAuth, (req, res) => {
res.render('index', {
userId: req.sessionInfo.userId,
publicBase: PUBLIC_BASE,
});
});
// Health-check unprotected (used by reverse proxy / monitoring)
app.get('/health', (_req, res) => {
res.json({ status: 'ok' });
});
// Catch-all 404
app.use((_req, res) => {
res.status(404).send('Not found');
});
// ─── Start ────────────────────────────────────────────────────────────────────
app.listen(PORT, () => {
console.log(`facematch app listening on port ${PORT} (base: ${PUBLIC_BASE})`);
});