169 lines
4.3 KiB
TypeScript
169 lines
4.3 KiB
TypeScript
import type { FastifyInstance } from 'fastify';
|
|
import { AuthService } from '../services/auth/auth.service.js';
|
|
|
|
const registerSchema = {
|
|
body: {
|
|
type: 'object',
|
|
required: ['email', 'password', 'nickname'],
|
|
properties: {
|
|
email: { type: 'string', minLength: 1 },
|
|
password: { type: 'string', minLength: 8 },
|
|
nickname: { type: 'string', minLength: 2, maxLength: 30 },
|
|
},
|
|
},
|
|
};
|
|
|
|
const loginSchema = {
|
|
body: {
|
|
type: 'object',
|
|
required: ['email', 'password'],
|
|
properties: {
|
|
email: { type: 'string', minLength: 1 },
|
|
password: { type: 'string' },
|
|
},
|
|
},
|
|
};
|
|
|
|
const refreshTokenSchema = {
|
|
body: {
|
|
type: 'object',
|
|
required: ['refreshToken'],
|
|
properties: {
|
|
refreshToken: { type: 'string' },
|
|
},
|
|
},
|
|
};
|
|
|
|
const logoutSchema = refreshTokenSchema;
|
|
|
|
const verifyEmailSchema = {
|
|
body: {
|
|
type: 'object',
|
|
required: ['userId', 'code'],
|
|
properties: {
|
|
userId: { type: 'string', minLength: 1 },
|
|
code: { type: 'string', minLength: 1, maxLength: 10 },
|
|
},
|
|
},
|
|
};
|
|
|
|
const forgotPasswordSchema = {
|
|
body: {
|
|
type: 'object',
|
|
required: ['email'],
|
|
properties: {
|
|
email: { type: 'string', minLength: 1 },
|
|
},
|
|
},
|
|
};
|
|
|
|
const resetPasswordSchema = {
|
|
body: {
|
|
type: 'object',
|
|
required: ['token', 'newPassword'],
|
|
properties: {
|
|
token: { type: 'string' },
|
|
newPassword: { type: 'string', minLength: 8 },
|
|
},
|
|
},
|
|
};
|
|
|
|
export async function authRoutes(app: FastifyInstance) {
|
|
const authService = new AuthService(app.db);
|
|
const { rateLimitOptions } = app;
|
|
|
|
app.post(
|
|
'/register',
|
|
{ schema: registerSchema, config: { rateLimit: rateLimitOptions.register } },
|
|
async (req, reply) => {
|
|
const body = req.body as { email: string; password: string; nickname: string };
|
|
const { userId, verificationCode } = await authService.register(body);
|
|
|
|
return reply.status(201).send({
|
|
userId,
|
|
message: 'Registration successful. Please verify your email.',
|
|
verificationCode,
|
|
});
|
|
},
|
|
);
|
|
|
|
app.post(
|
|
'/login',
|
|
{ schema: loginSchema, config: { rateLimit: rateLimitOptions.login } },
|
|
async (req, reply) => {
|
|
const body = req.body as { email: string; password: string };
|
|
const userAgent = req.headers['user-agent'];
|
|
const ipAddress = req.ip;
|
|
|
|
const result = await authService.login({
|
|
email: body.email,
|
|
password: body.password,
|
|
userAgent,
|
|
ipAddress,
|
|
});
|
|
|
|
return reply.send(result);
|
|
},
|
|
);
|
|
|
|
app.post(
|
|
'/logout',
|
|
{ schema: logoutSchema, config: { rateLimit: rateLimitOptions.apiGuest } },
|
|
async (req, reply) => {
|
|
const body = req.body as { refreshToken: string };
|
|
await authService.logout(body.refreshToken);
|
|
return reply.status(204).send();
|
|
},
|
|
);
|
|
|
|
app.post(
|
|
'/refresh',
|
|
{ schema: refreshTokenSchema, config: { rateLimit: rateLimitOptions.apiGuest } },
|
|
async (req, reply) => {
|
|
const body = req.body as { refreshToken: string };
|
|
const userAgent = req.headers['user-agent'];
|
|
const ipAddress = req.ip;
|
|
|
|
const result = await authService.refresh({
|
|
refreshToken: body.refreshToken,
|
|
userAgent,
|
|
ipAddress,
|
|
});
|
|
|
|
return reply.send(result);
|
|
},
|
|
);
|
|
|
|
app.post(
|
|
'/verify-email',
|
|
{ schema: verifyEmailSchema, config: { rateLimit: rateLimitOptions.verifyEmail } },
|
|
async (req, reply) => {
|
|
const body = req.body as { userId: string; code: string };
|
|
await authService.verifyEmail(body.userId, body.code);
|
|
return reply.send({ message: 'Email verified successfully' });
|
|
},
|
|
);
|
|
|
|
app.post(
|
|
'/forgot-password',
|
|
{ schema: forgotPasswordSchema, config: { rateLimit: rateLimitOptions.forgotPassword } },
|
|
async (req, reply) => {
|
|
const body = req.body as { email: string };
|
|
await authService.forgotPassword(body.email);
|
|
return reply.send({
|
|
message: 'If the email exists, a reset link has been sent.',
|
|
});
|
|
},
|
|
);
|
|
|
|
app.post(
|
|
'/reset-password',
|
|
{ schema: resetPasswordSchema, config: { rateLimit: rateLimitOptions.forgotPassword } },
|
|
async (req, reply) => {
|
|
const body = req.body as { token: string; newPassword: string };
|
|
await authService.resetPassword(body.token, body.newPassword);
|
|
return reply.send({ message: 'Password reset successfully' });
|
|
},
|
|
);
|
|
}
|