import * as authService from '../services/auth.service.js'; import { logLoginAttempt, logPasswordChange, logEmailLink, logLogin, logLogout, } from '../services/audit.service.js'; import { verifyRefreshToken, generateAccessToken } from '../utils/jwt.js'; import { getUserById } from '../services/auth.service.js'; /** * KROK 1: Login s temporary password * POST /api/auth/login */ export const login = async (req, res, next) => { const { username, password, rememberMe } = req.body; const ipAddress = req.ip || req.connection.remoteAddress; const userAgent = req.headers['user-agent']; try { const result = await authService.loginWithTempPassword( username, password, ipAddress, userAgent ); // Log successful login await logLoginAttempt(username, true, ipAddress, userAgent); await logLogin(result.user.id, username, ipAddress, userAgent); // Nastav cookie s access tokenom (httpOnly, secure) const isProduction = process.env.NODE_ENV === 'production'; res.cookie('accessToken', result.tokens.accessToken, { httpOnly: true, secure: isProduction, sameSite: isProduction ? 'strict' : 'lax', maxAge: 60 * 60 * 1000, // 1 hodina }); // Refresh token iba ak user chce zostať prihlásený if (rememberMe) { res.cookie('refreshToken', result.tokens.refreshToken, { httpOnly: true, secure: isProduction, sameSite: isProduction ? 'strict' : 'lax', maxAge: 7 * 24 * 60 * 60 * 1000, // 7 dní }); } res.status(200).json({ success: true, data: { user: result.user, tokens: result.tokens, needsPasswordChange: result.needsPasswordChange, needsEmailSetup: result.needsEmailSetup, }, message: 'Prihlásenie úspešné', }); } catch (error) { // Log failed login await logLoginAttempt(username, false, ipAddress, userAgent, error.message); next(error); } }; /** * Refresh access token using refresh token * POST /api/auth/refresh */ export const refreshToken = async (req, res, next) => { try { const token = req.cookies?.refreshToken; if (!token) { return res.status(401).json({ success: false, error: { message: 'Refresh token nie je k dispozícii', statusCode: 401, }, }); } // Verify refresh token const decoded = verifyRefreshToken(token); // Get user from DB const user = await getUserById(decoded.id); // Generate new access token const newAccessToken = generateAccessToken({ id: user.id, username: user.username, role: user.role, }); // Set new access token cookie const isProduction = process.env.NODE_ENV === 'production'; res.cookie('accessToken', newAccessToken, { httpOnly: true, secure: isProduction, sameSite: isProduction ? 'strict' : 'lax', maxAge: 60 * 60 * 1000, // 1 hodina }); res.status(200).json({ success: true, data: { accessToken: newAccessToken, }, message: 'Token obnovený', }); } catch (error) { // Clear invalid cookies res.clearCookie('accessToken'); res.clearCookie('refreshToken'); return res.status(401).json({ success: false, error: { message: 'Refresh token expiroval alebo je neplatný', statusCode: 401, }, }); } }; /** * KROK 2: Nastavenie nového hesla * POST /api/auth/set-password * Requires: authentication */ export const setPassword = async (req, res, next) => { const { newPassword } = req.body; const userId = req.userId; const ipAddress = req.ip || req.connection.remoteAddress; const userAgent = req.headers['user-agent']; try { const result = await authService.setNewPassword(userId, newPassword); // Log password change await logPasswordChange(userId, ipAddress, userAgent); res.status(200).json({ success: true, data: result, message: 'Heslo úspešne nastavené', }); } catch (error) { next(error); } }; /** * KROK 3: Pripojenie emailu s JMAP validáciou * POST /api/auth/link-email * Requires: authentication */ export const linkEmail = async (req, res, next) => { const { email, emailPassword } = req.body; const userId = req.userId; const ipAddress = req.ip || req.connection.remoteAddress; const userAgent = req.headers['user-agent']; try { const result = await authService.linkEmail(userId, email, emailPassword); // Log email link await logEmailLink(userId, email, ipAddress, userAgent); res.status(200).json({ success: true, data: { email, accountId: result.accountId, }, message: 'Email účet úspešne pripojený a overený', }); } catch (error) { next(error); } }; /** * KROK 3 (alternatíva): Skip email setup * POST /api/auth/skip-email * Requires: authentication */ export const skipEmail = async (req, res, next) => { const userId = req.userId; try { const result = await authService.skipEmailSetup(userId); res.status(200).json({ success: true, data: result, message: 'Email setup preskočený', }); } catch (error) { next(error); } }; /** * Logout * POST /api/auth/logout * Requires: authentication */ export const logout = async (req, res, next) => { try { const userId = req.userId; const ipAddress = req.ip || req.connection.remoteAddress; const userAgent = req.headers['user-agent']; // Log logout event await logLogout(userId, ipAddress, userAgent); const result = await authService.logout(); // Vymaž cookies res.clearCookie('accessToken'); res.clearCookie('refreshToken'); res.status(200).json({ success: true, message: result.message, }); } catch (error) { next(error); } }; /** * Získanie aktuálnej session info * GET /api/auth/session * Requires: authentication */ export const getSession = async (req, res, next) => { try { res.status(200).json({ success: true, data: { user: req.user, authenticated: true, }, }); } catch (error) { next(error); } }; /** * Profil aktuálneho usera * GET /api/auth/me * Requires: authentication */ export const getMe = async (req, res, next) => { try { res.status(200).json({ success: true, data: { user: req.user, }, }); } catch (error) { next(error); } };