mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
refactor: change password repository lookup (#19584)
This commit is contained in:
parent
a2a9797fab
commit
09cbc5d3f4
@ -97,6 +97,16 @@ where
|
|||||||
"users"."id" = $1
|
"users"."id" = $1
|
||||||
and "users"."deletedAt" is null
|
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
|
-- UserRepository.getByEmail
|
||||||
select
|
select
|
||||||
"id",
|
"id",
|
||||||
|
@ -100,6 +100,16 @@ export class UserRepository {
|
|||||||
.executeTakeFirstOrThrow();
|
.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] })
|
@GenerateSql({ params: [DummyValue.EMAIL] })
|
||||||
getByEmail(email: string, options?: { withPassword?: boolean }) {
|
getByEmail(email: string, options?: { withPassword?: boolean }) {
|
||||||
return this.db
|
return this.db
|
||||||
|
@ -116,46 +116,33 @@ describe(AuthService.name, () => {
|
|||||||
const auth = factory.auth({ user });
|
const auth = factory.auth({ user });
|
||||||
const dto = { password: 'old-password', newPassword: 'new-password' };
|
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);
|
mocks.user.update.mockResolvedValue(user);
|
||||||
|
|
||||||
await sut.changePassword(auth, dto);
|
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');
|
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 () => {
|
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' };
|
const dto = { password: 'old-password', newPassword: 'new-password' };
|
||||||
|
|
||||||
mocks.crypto.compareBcrypt.mockReturnValue(false);
|
mocks.crypto.compareBcrypt.mockReturnValue(false);
|
||||||
|
|
||||||
mocks.user.getByEmail.mockResolvedValue({
|
mocks.user.getForChangePassword.mockResolvedValue({ id: user.id, password: 'hash-password' });
|
||||||
email: 'test@immich.com',
|
|
||||||
password: 'hash-password',
|
|
||||||
} as UserAdmin & { password: string });
|
|
||||||
|
|
||||||
await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(BadRequestException);
|
await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(BadRequestException);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw when user does not have a password', async () => {
|
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' };
|
const dto = { password: 'old-password', newPassword: 'new-password' };
|
||||||
|
|
||||||
mocks.user.getByEmail.mockResolvedValue({
|
mocks.user.getForChangePassword.mockResolvedValue({ id: user.id, password: '' });
|
||||||
email: 'test@immich.com',
|
|
||||||
password: '',
|
|
||||||
} as UserAdmin & { password: string });
|
|
||||||
|
|
||||||
await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(BadRequestException);
|
await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(BadRequestException);
|
||||||
});
|
});
|
||||||
|
@ -91,11 +91,7 @@ export class AuthService extends BaseService {
|
|||||||
|
|
||||||
async changePassword(auth: AuthDto, dto: ChangePasswordDto): Promise<UserAdminResponseDto> {
|
async changePassword(auth: AuthDto, dto: ChangePasswordDto): Promise<UserAdminResponseDto> {
|
||||||
const { password, newPassword } = dto;
|
const { password, newPassword } = dto;
|
||||||
const user = await this.userRepository.getByEmail(auth.user.email, { withPassword: true });
|
const user = await this.userRepository.getForChangePassword(auth.user.id);
|
||||||
if (!user) {
|
|
||||||
throw new UnauthorizedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
const valid = this.validateSecret(password, user.password);
|
const valid = this.validateSecret(password, user.password);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new BadRequestException('Wrong password');
|
throw new BadRequestException('Wrong password');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user