From b8151a038a1ea55afae8073b439b74e364cac12f Mon Sep 17 00:00:00 2001 From: Ariel Leyva Date: Sat, 3 Jan 2026 02:44:03 -0500 Subject: [PATCH] fix: request a password to change sensitive user data (#5629) --- errors/errors.go | 33 +++++++++++++------------ frontend/src/api/users.ts | 10 ++++++-- frontend/src/i18n/en.json | 3 ++- frontend/src/types/settings.d.ts | 1 + frontend/src/views/settings/Profile.vue | 19 ++++++++++++-- frontend/src/views/settings/User.vue | 28 ++++++++++++++++++--- http/http.go | 5 ++-- http/settings.go | 2 ++ http/users.go | 28 +++++++++++++++++++++ 9 files changed, 103 insertions(+), 26 deletions(-) diff --git a/errors/errors.go b/errors/errors.go index 85258e5b..748354a8 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -6,22 +6,23 @@ import ( ) var ( - ErrEmptyKey = errors.New("empty key") - ErrExist = errors.New("the resource already exists") - ErrNotExist = errors.New("the resource does not exist") - ErrEmptyPassword = errors.New("password is empty") - ErrEasyPassword = errors.New("password is too easy") - ErrEmptyUsername = errors.New("username is empty") - ErrEmptyRequest = errors.New("empty request") - ErrScopeIsRelative = errors.New("scope is a relative path") - ErrInvalidDataType = errors.New("invalid data type") - ErrIsDirectory = errors.New("file is directory") - ErrInvalidOption = errors.New("invalid option") - ErrInvalidAuthMethod = errors.New("invalid auth method") - ErrPermissionDenied = errors.New("permission denied") - ErrInvalidRequestParams = errors.New("invalid request params") - ErrSourceIsParent = errors.New("source is parent") - ErrRootUserDeletion = errors.New("user with id 1 can't be deleted") + ErrEmptyKey = errors.New("empty key") + ErrExist = errors.New("the resource already exists") + ErrNotExist = errors.New("the resource does not exist") + ErrEmptyPassword = errors.New("password is empty") + ErrEasyPassword = errors.New("password is too easy") + ErrEmptyUsername = errors.New("username is empty") + ErrEmptyRequest = errors.New("empty request") + ErrScopeIsRelative = errors.New("scope is a relative path") + ErrInvalidDataType = errors.New("invalid data type") + ErrIsDirectory = errors.New("file is directory") + ErrInvalidOption = errors.New("invalid option") + ErrInvalidAuthMethod = errors.New("invalid auth method") + ErrPermissionDenied = errors.New("permission denied") + ErrInvalidRequestParams = errors.New("invalid request params") + ErrSourceIsParent = errors.New("source is parent") + ErrRootUserDeletion = errors.New("user with id 1 can't be deleted") + ErrCurrentPasswordIncorrect = errors.New("the current password is incorrect") ) type ErrShortPassword struct { diff --git a/frontend/src/api/users.ts b/frontend/src/api/users.ts index 78096b49..56e1d0f3 100644 --- a/frontend/src/api/users.ts +++ b/frontend/src/api/users.ts @@ -8,12 +8,13 @@ export async function get(id: number) { return fetchJSON(`/api/users/${id}`, {}); } -export async function create(user: IUser) { +export async function create(user: IUser, currentPassword: string) { const res = await fetchURL(`/api/users`, { method: "POST", body: JSON.stringify({ what: "user", which: [], + current_password: currentPassword, data: user, }), }); @@ -25,12 +26,17 @@ export async function create(user: IUser) { throw new StatusError(await res.text(), res.status); } -export async function update(user: Partial, which = ["all"]) { +export async function update( + user: Partial, + which = ["all"], + currentPassword: string | null = null +) { await fetchURL(`/api/users/${user.id}`, { method: "PUT", body: JSON.stringify({ what: "user", which: which, + ...(currentPassword != null ? { current_password: currentPassword } : {}), data: user, }), }); diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index de5368bd..60fe527f 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -258,7 +258,8 @@ "userManagement": "User Management", "userUpdated": "User updated!", "username": "Username", - "users": "Users" + "users": "Users", + "currentPassword": "Your Current Password" }, "sidebar": { "help": "Help", diff --git a/frontend/src/types/settings.d.ts b/frontend/src/types/settings.d.ts index 562c718b..c213e016 100644 --- a/frontend/src/types/settings.d.ts +++ b/frontend/src/types/settings.d.ts @@ -5,6 +5,7 @@ interface ISettings { minimumPasswordLength: number; userHomeBasePath: string; defaults: SettingsDefaults; + authMethod: string; rules: any[]; branding: SettingsBranding; tus: SettingsTus; diff --git a/frontend/src/views/settings/Profile.vue b/frontend/src/views/settings/Profile.vue index 1b079473..328b2f1a 100644 --- a/frontend/src/views/settings/Profile.vue +++ b/frontend/src/views/settings/Profile.vue @@ -69,6 +69,15 @@ v-model="passwordConf" name="passwordConf" /> +
@@ -87,7 +96,7 @@