const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const { db } = require('../database/db'); async function photoAuth(req, res, next) { try { // Extract event slug from the path let eventSlug; // For thumbnails, we need to parse the filename to get the event info if (req.path.startsWith('/thumb_')) { // For now, we'll rely on JWT token for thumbnail access eventSlug = null; } else { // For regular photos, the slug is the first part of the path eventSlug = req.path.split('/')[1]; } // First check for JWT token (from gallery access) const authHeader = req.headers.authorization; if (authHeader && authHeader.startsWith('Bearer ')) { const token = authHeader.replace('Bearer ', ''); try { const decoded = jwt.verify(token, process.env.JWT_SECRET); // Check if it's a gallery token if (decoded.type === 'gallery') { // For thumbnails, we accept any valid gallery token if (!eventSlug) { const event = await db('events').where({ slug: decoded.eventSlug, is_active: true }).first(); if (event) { req.event = event; return next(); } } // For regular photos, check if token matches the event else if (decoded.eventSlug === eventSlug) { const event = await db('events').where({ slug: eventSlug, is_active: true }).first(); if (event) { req.event = event; return next(); } } } // Check if it's an admin token (admins can view all photos) if (decoded.type === 'admin') { if (!eventSlug) { // For thumbnails with admin token, allow access return next(); } const event = await db('events').where({ slug: eventSlug }).first(); if (event) { req.event = event; return next(); } } } catch (err) { // Token invalid, fall through to password check } } // Check for password header (legacy support) const password = req.headers['x-gallery-password']; if (!password && !authHeader) { return res.status(401).json({ error: 'Authentication required' }); } // If no eventSlug (thumbnails), we require JWT token if (!eventSlug) { return res.status(401).json({ error: 'Authentication required for thumbnails' }); } const event = await db('events').where({ slug: eventSlug, is_active: true }).first(); if (!event) { return res.status(404).json({ error: 'Gallery not found' }); } if (password) { const validPassword = await bcrypt.compare(password, event.password_hash); if (!validPassword) { await db('access_logs').insert({ event_id: event.id, ip_address: req.ip, user_agent: req.headers['user-agent'], action: 'login_fail' }); return res.status(401).json({ error: 'Invalid password' }); } } else { // No valid authentication return res.status(401).json({ error: 'Invalid authentication' }); } req.event = event; next(); } catch (error) { console.error('Photo auth error:', error); res.status(500).json({ error: 'Authentication error' }); } } module.exports = photoAuth;