const jwt = require('jsonwebtoken'); const bcrypt = require('bcrypt'); const db = require('./database'); const JWT_SECRET = process.env.JWT_SECRET || 'sua-chave-secreta-alterar-em-producao'; const JWT_EXPIRES_IN = '7d'; // ================================================================ // MIDDLEWARE DE AUTENTICAÇÃO // ================================================================ function authenticateToken(req, res, next) { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN // Identifica se a rota é uma API (via URL ou cabeçalho Accept) const isApiRoute = req.originalUrl.includes('/api') || (req.headers.accept && req.headers.accept.includes('application/json')); // Se não tem token, verifica se está tentando acessar uma página if (!token) { const isLoginRoute = req.originalUrl.includes('/login') || req.originalUrl === '/auth/login.html'; if (isLoginRoute || req.originalUrl === '/status') { return next(); } if (isApiRoute) { return res.status(401).json({ error: 'Token não fornecido' }); } return res.redirect('/login'); } // Verificar token via JWT (Fluxo padrão) jwt.verify(token, JWT_SECRET, async (err, user) => { if (err) { // Se não for um JWT válido, vamos verificar se é um Token Estático de API try { const apiToken = await db.get('SELECT * FROM api_tokens WHERE token = $1', [token]); if (apiToken) { // Token estático encontrado! Atualizar last_used_at em background db.run('UPDATE api_tokens SET last_used_at = CURRENT_TIMESTAMP WHERE id = $1', [apiToken.id]).catch(() => {}); // Injetar usuário "mock" na requisição com permissão de admin req.user = { id: -1, username: 'api_token', is_admin: true, email: 'api@system.local' }; return next(); } } catch (dbErr) { console.error('Erro ao verificar API Token estático:', dbErr); } if (isApiRoute) { return res.status(403).json({ error: 'Token inválido' }); } return res.redirect('/login'); } req.user = user; next(); }); } // ================================================================ // HASH DE SENHA // ================================================================ async function hashPassword(password) { const saltRounds = 10; return await bcrypt.hash(password, saltRounds); } async function verifyPassword(password, hash) { return await bcrypt.compare(password, hash); } // ================================================================ // GERAR TOKEN JWT // ================================================================ function generateToken(user, expiresIn = JWT_EXPIRES_IN) { return jwt.sign( { id: user.id, username: user.username, email: user.email, is_admin: user.is_admin }, JWT_SECRET, { expiresIn: expiresIn } ); } // ================================================================ // CRIAR USUÁRIO INICIAL // ================================================================ async function createInitialUser() { try { // Verificar se usuário já existe const existingUser = await db.get('SELECT * FROM users WHERE username = $1', ['rcesar']); if (existingUser) { console.log('👤 Usuário admin já existe:', existingUser.username); return; } const initialPassword = process.env.INITIAL_ADMIN_PASSWORD; if (!initialPassword) { console.log('⚠️ INITIAL_ADMIN_PASSWORD não definido — usuário admin inicial não será criado automaticamente'); return; } const passwordHash = await hashPassword(initialPassword); await db.run( `INSERT INTO users (username, email, password_hash, is_admin, created_at) VALUES ($1, $2, $3, true, CURRENT_TIMESTAMP) RETURNING id`, ['rcesar', 'rcesar@rcesar.com', passwordHash] ); console.log('✅ Usuário admin criado: rcesar'); } catch (error) { // Ignorar se tabela não existe ainda if (error.message.includes('no such table')) { console.log('⚠️ Tabela users não existe. Será criada pelo database.js'); } else { console.error('❌ Erro ao criar usuário inicial:', error); } } } module.exports = { authenticateToken, hashPassword, verifyPassword, generateToken, createInitialUser, JWT_SECRET };