feat: 禁止默认密码

This commit is contained in:
手瓜一十雪 2025-09-06 11:41:06 +08:00
parent e4c1807f76
commit e406dca7ae
4 changed files with 94 additions and 20 deletions

View File

@ -33,6 +33,14 @@ export default class WebUIManager {
return data.data
}
public static async changePasswordFromDefault(newToken: string) {
const { data } = await serverRequest.post<ServerResponse<boolean>>(
'/auth/update_token',
{ newToken, fromDefault: true }
)
return data.data
}
public static async checkUsingDefaultToken() {
const { data } = await serverRequest.get<ServerResponse<boolean>>(
'/auth/check_using_default_token'

View File

@ -1,5 +1,6 @@
import { Input } from '@heroui/input'
import { useLocalStorage } from '@uidotdev/usehooks'
import { useEffect, useState } from 'react'
import { Controller, useForm } from 'react-hook-form'
import toast from 'react-hot-toast'
import { useNavigate } from 'react-router-dom'
@ -11,6 +12,9 @@ import SaveButtons from '@/components/button/save_buttons'
import WebUIManager from '@/controllers/webui_manager'
const ChangePasswordCard = () => {
const [isDefaultToken, setIsDefaultToken] = useState<boolean>(false)
const [isLoadingCheck, setIsLoadingCheck] = useState<boolean>(true)
const {
control,
handleSubmit: handleWebuiSubmit,
@ -29,9 +33,32 @@ const ChangePasswordCard = () => {
const navigate = useNavigate()
const [_, setToken] = useLocalStorage(key.token, '')
// 检查是否使用默认密码
useEffect(() => {
const checkDefaultToken = async () => {
try {
const isDefault = await WebUIManager.checkUsingDefaultToken()
setIsDefaultToken(isDefault)
} catch (error) {
console.error('检查默认密码状态失败:', error)
} finally {
setIsLoadingCheck(false)
}
}
checkDefaultToken()
}, [])
const onSubmit = handleWebuiSubmit(async (data) => {
try {
await WebUIManager.changePassword(data.oldToken, data.newToken)
if (isDefaultToken) {
// 从默认密码更新
await WebUIManager.changePasswordFromDefault(data.newToken)
} else {
// 正常密码更新
await WebUIManager.changePassword(data.oldToken, data.newToken)
}
toast.success('修改成功')
setToken('')
localStorage.removeItem(key.token)
@ -42,33 +69,57 @@ const ChangePasswordCard = () => {
}
})
if (isLoadingCheck) {
return (
<>
<title> - NapCat WebUI</title>
<div className="flex justify-center items-center h-32">
<div className="text-center">...</div>
</div>
</>
)
}
return (
<>
<title> - NapCat WebUI</title>
<Controller
control={control}
name="oldToken"
render={({ field }) => (
<Input
{...field}
label="旧密码"
placeholder="请输入旧密码"
type="password"
/>
)}
/>
{isDefaultToken && (
<div className="mb-4 p-3 bg-warning-50 border border-warning-200 rounded-lg">
<p className="text-warning-700 text-sm">
使
</p>
</div>
)}
{!isDefaultToken && (
<Controller
control={control}
name="oldToken"
render={({ field }) => (
<Input
{...field}
label="旧密码"
placeholder="请输入旧密码"
type="password"
/>
)}
/>
)}
<Controller
control={control}
name="newToken"
render={({ field }) => (
<Input
{...field}
label="新密码"
placeholder="请输入新密码"
label={isDefaultToken ? "设置新密码" : "新密码"}
placeholder={isDefaultToken ? "请设置一个安全的新密码" : "请输入新密码"}
type="password"
/>
)}
/>
<SaveButtons
onSubmit={onSubmit}
reset={reset}

View File

@ -25,7 +25,6 @@ export default function WebLoginPage() {
const [tokenValue, setTokenValue] = useState<string>(token || '')
const [isLoading, setIsLoading] = useState<boolean>(false)
const [, setLocalToken] = useLocalStorage<string>(key.token, '')
const onSubmit = async () => {
if (!tokenValue) {
toast.error('请输入token')

View File

@ -93,11 +93,16 @@ export const checkHandler: RequestHandler = async (req, res) => {
// 修改密码token
export const UpdateTokenHandler: RequestHandler = async (req, res) => {
const { oldToken, newToken } = req.body;
const { oldToken, newToken, fromDefault } = req.body;
const authorization = req.headers.authorization;
if (isEmpty(oldToken) || isEmpty(newToken)) {
return sendError(res, 'oldToken or newToken is empty');
if (isEmpty(newToken)) {
return sendError(res, 'newToken is empty');
}
// 如果不是从默认密码更新,则需要验证旧密码
if (!fromDefault && isEmpty(oldToken)) {
return sendError(res, 'oldToken is required when not updating from default password');
}
try {
@ -108,7 +113,18 @@ export const UpdateTokenHandler: RequestHandler = async (req, res) => {
AuthHelper.revokeCredential(Credential);
}
await WebUiConfig.UpdateToken(oldToken, newToken);
if (fromDefault) {
// 从默认密码更新,直接设置新密码
const currentConfig = await WebUiConfig.GetWebUIConfig();
if (!currentConfig.defaultToken) {
return sendError(res, 'Current password is not default password');
}
await WebUiConfig.UpdateWebUIConfig({ token: newToken, defaultToken: false });
} else {
// 正常的密码更新流程
await WebUiConfig.UpdateToken(oldToken, newToken);
}
return sendSuccess(res, 'Token updated successfully');
} catch (e: any) {
return sendError(res, `Failed to update token: ${e.message}`);