import bcrypt from 'bcryptjs'; import jwt from 'jsonwebtoken'; import { db } from './db.js'; import { config } from './config.js'; export function signUser(user) { return jwt.sign( { sub: user.id, email: user.email, role: user.role }, config.jwtSecret, { expiresIn: '12h' } ); } export function publicUser(row) { if (!row) return null; return { id: row.id, email: row.email, displayName: row.display_name, authProvider: row.auth_provider, role: row.role, theme: row.theme || 'dashtreme', jobTitle: row.job_title || '', phone: row.phone || '', timezone: row.timezone || '', avatarUrl: row.avatar_url || '', updatedAt: row.updated_at || '', createdAt: row.created_at }; } export function requireAuth(req, res, next) { const header = req.get('authorization') || ''; const token = header.startsWith('Bearer ') ? header.slice(7) : ''; if (!token) return res.status(401).json({ error: 'Authentication required' }); try { const payload = jwt.verify(token, config.jwtSecret); const user = db.prepare('SELECT * FROM users WHERE id = ?').get(payload.sub); if (!user) return res.status(401).json({ error: 'Invalid session' }); req.user = publicUser(user); next(); } catch { res.status(401).json({ error: 'Invalid session' }); } } export function requireAdmin(req, res, next) { if (req.user?.role !== 'admin') return res.status(403).json({ error: 'Admin role required' }); next(); } export function authenticateLocal(email, password) { const user = db.prepare('SELECT * FROM users WHERE email = ? AND auth_provider = ?').get(email.toLowerCase(), 'local'); if (!user?.password_hash) return null; if (!bcrypt.compareSync(password, user.password_hash)) return null; return user; }