From d5b84ae0b8bcd83be91577668f777dbefdcf84f5 Mon Sep 17 00:00:00 2001 From: Finn Dittmar <86927734+Vito0912@users.noreply.github.com> Date: Tue, 24 Jun 2025 10:02:55 +0200 Subject: [PATCH] Only allow changing the email if the correct password is provided (#1288) * fix * fix overwriting password * finalize * BadRequestException --------- Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com> --- .../src/core/user/dto/update-user.dto.ts | 16 +++++++- apps/server/src/core/user/user.controller.ts | 2 +- apps/server/src/core/user/user.service.ts | 37 +++++++++++++++++-- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/apps/server/src/core/user/dto/update-user.dto.ts b/apps/server/src/core/user/dto/update-user.dto.ts index 6b55a3db..3f771339 100644 --- a/apps/server/src/core/user/dto/update-user.dto.ts +++ b/apps/server/src/core/user/dto/update-user.dto.ts @@ -1,5 +1,13 @@ import { OmitType, PartialType } from '@nestjs/mapped-types'; -import { IsBoolean, IsIn, IsOptional, IsString } from 'class-validator'; +import { + IsBoolean, + IsIn, + IsNotEmpty, + IsOptional, + IsString, + MaxLength, + MinLength, +} from 'class-validator'; import { CreateUserDto } from '../../auth/dto/create-user.dto'; export class UpdateUserDto extends PartialType( @@ -21,4 +29,10 @@ export class UpdateUserDto extends PartialType( @IsOptional() @IsString() locale: string; + + @IsOptional() + @MinLength(8) + @MaxLength(70) + @IsString() + confirmPassword: string; } diff --git a/apps/server/src/core/user/user.controller.ts b/apps/server/src/core/user/user.controller.ts index 97779a58..cf632648 100644 --- a/apps/server/src/core/user/user.controller.ts +++ b/apps/server/src/core/user/user.controller.ts @@ -50,6 +50,6 @@ export class UserController { @AuthUser() user: User, @AuthWorkspace() workspace: Workspace, ) { - return this.userService.update(updateUserDto, user.id, workspace.id); + return this.userService.update(updateUserDto, user.id, workspace); } } diff --git a/apps/server/src/core/user/user.service.ts b/apps/server/src/core/user/user.service.ts index d7c59320..f71c85f1 100644 --- a/apps/server/src/core/user/user.service.ts +++ b/apps/server/src/core/user/user.service.ts @@ -3,8 +3,12 @@ import { BadRequestException, Injectable, NotFoundException, + UnauthorizedException, } from '@nestjs/common'; import { UpdateUserDto } from './dto/update-user.dto'; +import { comparePasswordHash } from 'src/common/helpers/utils'; +import { Workspace } from '@docmost/db/types/entity.types'; +import { validateSsoEnforcement } from '../auth/auth.util'; @Injectable() export class UserService { @@ -17,9 +21,14 @@ export class UserService { async update( updateUserDto: UpdateUserDto, userId: string, - workspaceId: string, + workspace: Workspace, ) { - const user = await this.userRepo.findById(userId, workspaceId); + const includePassword = + updateUserDto.email != null && updateUserDto.confirmPassword != null; + + const user = await this.userRepo.findById(userId, workspace.id, { + includePassword, + }); if (!user) { throw new NotFoundException('User not found'); @@ -47,9 +56,27 @@ export class UserService { } if (updateUserDto.email && user.email != updateUserDto.email) { - if (await this.userRepo.findByEmail(updateUserDto.email, workspaceId)) { + validateSsoEnforcement(workspace); + + if (!updateUserDto.confirmPassword) { + throw new BadRequestException( + 'You must provide a password to change your email', + ); + } + + const isPasswordMatch = await comparePasswordHash( + updateUserDto.confirmPassword, + user.password, + ); + + if (!isPasswordMatch) { + throw new BadRequestException('You must provide the correct password to change your email'); + } + + if (await this.userRepo.findByEmail(updateUserDto.email, workspace.id)) { throw new BadRequestException('A user with this email already exists'); } + user.email = updateUserDto.email; } @@ -61,7 +88,9 @@ export class UserService { user.locale = updateUserDto.locale; } - await this.userRepo.updateUser(updateUserDto, userId, workspaceId); + delete updateUserDto.confirmPassword; + + await this.userRepo.updateUser(updateUserDto, userId, workspace.id); return user; } }