UNPKG

myex-cli

Version:

Opinionated Express.js framework with CLI tools

309 lines (275 loc) 8.69 kB
import jwt from 'jsonwebtoken'; import bcrypt from 'bcryptjs'; import { logger } from '../utils/logger.js'; import { authService } from '../services/auth.service.js'; export const authController = { /** * Register a new user * @param {import('express').Request} req - Express request object * @param {import('express').Response} res - Express response object */ register: async (req, res) => { try { const { email, password, name } = req.body; // Validate input if (!email || !password || !name) { return res.status(400).json({ status: 'error', message: 'Email, password, and name are required', }); } // Check if user already exists const existingUser = await authService.findUserByEmail(email); if (existingUser) { return res.status(409).json({ status: 'error', message: 'User with this email already exists', }); } // Create new user const user = await authService.createUser({ email, password, // Will be hashed in the service name, role: 'user', // Default role }); // Generate tokens const accessToken = authService.generateAccessToken(user); const refreshToken = authService.generateRefreshToken(user); // Save refresh token to database await authService.saveRefreshToken(user._id, refreshToken); // Return success with tokens res.status(201).json({ status: 'success', message: 'User registered successfully', data: { user: { id: user._id, email: user.email, name: user.name, role: user.role, }, tokens: { accessToken, refreshToken, }, }, }); } catch (error) { logger.error(`Registration error: ${error.message}`); res.status(500).json({ status: 'error', message: 'Failed to register user', }); } }, /** * Login a user * @param {import('express').Request} req - Express request object * @param {import('express').Response} res - Express response object */ login: async (req, res) => { try { const { email, password } = req.body; // Validate input if (!email || !password) { return res.status(400).json({ status: 'error', message: 'Email and password are required', }); } // Find user by email const user = await authService.findUserByEmail(email); if (!user) { return res.status(401).json({ status: 'error', message: 'Invalid email or password', }); } // Check password const isPasswordValid = await bcrypt.compare(password, user.password); if (!isPasswordValid) { logger.warn(`Failed login attempt for user: ${email}`); return res.status(401).json({ status: 'error', message: 'Invalid email or password', }); } // Generate tokens const accessToken = authService.generateAccessToken(user); const refreshToken = authService.generateRefreshToken(user); // Save refresh token to database await authService.saveRefreshToken(user._id, refreshToken); // Return success with tokens res.status(200).json({ status: 'success', message: 'Login successful', data: { user: { id: user._id, email: user.email, name: user.name, role: user.role, }, tokens: { accessToken, refreshToken, }, }, }); } catch (error) { logger.error(`Login error: ${error.message}`); res.status(500).json({ status: 'error', message: 'Failed to login', }); } }, /** * Refresh access token using refresh token * @param {import('express').Request} req - Express request object * @param {import('express').Response} res - Express response object */ refreshToken: async (req, res) => { try { const { refreshToken } = req.body; if (!refreshToken) { return res.status(400).json({ status: 'error', message: 'Refresh token is required', }); } // Check if refresh token is valid const user = await authService.verifyRefreshToken(refreshToken); if (!user) { return res.status(403).json({ status: 'error', message: 'Invalid refresh token', }); } // Generate new access token const newAccessToken = authService.generateAccessToken(user); // Return new access token res.status(200).json({ status: 'success', message: 'Token refreshed successfully', data: { accessToken: newAccessToken, }, }); } catch (error) { logger.error(`Token refresh error: ${error.message}`); res.status(500).json({ status: 'error', message: 'Failed to refresh token', }); } }, /** * Logout a user * @param {import('express').Request} req - Express request object * @param {import('express').Response} res - Express response object */ logout: async (req, res) => { try { const { refreshToken } = req.body; if (!refreshToken) { return res.status(400).json({ status: 'error', message: 'Refresh token is required', }); } // Remove refresh token from database await authService.removeRefreshToken(refreshToken); res.status(200).json({ status: 'success', message: 'Logged out successfully', }); } catch (error) { logger.error(`Logout error: ${error.message}`); res.status(500).json({ status: 'error', message: 'Failed to logout', }); } }, /** * Initiate password reset process * @param {import('express').Request} req - Express request object * @param {import('express').Response} res - Express response object */ forgotPassword: async (req, res) => { try { const { email } = req.body; if (!email) { return res.status(400).json({ status: 'error', message: 'Email is required', }); } // Check if user exists const user = await authService.findUserByEmail(email); if (!user) { return res.status(404).json({ status: 'error', message: 'User not found', }); } // Generate reset token and save it const resetToken = await authService.generatePasswordResetToken(user._id); // In a real app, send email with reset link here // For now, just return the token in the response res.status(200).json({ status: 'success', message: 'Password reset instructions sent to email', data: { resetToken, // Remove this in production }, }); } catch (error) { logger.error(`Forgot password error: ${error.message}`); res.status(500).json({ status: 'error', message: 'Failed to process forgot password request', }); } }, /** * Reset password with reset token * @param {import('express').Request} req - Express request object * @param {import('express').Response} res - Express response object */ resetPassword: async (req, res) => { try { const { token, newPassword } = req.body; if (!token || !newPassword) { return res.status(400).json({ status: 'error', message: 'Token and new password are required', }); } // Verify and use the reset token const userId = await authService.verifyPasswordResetToken(token); if (!userId) { return res.status(403).json({ status: 'error', message: 'Invalid or expired reset token', }); } // Update password await authService.updatePassword(userId, newPassword); // Invalidate token await authService.invalidatePasswordResetToken(token); res.status(200).json({ status: 'success', message: 'Password reset successfully', }); } catch (error) { logger.error(`Reset password error: ${error.message}`); res.status(500).json({ status: 'error', message: 'Failed to reset password', }); } }, };