diff --git a/backend/apps/web/models/auths.py b/backend/apps/web/models/auths.py
index 1bd4b4cb..800750c3 100644
--- a/backend/apps/web/models/auths.py
+++ b/backend/apps/web/models/auths.py
@@ -64,6 +64,11 @@ class SigninForm(BaseModel):
password: str
+class UpdatePasswordForm(BaseModel):
+ password: str
+ new_password: str
+
+
class SignupForm(BaseModel):
name: str
email: str
@@ -109,7 +114,16 @@ class AuthsTable:
except:
return None
- def delete_auth_by_id(self, id: str) -> Optional[UserModel]:
+ def update_user_password_by_id(self, id: str, new_password: str) -> bool:
+ try:
+ query = Auth.update(password=new_password).where(Auth.id == id)
+ result = query.execute()
+
+ return True if result == 1 else False
+ except:
+ return False
+
+ def delete_auth_by_id(self, id: str) -> bool:
try:
# Delete User
result = Users.delete_user_by_id(id)
diff --git a/backend/apps/web/routers/auths.py b/backend/apps/web/routers/auths.py
index 27d6a3b6..9174865a 100644
--- a/backend/apps/web/routers/auths.py
+++ b/backend/apps/web/routers/auths.py
@@ -11,6 +11,7 @@ import uuid
from apps.web.models.auths import (
SigninForm,
SignupForm,
+ UpdatePasswordForm,
UserResponse,
SigninResponse,
Auths,
@@ -53,6 +54,28 @@ async def get_session_user(cred=Depends(bearer_scheme)):
)
+############################
+# Update Password
+############################
+
+
+@router.post("/update/password", response_model=bool)
+async def update_password(form_data: UpdatePasswordForm, cred=Depends(bearer_scheme)):
+ token = cred.credentials
+ session_user = Users.get_user_by_token(token)
+
+ if session_user:
+ user = Auths.authenticate_user(session_user.email, form_data.password)
+
+ if user:
+ hashed = get_password_hash(form_data.new_password)
+ return Auths.update_user_password_by_id(user.id, hashed)
+ else:
+ raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_PASSWORD)
+ else:
+ raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED)
+
+
############################
# SignIn
############################
diff --git a/backend/constants.py b/backend/constants.py
index a068995d..761507f2 100644
--- a/backend/constants.py
+++ b/backend/constants.py
@@ -21,6 +21,9 @@ class ERROR_MESSAGES(str, Enum):
"Your session has expired or the token is invalid. Please sign in again."
)
INVALID_CRED = "The email or password provided is incorrect. Please check for typos and try logging in again."
+ INVALID_PASSWORD = (
+ "The password provided is incorrect. Please check for typos and try again."
+ )
UNAUTHORIZED = "401 Unauthorized"
ACCESS_PROHIBITED = "You do not have permission to access this resource. Please contact your administrator for assistance."
ACTION_PROHIBITED = (
diff --git a/src/lib/apis/auths/index.ts b/src/lib/apis/auths/index.ts
index 56a4a7a6..73934055 100644
--- a/src/lib/apis/auths/index.ts
+++ b/src/lib/apis/auths/index.ts
@@ -88,3 +88,34 @@ export const userSignUp = async (name: string, email: string, password: string)
return res;
};
+
+export const updateUserPassword = async (token: string, password: string, newPassword: string) => {
+ let error = null;
+
+ const res = await fetch(`${WEBUI_API_BASE_URL}/auths/update/password`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(token && { authorization: `Bearer ${token}` })
+ },
+ body: JSON.stringify({
+ password: password,
+ new_password: newPassword
+ })
+ })
+ .then(async (res) => {
+ if (!res.ok) throw await res.json();
+ return res.json();
+ })
+ .catch((err) => {
+ console.log(err);
+ error = err.detail;
+ return null;
+ });
+
+ if (error) {
+ throw error;
+ }
+
+ return res;
+};
diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte
index 47c57d99..18aa6eca 100644
--- a/src/lib/components/chat/SettingsModal.svelte
+++ b/src/lib/components/chat/SettingsModal.svelte
@@ -18,6 +18,7 @@
import Advanced from './Settings/Advanced.svelte';
import Modal from '../common/Modal.svelte';
+ import { updateUserPassword } from '$lib/apis/auths';
export let show = false;
@@ -118,6 +119,11 @@
let authType = 'Basic';
let authContent = '';
+ // Account
+ let currentPassword = '';
+ let newPassword = '';
+ let newPasswordConfirm = '';
+
// About
let ollamaVersion = '';
@@ -595,6 +601,31 @@
return models;
};
+ const updatePasswordHandler = async () => {
+ if (newPassword === newPasswordConfirm) {
+ const res = await updateUserPassword(localStorage.token, currentPassword, newPassword).catch(
+ (error) => {
+ toast.error(error);
+ return null;
+ }
+ );
+
+ if (res) {
+ toast.success('Successfully updated.');
+ }
+
+ currentPassword = '';
+ newPassword = '';
+ newPasswordConfirm = '';
+ } else {
+ toast.error(
+ `The passwords you entered don't quite match. Please double-check and try again.`
+ );
+ newPassword = '';
+ newPasswordConfirm = '';
+ }
+ };
+
onMount(async () => {
let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
console.log(settings);
@@ -845,6 +876,32 @@
{/if}
+
+