mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-21 06:10:04 +08:00
feat: 禁止默认密码
This commit is contained in:
parent
e4c1807f76
commit
e406dca7ae
@ -33,6 +33,14 @@ export default class WebUIManager {
|
|||||||
return data.data
|
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() {
|
public static async checkUsingDefaultToken() {
|
||||||
const { data } = await serverRequest.get<ServerResponse<boolean>>(
|
const { data } = await serverRequest.get<ServerResponse<boolean>>(
|
||||||
'/auth/check_using_default_token'
|
'/auth/check_using_default_token'
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { Input } from '@heroui/input'
|
import { Input } from '@heroui/input'
|
||||||
import { useLocalStorage } from '@uidotdev/usehooks'
|
import { useLocalStorage } from '@uidotdev/usehooks'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
import { Controller, useForm } from 'react-hook-form'
|
import { Controller, useForm } from 'react-hook-form'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
@ -11,6 +12,9 @@ import SaveButtons from '@/components/button/save_buttons'
|
|||||||
import WebUIManager from '@/controllers/webui_manager'
|
import WebUIManager from '@/controllers/webui_manager'
|
||||||
|
|
||||||
const ChangePasswordCard = () => {
|
const ChangePasswordCard = () => {
|
||||||
|
const [isDefaultToken, setIsDefaultToken] = useState<boolean>(false)
|
||||||
|
const [isLoadingCheck, setIsLoadingCheck] = useState<boolean>(true)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
handleSubmit: handleWebuiSubmit,
|
handleSubmit: handleWebuiSubmit,
|
||||||
@ -29,9 +33,32 @@ const ChangePasswordCard = () => {
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [_, setToken] = useLocalStorage(key.token, '')
|
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) => {
|
const onSubmit = handleWebuiSubmit(async (data) => {
|
||||||
try {
|
try {
|
||||||
|
if (isDefaultToken) {
|
||||||
|
// 从默认密码更新
|
||||||
|
await WebUIManager.changePasswordFromDefault(data.newToken)
|
||||||
|
} else {
|
||||||
|
// 正常密码更新
|
||||||
await WebUIManager.changePassword(data.oldToken, data.newToken)
|
await WebUIManager.changePassword(data.oldToken, data.newToken)
|
||||||
|
}
|
||||||
|
|
||||||
toast.success('修改成功')
|
toast.success('修改成功')
|
||||||
setToken('')
|
setToken('')
|
||||||
localStorage.removeItem(key.token)
|
localStorage.removeItem(key.token)
|
||||||
@ -42,9 +69,30 @@ const ChangePasswordCard = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (isLoadingCheck) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<title>修改密码 - NapCat WebUI</title>
|
<title>修改密码 - NapCat WebUI</title>
|
||||||
|
<div className="flex justify-center items-center h-32">
|
||||||
|
<div className="text-center">加载中...</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<title>修改密码 - NapCat WebUI</title>
|
||||||
|
|
||||||
|
{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
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="oldToken"
|
name="oldToken"
|
||||||
@ -57,18 +105,21 @@ const ChangePasswordCard = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="newToken"
|
name="newToken"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
label="新密码"
|
label={isDefaultToken ? "设置新密码" : "新密码"}
|
||||||
placeholder="请输入新密码"
|
placeholder={isDefaultToken ? "请设置一个安全的新密码" : "请输入新密码"}
|
||||||
type="password"
|
type="password"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SaveButtons
|
<SaveButtons
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
reset={reset}
|
reset={reset}
|
||||||
|
|||||||
@ -25,7 +25,6 @@ export default function WebLoginPage() {
|
|||||||
const [tokenValue, setTokenValue] = useState<string>(token || '')
|
const [tokenValue, setTokenValue] = useState<string>(token || '')
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
const [isLoading, setIsLoading] = useState<boolean>(false)
|
||||||
const [, setLocalToken] = useLocalStorage<string>(key.token, '')
|
const [, setLocalToken] = useLocalStorage<string>(key.token, '')
|
||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
if (!tokenValue) {
|
if (!tokenValue) {
|
||||||
toast.error('请输入token')
|
toast.error('请输入token')
|
||||||
|
|||||||
@ -93,11 +93,16 @@ export const checkHandler: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
// 修改密码(token)
|
// 修改密码(token)
|
||||||
export const UpdateTokenHandler: RequestHandler = async (req, res) => {
|
export const UpdateTokenHandler: RequestHandler = async (req, res) => {
|
||||||
const { oldToken, newToken } = req.body;
|
const { oldToken, newToken, fromDefault } = req.body;
|
||||||
const authorization = req.headers.authorization;
|
const authorization = req.headers.authorization;
|
||||||
|
|
||||||
if (isEmpty(oldToken) || isEmpty(newToken)) {
|
if (isEmpty(newToken)) {
|
||||||
return sendError(res, 'oldToken or newToken is empty');
|
return sendError(res, 'newToken is empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不是从默认密码更新,则需要验证旧密码
|
||||||
|
if (!fromDefault && isEmpty(oldToken)) {
|
||||||
|
return sendError(res, 'oldToken is required when not updating from default password');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -108,7 +113,18 @@ export const UpdateTokenHandler: RequestHandler = async (req, res) => {
|
|||||||
AuthHelper.revokeCredential(Credential);
|
AuthHelper.revokeCredential(Credential);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
await WebUiConfig.UpdateToken(oldToken, newToken);
|
||||||
|
}
|
||||||
|
|
||||||
return sendSuccess(res, 'Token updated successfully');
|
return sendSuccess(res, 'Token updated successfully');
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return sendError(res, `Failed to update token: ${e.message}`);
|
return sendError(res, `Failed to update token: ${e.message}`);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user