import { BadRequestException, Body, Controller, HttpCode, HttpStatus, Post, Req, Res, UseGuards, } from '@nestjs/common'; import { LoginDto } from './dto/login.dto'; import { AuthService } from './services/auth.service'; import { SetupGuard } from './guards/setup.guard'; import { EnvironmentService } from '../../integrations/environment/environment.service'; import { CreateAdminUserDto } from './dto/create-admin-user.dto'; import { ChangePasswordDto } from './dto/change-password.dto'; import { AuthUser } from '../../common/decorators/auth-user.decorator'; import { User, Workspace } from '@docmost/db/types/entity.types'; import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator'; import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'; import { ForgotPasswordDto } from './dto/forgot-password.dto'; import { PasswordResetDto } from './dto/password-reset.dto'; import { VerifyUserTokenDto } from './dto/verify-user-token.dto'; import { FastifyReply } from 'fastify'; import { addDays } from 'date-fns'; import { validateSsoEnforcement } from './auth.util'; @Controller('auth') export class AuthController { constructor( private authService: AuthService, private environmentService: EnvironmentService, ) {} @HttpCode(HttpStatus.OK) @Post('login') async login( @AuthWorkspace() workspace: Workspace, @Res({ passthrough: true }) res: FastifyReply, @Body() loginInput: LoginDto, ) { validateSsoEnforcement(workspace); const authToken = await this.authService.login(loginInput, workspace.id); this.setAuthCookie(res, authToken); } @UseGuards(SetupGuard) @HttpCode(HttpStatus.OK) @Post('setup') async setupWorkspace( @Res({ passthrough: true }) res: FastifyReply, @Body() createAdminUserDto: CreateAdminUserDto, ) { const { workspace, authToken } = await this.authService.setup(createAdminUserDto); this.setAuthCookie(res, authToken); return workspace; } @UseGuards(JwtAuthGuard) @HttpCode(HttpStatus.OK) @Post('change-password') async changePassword( @Body() dto: ChangePasswordDto, @AuthUser() user: User, @AuthWorkspace() workspace: Workspace, ) { return this.authService.changePassword(dto, user.id, workspace.id); } @HttpCode(HttpStatus.OK) @Post('forgot-password') async forgotPassword( @Body() forgotPasswordDto: ForgotPasswordDto, @AuthWorkspace() workspace: Workspace, ) { validateSsoEnforcement(workspace); return this.authService.forgotPassword(forgotPasswordDto, workspace); } @HttpCode(HttpStatus.OK) @Post('password-reset') async passwordReset( @Res({ passthrough: true }) res: FastifyReply, @Body() passwordResetDto: PasswordResetDto, @AuthWorkspace() workspace: Workspace, ) { const authToken = await this.authService.passwordReset( passwordResetDto, workspace.id, ); this.setAuthCookie(res, authToken); } @HttpCode(HttpStatus.OK) @Post('verify-token') async verifyResetToken( @Body() verifyUserTokenDto: VerifyUserTokenDto, @AuthWorkspace() workspace: Workspace, ) { return this.authService.verifyUserToken(verifyUserTokenDto, workspace.id); } @UseGuards(JwtAuthGuard) @HttpCode(HttpStatus.OK) @Post('collab-token') async collabToken( @AuthUser() user: User, @AuthWorkspace() workspace: Workspace, ) { return this.authService.getCollabToken(user.id, workspace.id); } @UseGuards(JwtAuthGuard) @HttpCode(HttpStatus.OK) @Post('logout') async logout(@Res({ passthrough: true }) res: FastifyReply) { res.clearCookie('authToken'); } setAuthCookie(res: FastifyReply, token: string) { res.setCookie('authToken', token, { httpOnly: true, path: '/', expires: addDays(new Date(), 30), secure: this.environmentService.isHttps(), }); } }