const fs = require('fs'); const path = require('path'); const session = require('express-session'); const SQLiteStore = require('connect-sqlite3')(session); const SESSION_FILENAME = process.env.ADMIN_SESSION_DB || 'sessions.sqlite'; const SESSION_DIR = process.env.ADMIN_SESSION_DIR ? path.resolve(process.env.ADMIN_SESSION_DIR) : path.join(__dirname, '..', 'data'); const SESSION_SECRET = process.env.ADMIN_SESSION_SECRET; const IS_PRODUCTION = process.env.NODE_ENV === 'production'; const ADMIN_SESSION_COOKIE_SECURE = process.env.ADMIN_SESSION_COOKIE_SECURE; const parseBooleanEnv = (value) => { if (typeof value !== 'string') { return undefined; } switch (value.toLowerCase().trim()) { case 'true': case '1': case 'yes': case 'on': return true; case 'false': case '0': case 'no': case 'off': return false; default: return undefined; } }; const secureOverride = parseBooleanEnv(ADMIN_SESSION_COOKIE_SECURE); const cookieSecure = secureOverride ?? IS_PRODUCTION; if (IS_PRODUCTION && secureOverride === false) { console.warn('[Session] ADMIN_SESSION_COOKIE_SECURE=false detected – secure cookies disabled in production. Only do this on trusted HTTP deployments.'); } if (!SESSION_SECRET) { throw new Error('ADMIN_SESSION_SECRET is required for session management'); } // Ensure session directory exists so SQLite can create the DB file if (!fs.existsSync(SESSION_DIR)) { fs.mkdirSync(SESSION_DIR, { recursive: true }); } const store = new SQLiteStore({ db: SESSION_FILENAME, dir: SESSION_DIR, ttl: 8 * 60 * 60 // seconds }); const sessionMiddleware = session({ name: 'sid', store, secret: SESSION_SECRET, resave: false, saveUninitialized: false, cookie: { httpOnly: true, secure: cookieSecure, sameSite: 'strict', maxAge: 8 * 60 * 60 * 1000 // 8 hours } }); module.exports = sessionMiddleware;