feat(server): remove deprecated password field from update-me (#32623)
* feat(server): remove deprecated password field from update-me * fix: tests for removed password field (cherry picked from commit 3f6a071203187681b6c06b977665dc624c431336)
This commit is contained in:
@@ -1,40 +0,0 @@
|
||||
import { LoginResponseDto, getMyUser, login } from '@immich/sdk';
|
||||
import { createUserDto } from 'src/fixtures.js';
|
||||
import { app, asBearerAuth, utils } from 'src/utils.js';
|
||||
import request from 'supertest';
|
||||
import { beforeAll, describe, expect, it } from 'vitest';
|
||||
|
||||
describe('/users', () => {
|
||||
let admin: LoginResponseDto;
|
||||
let nonAdmin: LoginResponseDto;
|
||||
|
||||
beforeAll(async () => {
|
||||
await utils.resetDatabase();
|
||||
admin = await utils.adminSetup({ onboarding: false });
|
||||
nonAdmin = await utils.userSetup(admin.accessToken, createUserDto.user2);
|
||||
});
|
||||
|
||||
describe('PUT /users/me', () => {
|
||||
/** @deprecated */
|
||||
it('should allow a user to change their password (deprecated)', async () => {
|
||||
const user = await getMyUser({ headers: asBearerAuth(nonAdmin.accessToken) });
|
||||
|
||||
expect(user.shouldChangePassword).toBe(true);
|
||||
|
||||
const { status, body } = await request(app)
|
||||
.put(`/users/me`)
|
||||
.send({ password: 'super-secret' })
|
||||
.set('Authorization', `Bearer ${nonAdmin.accessToken}`);
|
||||
|
||||
expect(status).toBe(200);
|
||||
expect(body).toMatchObject({
|
||||
email: nonAdmin.userEmail,
|
||||
shouldChangePassword: false,
|
||||
});
|
||||
|
||||
const token = await login({ loginCredentialDto: { email: nonAdmin.userEmail, password: 'super-secret' } });
|
||||
|
||||
expect(token.accessToken).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -71,6 +71,7 @@ test.describe('Registration', () => {
|
||||
// change password
|
||||
await expect(page.getByRole('heading')).toHaveText('Change Password');
|
||||
await expect(page).toHaveURL('/auth/change-password');
|
||||
await page.getByLabel('Password', { exact: true }).fill('password');
|
||||
await page.getByLabel('New Password').fill('new-password');
|
||||
await page.getByLabel('Confirm Password').fill('new-password');
|
||||
await page.getByRole('button', { name: 'Change password' }).click();
|
||||
|
||||
@@ -34312,11 +34312,6 @@
|
||||
"name": {
|
||||
"description": "User name",
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"deprecated": true,
|
||||
"description": "User password (deprecated, use change password endpoint)",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
|
||||
@@ -3266,8 +3266,6 @@ export type UserUpdateMeDto = {
|
||||
email?: string;
|
||||
/** User name */
|
||||
name?: string;
|
||||
/** User password (deprecated, use change password endpoint) */
|
||||
password?: string;
|
||||
};
|
||||
export type OnboardingResponseDto = {
|
||||
/** Is user onboarded */
|
||||
|
||||
@@ -11,11 +11,6 @@ import { isoDatetimeToDate, sanitizeFilename, stringToBool, toEmail } from 'src/
|
||||
export const UserUpdateMeSchema = z
|
||||
.object({
|
||||
email: toEmail.optional().describe('User email'),
|
||||
password: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('User password (deprecated, use change password endpoint)')
|
||||
.meta({ deprecated: true }),
|
||||
name: z.string().optional().describe('User name'),
|
||||
avatarColor: UserAvatarColorSchema.nullish(),
|
||||
})
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Updateable } from 'kysely';
|
||||
import { DateTime } from 'luxon';
|
||||
import type { ArgOf } from 'src/repositories/event.repository.js';
|
||||
import type { JobOf, UserMetadataItem } from 'src/types.js';
|
||||
import { SALT_ROUNDS } from 'src/constants.js';
|
||||
import { StorageCore } from 'src/cores/storage.core.js';
|
||||
import { OnEvent, OnJob } from 'src/decorators.js';
|
||||
import { AuthDto } from 'src/dtos/auth.dto.js';
|
||||
@@ -68,12 +67,6 @@ export class UserService extends BaseService {
|
||||
avatarColor: dto.avatarColor,
|
||||
};
|
||||
|
||||
if (dto.password) {
|
||||
const hashedPassword = await this.cryptoRepository.hashBcrypt(dto.password, SALT_ROUNDS);
|
||||
update.password = hashedPassword;
|
||||
update.shouldChangePassword = false;
|
||||
}
|
||||
|
||||
const updatedUser = await this.userRepository.update(user.id, update);
|
||||
|
||||
return mapUserAdmin(updatedUser);
|
||||
|
||||
@@ -198,17 +198,6 @@ describe(UserService.name, () => {
|
||||
await expect(sut.updateMe(auth, dto)).resolves.toMatchObject(dto);
|
||||
await expect(sut.getMe(auth)).resolves.toMatchObject(dto);
|
||||
});
|
||||
|
||||
it('should clear shouldChangePassword when the password is updated', async () => {
|
||||
const { sut, ctx } = setup();
|
||||
const { user } = await ctx.newUser({ shouldChangePassword: true });
|
||||
const auth = factory.auth({ user: { id: user.id } });
|
||||
|
||||
await expect(sut.updateMe(auth, { password: 'super-secret' })).resolves.toMatchObject({
|
||||
shouldChangePassword: false,
|
||||
});
|
||||
await expect(sut.getMe(auth)).resolves.toMatchObject({ shouldChangePassword: false });
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateMyPreferences', () => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import AuthPageLayout from '$lib/components/layouts/AuthPageLayout.svelte';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import { Route } from '$lib/route';
|
||||
import { updateMyUser } from '@immich/sdk';
|
||||
import { handleChangePassword } from '$lib/services/user.service';
|
||||
import { Alert, Button, Field, HelperText, PasswordInput, Stack, Text } from '@immich/ui';
|
||||
import { t } from 'svelte-i18n';
|
||||
import type { PageData } from './$types';
|
||||
@@ -14,9 +14,10 @@
|
||||
|
||||
let { data }: Props = $props();
|
||||
|
||||
let currentPassword = $state('');
|
||||
let password = $state('');
|
||||
let passwordConfirm = $state('');
|
||||
const valid = $derived(password === passwordConfirm && passwordConfirm.length > 0);
|
||||
const valid = $derived(currentPassword.length > 0 && password === passwordConfirm && passwordConfirm.length > 0);
|
||||
const errorMessage = $derived(passwordConfirm.length === 0 || valid ? '' : $t('password_does_not_match'));
|
||||
|
||||
const onSubmit = async () => {
|
||||
@@ -24,8 +25,10 @@
|
||||
return;
|
||||
}
|
||||
|
||||
await updateMyUser({ userUpdateMeDto: { password } });
|
||||
await goto(Route.logout());
|
||||
const success = await handleChangePassword({ password: currentPassword, newPassword: password });
|
||||
if (success) {
|
||||
await goto(Route.logout());
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -38,6 +41,10 @@
|
||||
</Stack>
|
||||
</Alert>
|
||||
|
||||
<Field label={$t('password')} required>
|
||||
<PasswordInput bind:value={currentPassword} autocomplete="current-password" />
|
||||
</Field>
|
||||
|
||||
<Field label={$t('new_password')} required>
|
||||
<PasswordInput bind:value={password} autocomplete="new-password" />
|
||||
</Field>
|
||||
|
||||
Reference in New Issue
Block a user