diff --git a/server/src/queries/user.repository.sql b/server/src/queries/user.repository.sql index 0638b8c965..88f94c85ac 100644 --- a/server/src/queries/user.repository.sql +++ b/server/src/queries/user.repository.sql @@ -97,6 +97,16 @@ where "users"."id" = $1 and "users"."deletedAt" is null +-- UserRepository.getForChangePassword +select + "users"."id", + "users"."password" +from + "users" +where + "users"."id" = $1 + and "users"."deletedAt" is null + -- UserRepository.getByEmail select "id", diff --git a/server/src/repositories/user.repository.ts b/server/src/repositories/user.repository.ts index 06159041c5..ef55c93222 100644 --- a/server/src/repositories/user.repository.ts +++ b/server/src/repositories/user.repository.ts @@ -100,6 +100,16 @@ export class UserRepository { .executeTakeFirstOrThrow(); } + @GenerateSql({ params: [DummyValue.UUID] }) + getForChangePassword(id: string) { + return this.db + .selectFrom('users') + .select(['users.id', 'users.password']) + .where('users.id', '=', id) + .where('users.deletedAt', 'is', null) + .executeTakeFirstOrThrow(); + } + @GenerateSql({ params: [DummyValue.EMAIL] }) getByEmail(email: string, options?: { withPassword?: boolean }) { return this.db diff --git a/server/src/services/auth.service.spec.ts b/server/src/services/auth.service.spec.ts index e84db72fc9..3568bb9d6b 100644 --- a/server/src/services/auth.service.spec.ts +++ b/server/src/services/auth.service.spec.ts @@ -116,46 +116,33 @@ describe(AuthService.name, () => { const auth = factory.auth({ user }); const dto = { password: 'old-password', newPassword: 'new-password' }; - mocks.user.getByEmail.mockResolvedValue({ ...user, password: 'hash-password' }); + mocks.user.getForChangePassword.mockResolvedValue({ id: user.id, password: 'hash-password' }); mocks.user.update.mockResolvedValue(user); await sut.changePassword(auth, dto); - expect(mocks.user.getByEmail).toHaveBeenCalledWith(auth.user.email, { withPassword: true }); + expect(mocks.user.getForChangePassword).toHaveBeenCalledWith(user.id); expect(mocks.crypto.compareBcrypt).toHaveBeenCalledWith('old-password', 'hash-password'); }); - it('should throw when auth user email is not found', async () => { - const auth = { user: { email: 'test@imimch.com' } } as AuthDto; - const dto = { password: 'old-password', newPassword: 'new-password' }; - - mocks.user.getByEmail.mockResolvedValue(void 0); - - await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(UnauthorizedException); - }); - it('should throw when password does not match existing password', async () => { - const auth = { user: { email: 'test@imimch.com' } as UserAdmin }; + const user = factory.user(); + const auth = factory.auth({ user }); const dto = { password: 'old-password', newPassword: 'new-password' }; mocks.crypto.compareBcrypt.mockReturnValue(false); - mocks.user.getByEmail.mockResolvedValue({ - email: 'test@immich.com', - password: 'hash-password', - } as UserAdmin & { password: string }); + mocks.user.getForChangePassword.mockResolvedValue({ id: user.id, password: 'hash-password' }); await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(BadRequestException); }); it('should throw when user does not have a password', async () => { - const auth = { user: { email: 'test@imimch.com' } } as AuthDto; + const user = factory.user(); + const auth = factory.auth({ user }); const dto = { password: 'old-password', newPassword: 'new-password' }; - mocks.user.getByEmail.mockResolvedValue({ - email: 'test@immich.com', - password: '', - } as UserAdmin & { password: string }); + mocks.user.getForChangePassword.mockResolvedValue({ id: user.id, password: '' }); await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(BadRequestException); }); diff --git a/server/src/services/auth.service.ts b/server/src/services/auth.service.ts index cbe892054d..70da8d81d3 100644 --- a/server/src/services/auth.service.ts +++ b/server/src/services/auth.service.ts @@ -91,11 +91,7 @@ export class AuthService extends BaseService { async changePassword(auth: AuthDto, dto: ChangePasswordDto): Promise { const { password, newPassword } = dto; - const user = await this.userRepository.getByEmail(auth.user.email, { withPassword: true }); - if (!user) { - throw new UnauthorizedException(); - } - + const user = await this.userRepository.getForChangePassword(auth.user.id); const valid = this.validateSecret(password, user.password); if (!valid) { throw new BadRequestException('Wrong password');