diff --git a/astrbot/dashboard/routes/auth.py b/astrbot/dashboard/routes/auth.py
index 4ee0d57d4..70f9f6e2f 100644
--- a/astrbot/dashboard/routes/auth.py
+++ b/astrbot/dashboard/routes/auth.py
@@ -68,7 +68,11 @@ async def edit_account(self):
Response().error("新用户名和新密码不能同时为空,你改了个寂寞").__dict__
)
+ # Verify password confirmation
if new_pwd:
+ confirm_pwd = post_data.get("confirm_password", None)
+ if confirm_pwd != new_pwd:
+ return Response().error("两次输入的新密码不一致,健忘症患者?").__dict__
self.config["dashboard"]["password"] = new_pwd
if new_username:
self.config["dashboard"]["username"] = new_username
diff --git a/dashboard/src/i18n/locales/en-US/core/header.json b/dashboard/src/i18n/locales/en-US/core/header.json
index df3255ec0..080c59b13 100644
--- a/dashboard/src/i18n/locales/en-US/core/header.json
+++ b/dashboard/src/i18n/locales/en-US/core/header.json
@@ -72,14 +72,17 @@
"form": {
"currentPassword": "Current Password",
"newPassword": "New Password",
+ "confirmPassword": "Confirm New Password",
"newUsername": "New Username (Optional)",
"passwordHint": "Password must be at least 8 characters",
+ "confirmPasswordHint": "Please enter new password again to confirm",
"usernameHint": "Leave blank to keep current username",
"defaultCredentials": "Default username and password are both astrbot"
},
"validation": {
"passwordRequired": "Please enter password",
"passwordMinLength": "Password must be at least 8 characters",
+ "passwordMatch": "Passwords do not match",
"usernameMinLength": "Username must be at least 3 characters"
},
"actions": {
diff --git a/dashboard/src/i18n/locales/zh-CN/core/header.json b/dashboard/src/i18n/locales/zh-CN/core/header.json
index d21cb0f98..8b6b3dc1e 100644
--- a/dashboard/src/i18n/locales/zh-CN/core/header.json
+++ b/dashboard/src/i18n/locales/zh-CN/core/header.json
@@ -72,14 +72,17 @@
"form": {
"currentPassword": "当前密码",
"newPassword": "新密码",
+ "confirmPassword": "确认新密码",
"newUsername": "新用户名 (可选)",
"passwordHint": "密码长度至少 8 位",
+ "confirmPasswordHint": "请再次输入新密码以确认",
"usernameHint": "留空表示不修改用户名",
"defaultCredentials": "默认用户名和密码均为 astrbot"
},
"validation": {
"passwordRequired": "请输入密码",
"passwordMinLength": "密码长度至少 8 位",
+ "passwordMatch": "两次输入的密码不一致",
"usernameMinLength": "用户名长度至少3位"
},
"actions": {
@@ -90,4 +93,4 @@
"updateFailed": "修改失败,请重试"
}
}
-}
+}
diff --git a/dashboard/src/layouts/full/vertical-header/VerticalHeader.vue b/dashboard/src/layouts/full/vertical-header/VerticalHeader.vue
index 1bcd7f167..356d8344d 100644
--- a/dashboard/src/layouts/full/vertical-header/VerticalHeader.vue
+++ b/dashboard/src/layouts/full/vertical-header/VerticalHeader.vue
@@ -33,6 +33,7 @@ let aboutDialog = ref(false);
const username = localStorage.getItem('user');
let password = ref('');
let newPassword = ref('');
+let confirmPassword = ref('');
let newUsername = ref('');
let status = ref('');
let updateStatus = ref('')
@@ -89,6 +90,10 @@ const passwordRules = computed(() => [
(v: string) => !!v || t('core.header.accountDialog.validation.passwordRequired'),
(v: string) => v.length >= 8 || t('core.header.accountDialog.validation.passwordMinLength')
]);
+const confirmPasswordRules = computed(() => [
+ (v: string) => !newPassword.value || !!v || t('core.header.accountDialog.validation.passwordRequired'),
+ (v: string) => !newPassword.value || v === newPassword.value || t('core.header.accountDialog.validation.passwordMatch')
+]);
const usernameRules = computed(() => [
(v: string) => !v || v.length >= 3 || t('core.header.accountDialog.validation.usernameMinLength')
]);
@@ -96,6 +101,7 @@ const usernameRules = computed(() => [
// 显示密码相关
const showPassword = ref(false);
const showNewPassword = ref(false);
+const showConfirmPassword = ref(false);
// 账户修改状态
const accountEditStatus = ref({
@@ -169,17 +175,14 @@ function accountEdit() {
accountEditStatus.value.error = false;
accountEditStatus.value.success = false;
- // md5加密
- // @ts-ignore
- if (password.value != '') {
- password.value = md5(password.value);
- }
- if (newPassword.value != '') {
- newPassword.value = md5(newPassword.value);
- }
+ const passwordHash = password.value ? md5(password.value) : '';
+ const newPasswordHash = newPassword.value ? md5(newPassword.value) : '';
+ const confirmPasswordHash = confirmPassword.value ? md5(confirmPassword.value) : '';
+
axios.post('/api/auth/account/edit', {
- password: password.value,
- new_password: newPassword.value,
+ password: passwordHash,
+ new_password: newPasswordHash,
+ confirm_password: confirmPasswordHash,
new_username: newUsername.value ? newUsername.value : username
})
.then((res) => {
@@ -188,6 +191,7 @@ function accountEdit() {
accountEditStatus.value.message = res.data.message;
password.value = '';
newPassword.value = '';
+ confirmPassword.value = '';
return;
}
accountEditStatus.value.success = true;
@@ -204,6 +208,7 @@ function accountEdit() {
accountEditStatus.value.message = typeof err === 'string' ? err : t('core.header.accountDialog.messages.updateFailed');
password.value = '';
newPassword.value = '';
+ confirmPassword.value = '';
})
.finally(() => {
accountEditStatus.value.loading = false;
@@ -734,10 +739,16 @@ onMounted(async () => {
+
+