website-monitor/backend/src/routes/auth.ts

144 lines
3.2 KiB
TypeScript

import { Router, Request, Response } from 'express';
import { z } from 'zod';
import db from '../db';
import {
hashPassword,
comparePassword,
generateToken,
validateEmail,
validatePassword,
} from '../utils/auth';
const router = Router();
const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
const loginSchema = z.object({
email: z.string().email(),
password: z.string(),
});
// Register
router.post('/register', async (req: Request, res: Response): Promise<void> => {
try {
const { email, password } = registerSchema.parse(req.body);
if (!validateEmail(email)) {
res.status(400).json({
error: 'invalid_email',
message: 'Invalid email format',
});
return;
}
const passwordValidation = validatePassword(password);
if (!passwordValidation.valid) {
res.status(400).json({
error: 'invalid_password',
message: 'Password does not meet requirements',
details: passwordValidation.errors,
});
return;
}
const existingUser = await db.users.findByEmail(email);
if (existingUser) {
res.status(409).json({
error: 'user_exists',
message: 'User with this email already exists',
});
return;
}
const passwordHash = await hashPassword(password);
const user = await db.users.create(email, passwordHash);
const token = generateToken(user);
res.status(201).json({
token,
user: {
id: user.id,
email: user.email,
plan: user.plan,
createdAt: user.createdAt,
},
});
} catch (error) {
if (error instanceof z.ZodError) {
res.status(400).json({
error: 'validation_error',
message: 'Invalid input',
details: error.errors,
});
return;
}
console.error('Register error:', error);
res.status(500).json({
error: 'server_error',
message: 'Failed to register user',
});
}
});
// Login
router.post('/login', async (req: Request, res: Response): Promise<void> => {
try {
const { email, password } = loginSchema.parse(req.body);
const user = await db.users.findByEmail(email);
if (!user) {
res.status(401).json({
error: 'invalid_credentials',
message: 'Invalid email or password',
});
return;
}
const isValidPassword = await comparePassword(password, user.passwordHash);
if (!isValidPassword) {
res.status(401).json({
error: 'invalid_credentials',
message: 'Invalid email or password',
});
return;
}
await db.users.updateLastLogin(user.id);
const token = generateToken(user);
res.json({
token,
user: {
id: user.id,
email: user.email,
plan: user.plan,
createdAt: user.createdAt,
lastLoginAt: new Date(),
},
});
} catch (error) {
if (error instanceof z.ZodError) {
res.status(400).json({
error: 'validation_error',
message: 'Invalid input',
details: error.errors,
});
return;
}
console.error('Login error:', error);
res.status(500).json({
error: 'server_error',
message: 'Failed to login',
});
}
});
export default router;