boredgame/src/lib/server/api/controllers/iam.controller.ts

104 lines
4.7 KiB
TypeScript

import { StatusCodes } from '$lib/constants/status-codes';
import { Controller } from '$lib/server/api/common/types/controller';
import { changePasswordDto } from '$lib/server/api/dtos/change-password.dto';
import { updateEmailDto } from '$lib/server/api/dtos/update-email.dto';
import { updateProfileDto } from '$lib/server/api/dtos/update-profile.dto';
import { verifyPasswordDto } from '$lib/server/api/dtos/verify-password.dto';
import { limiter } from '$lib/server/api/middleware/rate-limiter.middleware';
import { IamService } from '$lib/server/api/services/iam.service';
import { LoginRequestsService } from '$lib/server/api/services/loginrequest.service';
import { LuciaService } from '$lib/server/api/services/lucia.service';
import { zValidator } from '@hono/zod-validator';
import { setCookie } from 'hono/cookie';
import { inject, injectable } from 'tsyringe';
import { requireAuth } from '../middleware/require-auth.middleware';
@injectable()
export class IamController extends Controller {
constructor(
@inject(IamService) private readonly iamService: IamService,
@inject(LoginRequestsService) private readonly loginRequestService: LoginRequestsService,
@inject(LuciaService) private luciaService: LuciaService,
) {
super();
}
routes() {
const tags = ['IAM'];
return this.controller
.get('/', requireAuth, async (c) => {
const user = c.var.user;
return c.json({ user });
})
.put('/update/profile', requireAuth, zValidator('json', updateProfileDto), limiter({ limit: 30, minutes: 60 }), async (c) => {
const user = c.var.user;
const { firstName, lastName, username } = c.req.valid('json');
const updatedUser = await this.iamService.updateProfile(user.id, { firstName, lastName, username });
if (!updatedUser) {
return c.json('Username already in use', StatusCodes.BAD_REQUEST);
}
return c.json({ user: updatedUser }, StatusCodes.OK);
})
.post('/verify/password', requireAuth, zValidator('json', verifyPasswordDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
const user = c.var.user;
const { password } = c.req.valid('json');
const passwordVerified = await this.iamService.verifyPassword(user.id, { password });
if (!passwordVerified) {
console.log('Incorrect password');
return c.json('Incorrect password', StatusCodes.BAD_REQUEST);
}
return c.json({}, StatusCodes.OK);
})
.put('/update/password', requireAuth, zValidator('json', changePasswordDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
const user = c.var.user;
const { password, confirm_password } = c.req.valid('json');
if (password !== confirm_password) {
return c.json('Passwords do not match', StatusCodes.BAD_REQUEST);
}
try {
await this.iamService.updatePassword(user.id, { password, confirm_password });
await this.luciaService.lucia.invalidateUserSessions(user.id);
await this.loginRequestService.createUserSession(user.id, c.req, undefined);
const sessionCookie = this.luciaService.lucia.createBlankSessionCookie();
setCookie(c, sessionCookie.name, sessionCookie.value, {
path: sessionCookie.attributes.path,
maxAge: sessionCookie.attributes.maxAge,
domain: sessionCookie.attributes.domain,
sameSite: sessionCookie.attributes.sameSite as any,
secure: sessionCookie.attributes.secure,
httpOnly: sessionCookie.attributes.httpOnly,
expires: sessionCookie.attributes.expires,
});
return c.json({ status: 'success' });
} catch (error) {
console.error('Error updating password', error);
return c.json('Error updating password', StatusCodes.BAD_REQUEST);
}
})
.post('/update/email', requireAuth, zValidator('json', updateEmailDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
const user = c.var.user;
const { email } = c.req.valid('json');
const updatedUser = await this.iamService.updateEmail(user.id, { email });
if (!updatedUser) {
return c.json('Email already in use', StatusCodes.BAD_REQUEST);
}
return c.json({ user: updatedUser }, StatusCodes.OK);
})
.post('/logout', requireAuth, async (c) => {
const sessionId = c.var.session.id;
await this.iamService.logout(sessionId);
const sessionCookie = this.luciaService.lucia.createBlankSessionCookie();
setCookie(c, sessionCookie.name, sessionCookie.value, {
path: sessionCookie.attributes.path,
maxAge: sessionCookie.attributes.maxAge,
domain: sessionCookie.attributes.domain,
sameSite: sessionCookie.attributes.sameSite as any,
secure: sessionCookie.attributes.secure,
httpOnly: sessionCookie.attributes.httpOnly,
expires: sessionCookie.attributes.expires,
});
return c.json({ status: 'success' });
});
}
}