/** * Authentication Middleware for Weight Tracker * Handles password protection and session management */ const bcrypt = require('bcryptjs'); const session = require('express-session'); const cookieParser = require('cookie-parser'); // Default session configuration const sessionConfig = { secret: process.env.SESSION_SECRET || 'weight-tracker-secret', resave: false, saveUninitialized: false, cookie: { secure: process.env.COOKIE_SECURE === 'true', httpOnly: true, maxAge: 24 * 60 * 60 * 1000 // 24 hours } }; /** * Initialize authentication middleware * @param {Object} app - Express app */ function initAuth(app) { // Parse cookies app.use(cookieParser()); // Session management app.use(session(sessionConfig)); // Serve login page app.get('/login', (req, res) => { if (req.session.authenticated) { return res.redirect('/'); } res.sendFile('login.html', { root: __dirname }); }); // Handle login form submission app.post('/auth/login', (req, res) => { const { password } = req.body; const storedHash = process.env.PASSWORD_HASH; if (!storedHash) { console.error('PASSWORD_HASH environment variable not set'); return res.redirect('/login?error=config'); } // Verify password bcrypt.compare(password, storedHash, (err, isMatch) => { if (err) { console.error('Error verifying password:', err); return res.redirect('/login?error=server'); } if (isMatch) { // Set session as authenticated req.session.authenticated = true; res.redirect('/'); } else { res.redirect('/login?error=invalid'); } }); }); // Logout endpoint app.get('/auth/logout', (req, res) => { req.session.destroy(); res.redirect('/login'); }); // Authentication check endpoint for Nginx auth_request app.get('/auth/check', (req, res) => { if (req.session.authenticated) { return res.status(200).send('OK'); } return res.status(401).send('Unauthorized'); }); // Authentication middleware for all other routes app.use((req, res, next) => { // Skip auth for login-related routes and static assets if (req.path === '/login' || req.path === '/auth/login' || req.path === '/auth/check' || req.path.match(/\.(css|js|png|jpg|jpeg|gif|ico|svg)$/)) { return next(); } // Check if user is authenticated if (req.session.authenticated) { return next(); } // Redirect to login page res.redirect('/login'); }); } /** * Generate a password hash (utility function) * @param {string} password - Plain text password * @returns {Promise} - Hashed password */ function generateHash(password) { return bcrypt.hash(password, 10); } module.exports = { initAuth, generateHash };