Files
spotlightcam/backend/src/controllers/auth.js

499 lines
12 KiB
JavaScript
Raw Normal View History

feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
const { prisma } = require('../utils/db');
const {
hashPassword,
comparePassword,
generateToken,
generateVerificationToken,
generateVerificationCode,
getTokenExpiry
} = require('../utils/auth');
const { sendVerificationEmail, sendWelcomeEmail, sendPasswordResetEmail } = require('../utils/email');
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
// Register new user (Phase 1.5 - with WSDC support and email verification)
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
async function register(req, res, next) {
try {
const { username, email, password, firstName, lastName, wsdcId } = req.body;
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
// Check if user already exists
const existingUser = await prisma.user.findFirst({
where: {
OR: [
{ email },
{ username },
...(wsdcId ? [{ wsdcId }] : []),
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
],
},
});
if (existingUser) {
if (existingUser.email === email) {
return res.status(400).json({
success: false,
error: 'Email already registered',
});
}
if (existingUser.username === username) {
return res.status(400).json({
success: false,
error: 'Username already taken',
});
}
if (wsdcId && existingUser.wsdcId === wsdcId) {
return res.status(400).json({
success: false,
error: 'WSDC ID already registered',
});
}
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
}
// Hash password
const passwordHash = await hashPassword(password);
// Generate verification token and code
const verificationToken = generateVerificationToken();
const verificationCode = generateVerificationCode();
const verificationTokenExpiry = getTokenExpiry(24); // 24 hours
// Create display name for avatar
const displayName = firstName && lastName
? `${firstName} ${lastName}`
: username;
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
// Create user
const user = await prisma.user.create({
data: {
username,
email,
passwordHash,
firstName,
lastName,
wsdcId,
verificationToken,
verificationCode,
verificationTokenExpiry,
emailVerified: false,
avatar: `https://ui-avatars.com/api/?name=${encodeURIComponent(displayName)}&background=6366f1&color=fff`,
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
},
select: {
id: true,
username: true,
email: true,
firstName: true,
lastName: true,
wsdcId: true,
emailVerified: true,
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
avatar: true,
createdAt: true,
},
});
// Send verification email
try {
await sendVerificationEmail(
user.email,
user.firstName || user.username,
verificationToken,
verificationCode
);
} catch (emailError) {
console.error('Failed to send verification email:', emailError);
// Continue even if email fails - user can request resend
}
// Generate JWT token
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
const token = generateToken({ userId: user.id });
res.status(201).json({
success: true,
message: 'User registered successfully. Please check your email to verify your account.',
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
data: {
user,
token,
},
});
} catch (error) {
next(error);
}
}
// Login user
async function login(req, res, next) {
try {
const { email, password } = req.body;
// Find user by email
const user = await prisma.user.findUnique({
where: { email },
});
if (!user) {
return res.status(401).json({
success: false,
error: 'Invalid credentials',
});
}
// Compare password
const isPasswordValid = await comparePassword(password, user.passwordHash);
if (!isPasswordValid) {
return res.status(401).json({
success: false,
error: 'Invalid credentials',
});
}
// Generate token
const token = generateToken({ userId: user.id });
// Return user without password
const { passwordHash, ...userWithoutPassword } = user;
res.json({
success: true,
message: 'Login successful',
data: {
user: userWithoutPassword,
token,
},
});
} catch (error) {
next(error);
}
}
// Verify email by token (link in email)
async function verifyEmailByToken(req, res, next) {
try {
const { token } = req.query;
if (!token) {
return res.status(400).json({
success: false,
error: 'Verification token is required',
});
}
// Find user by verification token
const user = await prisma.user.findUnique({
where: { verificationToken: token },
});
if (!user) {
return res.status(404).json({
success: false,
error: 'Invalid or expired verification token',
});
}
// Check if already verified
if (user.emailVerified) {
return res.status(200).json({
success: true,
message: 'Email already verified',
});
}
// Check if token expired
if (user.verificationTokenExpiry && new Date() > user.verificationTokenExpiry) {
return res.status(400).json({
success: false,
error: 'Verification token has expired. Please request a new one.',
});
}
// Update user - mark as verified and clear tokens
await prisma.user.update({
where: { id: user.id },
data: {
emailVerified: true,
verificationToken: null,
verificationCode: null,
verificationTokenExpiry: null,
},
});
// Send welcome email
try {
await sendWelcomeEmail(user.email, user.firstName || user.username);
} catch (emailError) {
console.error('Failed to send welcome email:', emailError);
}
res.status(200).json({
success: true,
message: 'Email verified successfully!',
});
} catch (error) {
next(error);
}
}
// Verify email by code (6-digit PIN)
async function verifyEmailByCode(req, res, next) {
try {
const { code, email } = req.body;
if (!code || !email) {
return res.status(400).json({
success: false,
error: 'Email and verification code are required',
});
}
// Find user by email and code
const user = await prisma.user.findFirst({
where: {
email,
verificationCode: code,
},
});
if (!user) {
return res.status(400).json({
success: false,
error: 'Invalid verification code',
});
}
// Check if already verified
if (user.emailVerified) {
return res.status(200).json({
success: true,
message: 'Email already verified',
});
}
// Check if token expired
if (user.verificationTokenExpiry && new Date() > user.verificationTokenExpiry) {
return res.status(400).json({
success: false,
error: 'Verification code has expired. Please request a new one.',
});
}
// Update user - mark as verified and clear tokens
await prisma.user.update({
where: { id: user.id },
data: {
emailVerified: true,
verificationToken: null,
verificationCode: null,
verificationTokenExpiry: null,
},
});
// Send welcome email
try {
await sendWelcomeEmail(user.email, user.firstName || user.username);
} catch (emailError) {
console.error('Failed to send welcome email:', emailError);
}
res.status(200).json({
success: true,
message: 'Email verified successfully!',
});
} catch (error) {
next(error);
}
}
// Resend verification email
async function resendVerification(req, res, next) {
try {
const { email } = req.body;
if (!email) {
return res.status(400).json({
success: false,
error: 'Email is required',
});
}
// Find user by email
const user = await prisma.user.findUnique({
where: { email },
});
if (!user) {
return res.status(404).json({
success: false,
error: 'User not found',
});
}
// Check if already verified
if (user.emailVerified) {
return res.status(400).json({
success: false,
error: 'Email is already verified',
});
}
// Generate new verification token and code
const verificationToken = generateVerificationToken();
const verificationCode = generateVerificationCode();
const verificationTokenExpiry = getTokenExpiry(24); // 24 hours
// Update user with new tokens
await prisma.user.update({
where: { id: user.id },
data: {
verificationToken,
verificationCode,
verificationTokenExpiry,
},
});
// Send verification email
await sendVerificationEmail(
user.email,
user.firstName || user.username,
verificationToken,
verificationCode
);
res.status(200).json({
success: true,
message: 'Verification email sent successfully',
});
} catch (error) {
next(error);
}
}
// Request password reset (send email with reset link)
async function requestPasswordReset(req, res, next) {
try {
const { email } = req.body;
if (!email) {
return res.status(400).json({
success: false,
error: 'Email is required',
});
}
// Find user by email
const user = await prisma.user.findUnique({
where: { email },
});
// Always return success to prevent email enumeration
if (!user) {
return res.status(200).json({
success: true,
message: 'If an account with that email exists, a password reset link has been sent.',
});
}
// Generate reset token
const resetToken = generateVerificationToken();
const resetTokenExpiry = getTokenExpiry(1); // 1 hour expiry
// Save reset token to database
await prisma.user.update({
where: { id: user.id },
data: {
resetToken,
resetTokenExpiry,
},
});
// Send password reset email
try {
await sendPasswordResetEmail(
user.email,
user.firstName || user.username,
resetToken
);
} catch (emailError) {
console.error('Failed to send password reset email:', emailError);
return res.status(500).json({
success: false,
error: 'Failed to send password reset email',
});
}
res.status(200).json({
success: true,
message: 'If an account with that email exists, a password reset link has been sent.',
});
} catch (error) {
next(error);
}
}
// Reset password using token
async function resetPassword(req, res, next) {
try {
const { token, newPassword } = req.body;
if (!token || !newPassword) {
return res.status(400).json({
success: false,
error: 'Token and new password are required',
});
}
// Validate password length
if (newPassword.length < 8) {
return res.status(400).json({
success: false,
error: 'Password must be at least 8 characters long',
});
}
// Find user by reset token
const user = await prisma.user.findUnique({
where: { resetToken: token },
});
if (!user) {
return res.status(400).json({
success: false,
error: 'Invalid or expired reset token',
});
}
// Check if token expired
if (user.resetTokenExpiry && new Date() > user.resetTokenExpiry) {
return res.status(400).json({
success: false,
error: 'Reset token has expired. Please request a new one.',
});
}
// Hash new password
const passwordHash = await hashPassword(newPassword);
// Update user password and clear reset token
await prisma.user.update({
where: { id: user.id },
data: {
passwordHash,
resetToken: null,
resetTokenExpiry: null,
},
});
res.status(200).json({
success: true,
message: 'Password reset successfully',
});
} catch (error) {
next(error);
}
}
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
module.exports = {
register,
login,
verifyEmailByToken,
verifyEmailByCode,
resendVerification,
requestPasswordReset,
resetPassword,
feat: add JWT authentication with complete test coverage Phase 1 - Step 3: Authentication API **Backend Authentication:** - bcryptjs for password hashing (salt rounds: 10) - JWT tokens with 24h expiration - Secure password storage (never expose passwordHash) **API Endpoints:** - POST /api/auth/register - User registration - Username validation (3-50 chars, alphanumeric + underscore) - Email validation and normalization - Password validation (min 6 chars) - Duplicate email/username detection - Auto-generated avatar (ui-avatars.com) - POST /api/auth/login - User authentication - Email + password credentials - Returns JWT token + user data - Invalid credentials protection - GET /api/users/me - Get current user (protected) - Requires valid JWT token - Returns user data + stats (matches, ratings) - Token validation via middleware **Security Features:** - express-validator for input sanitization - Auth middleware for protected routes - Token verification (Bearer token) - Password never returned in responses - Proper error messages (no information leakage) **Frontend Integration:** - API service layer (frontend/src/services/api.js) - Updated AuthContext to use real API - Token storage in localStorage - Automatic token inclusion in requests - Error handling for expired/invalid tokens **Unit Tests (30 tests, 78.26% coverage):** Auth Endpoints (14 tests): - ✅ Register: success, duplicate email, duplicate username - ✅ Register validation: invalid email, short password, short username - ✅ Login: success, wrong password, non-existent user, invalid format - ✅ Protected route: valid token, no token, invalid token, malformed header Auth Utils (9 tests): - ✅ Password hashing and comparison - ✅ Different hashes for same password - ✅ JWT generation and verification - ✅ Token expiration validation - ✅ Invalid token handling All tests passing ✅ Coverage: 78.26% ✅
2025-11-12 22:16:14 +01:00
};