import passport from "passport"; import { Strategy as LocalStrategy } from "passport-local"; import { Express } from "express"; import session from "express-session"; import { scrypt, randomBytes, timingSafeEqual } from "crypto"; import { promisify } from "util"; import { storage } from "./storage"; import { User as SelectUser } from "@shared/schema"; declare global { namespace Express { interface User extends SelectUser { tenantId?: number; } } } const scryptAsync = promisify(scrypt); async function hashPassword(password: string) { const salt = randomBytes(16).toString("hex"); const buf = (await scryptAsync(password, salt, 64)) as Buffer; return `${buf.toString("hex")}.${salt}`; } async function comparePasswords(supplied: string, stored: string) { const [hashed, salt] = stored.split("."); const hashedBuf = Buffer.from(hashed, "hex"); const suppliedBuf = (await scryptAsync(supplied, salt, 64)) as Buffer; return timingSafeEqual(hashedBuf, suppliedBuf); } // CORREÇÃO: Session secret seguro - obrigatório em produção const SESSION_SECRET = process.env.SESSION_SECRET || (process.env.NODE_ENV === 'production' ? (() => { throw new Error('SESSION_SECRET obrigatório em produção'); })() : randomBytes(32).toString('hex')); const sessionSettings: session.SessionOptions = { secret: SESSION_SECRET, resave: false, saveUninitialized: false, store: storage.sessionStore, cookie: { secure: process.env.NODE_ENV === "production", httpOnly: true, maxAge: 24 * 60 * 60 * 1000, }, }; export const sessionMiddleware = session(sessionSettings); export function setupAuth(app: Express) { app.set("trust proxy", 1); app.use(sessionMiddleware); app.use(passport.initialize()); app.use(passport.session()); passport.use( new LocalStrategy(async (username, password, done) => { console.log(`[Auth] Tentativa de login: ${username}`); try { const user = await storage.getUserByUsername(username); if (!user) { console.log(`[Auth] Usuário não encontrado: ${username}`); return done(null, false); } console.log(`[Auth] Usuário encontrado, verificando senha...`); const validPassword = await comparePasswords(password, user.password); if (!validPassword) { console.log(`[Auth] Senha inválida para: ${username}`); return done(null, false); } console.log(`[Auth] Login bem-sucedido: ${username}`); return done(null, user); } catch (error: any) { console.error(`[Auth] Erro no login: ${error.message}`); return done(error); } }), ); passport.serializeUser((user, done) => { console.log(`[Auth] Serializando usuário: ${user.id}`); done(null, user.id); }); passport.deserializeUser(async (id: string, done) => { console.log(`[Auth] Desserializando usuário: ${id}`); try { const user = await storage.getUser(id); if (user) { console.log(`[Auth] Enriquecendo usuário: ${id}`); const enrichedUser = await storage.getEnrichedUser(user); console.log(`[Auth] Usuário desserializado: ${id}`); done(null, enrichedUser); } else { console.log(`[Auth] Usuário não encontrado na desserialização: ${id}`); done(null, null); } } catch (error: any) { console.error(`[Auth] Erro na desserialização: ${error.message}`); done(error); } }); app.post("/api/register", async (req, res, next) => { try { const existingUser = await storage.getUserByUsername(req.body.username); if (existingUser) { return res.status(400).send("Username already exists"); } const user = await storage.createUser({ ...req.body, password: await hashPassword(req.body.password), }); req.login(user, async (err) => { if (err) return next(err); const enrichedUser = await storage.getEnrichedUser(user); res.status(201).json(enrichedUser); }); } catch (error) { next(error); } }); app.post("/api/login", passport.authenticate("local"), async (req, res) => { console.log(`[Auth] Post-login, enriquecendo usuário: ${req.user!.id}`); try { const enrichedUser = await storage.getEnrichedUser(req.user!); console.log(`[Auth] Enviando resposta de login para: ${enrichedUser.username}`); res.status(200).json(enrichedUser); } catch (error: any) { console.error(`[Auth] Erro ao enriquecer usuário no login: ${error.message}`); res.status(500).json({ error: "Erro ao processar login" }); } }); app.post("/api/logout", (req, res, next) => { req.logout((err) => { if (err) return next(err); res.sendStatus(200); }); }); app.get("/api/user", (req, res) => { if (!req.isAuthenticated()) return res.sendStatus(401); res.json(req.user); }); }