mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-21 14:20:06 +08:00
refactor: 将默认密码相关逻辑重构为后端处理
This commit is contained in:
parent
5e032fcc6a
commit
ed0b8408df
@ -33,21 +33,6 @@ 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() {
|
|
||||||
const { data } = await serverRequest.get<ServerResponse<boolean>>(
|
|
||||||
'/auth/check_using_default_token'
|
|
||||||
)
|
|
||||||
return data.data
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async proxy<T>(url = '') {
|
public static async proxy<T>(url = '') {
|
||||||
const data = await serverRequest.get<ServerResponse<string>>(
|
const data = await serverRequest.get<ServerResponse<string>>(
|
||||||
'/base/proxy?url=' + encodeURIComponent(url)
|
'/base/proxy?url=' + encodeURIComponent(url)
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
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'
|
||||||
@ -12,9 +11,6 @@ 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,
|
||||||
@ -33,31 +29,10 @@ 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.changePassword(data.oldToken, data.newToken)
|
||||||
await WebUIManager.changePasswordFromDefault(data.newToken)
|
|
||||||
} else {
|
|
||||||
// 正常密码更新
|
|
||||||
await WebUIManager.changePassword(data.oldToken, data.newToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.success('修改成功')
|
toast.success('修改成功')
|
||||||
setToken('')
|
setToken('')
|
||||||
@ -69,43 +44,22 @@ 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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<title>修改密码 - NapCat WebUI</title>
|
<title>修改密码 - NapCat WebUI</title>
|
||||||
|
|
||||||
{isDefaultToken && (
|
<Controller
|
||||||
<div className="mb-4 p-3 bg-warning-50 border border-warning-200 rounded-lg">
|
control={control}
|
||||||
<p className="text-warning-700 text-sm">
|
name="oldToken"
|
||||||
检测到您正在使用默认密码,为了安全起见,请立即设置新密码。
|
render={({ field }) => (
|
||||||
</p>
|
<Input
|
||||||
</div>
|
{...field}
|
||||||
)}
|
label="旧密码"
|
||||||
|
placeholder="请输入旧密码"
|
||||||
{!isDefaultToken && (
|
type="password"
|
||||||
<Controller
|
/>
|
||||||
control={control}
|
)}
|
||||||
name="oldToken"
|
/>
|
||||||
render={({ field }) => (
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
label="旧密码"
|
|
||||||
placeholder="请输入旧密码"
|
|
||||||
type="password"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
@ -113,8 +67,8 @@ const ChangePasswordCard = () => {
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<Input
|
<Input
|
||||||
{...field}
|
{...field}
|
||||||
label={isDefaultToken ? "设置新密码" : "新密码"}
|
label="新密码"
|
||||||
placeholder={isDefaultToken ? "请设置一个安全的新密码" : "请输入新密码"}
|
placeholder="请输入新密码"
|
||||||
type="password"
|
type="password"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,52 +1,15 @@
|
|||||||
import { Spinner } from '@heroui/spinner'
|
import { Spinner } from '@heroui/spinner'
|
||||||
import { AnimatePresence, motion } from 'motion/react'
|
import { AnimatePresence, motion } from 'motion/react'
|
||||||
import { Suspense, useEffect } from 'react'
|
import { Suspense } from 'react'
|
||||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
|
import { Outlet, useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
import useAuth from '@/hooks/auth'
|
|
||||||
import useDialog from '@/hooks/use-dialog'
|
|
||||||
|
|
||||||
import WebUIManager from '@/controllers/webui_manager'
|
|
||||||
import DefaultLayout from '@/layouts/default'
|
import DefaultLayout from '@/layouts/default'
|
||||||
|
|
||||||
const CheckDefaultPassword = () => {
|
|
||||||
const { isAuth } = useAuth()
|
|
||||||
const dialog = useDialog()
|
|
||||||
const navigate = useNavigate()
|
|
||||||
const checkDefaultPassword = async () => {
|
|
||||||
const data = await WebUIManager.checkUsingDefaultToken()
|
|
||||||
if (data) {
|
|
||||||
dialog.confirm({
|
|
||||||
title: '修改默认密码',
|
|
||||||
content: '检测到当前密码为默认密码,为了您的安全,必须立即修改密码。',
|
|
||||||
confirmText: '前往修改',
|
|
||||||
onConfirm: () => {
|
|
||||||
navigate('/config?tab=token')
|
|
||||||
},
|
|
||||||
onCancel: () => {
|
|
||||||
navigate('/config?tab=token')
|
|
||||||
},
|
|
||||||
onClose() {
|
|
||||||
navigate('/config?tab=token')
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isAuth) {
|
|
||||||
checkDefaultPassword()
|
|
||||||
}
|
|
||||||
}, [isAuth])
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function IndexPage() {
|
export default function IndexPage() {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultLayout>
|
<DefaultLayout>
|
||||||
<CheckDefaultPassword />
|
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
<div className="flex justify-center px-10">
|
<div className="flex justify-center px-10">
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
NTMsgAtType,
|
NTMsgAtType,
|
||||||
} from '@/core';
|
} from '@/core';
|
||||||
import { OB11ConfigLoader } from '@/onebot/config';
|
import { OB11ConfigLoader } from '@/onebot/config';
|
||||||
|
import { pendingTokenToSend } from '@/webui/index';
|
||||||
import {
|
import {
|
||||||
OB11HttpClientAdapter,
|
OB11HttpClientAdapter,
|
||||||
OB11WebSocketClientAdapter,
|
OB11WebSocketClientAdapter,
|
||||||
@ -64,8 +65,8 @@ export class NapCatOneBot11Adapter {
|
|||||||
networkManager: OB11NetworkManager;
|
networkManager: OB11NetworkManager;
|
||||||
actions: ActionMap;
|
actions: ActionMap;
|
||||||
private readonly bootTime = Date.now() / 1000;
|
private readonly bootTime = Date.now() / 1000;
|
||||||
recallEventCache = new Map<string, any>();
|
recallEventCache = new Map<string, NodeJS.Timeout>();
|
||||||
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
|
constructor (core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
|
||||||
this.core = core;
|
this.core = core;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath, OneBotConfigSchema);
|
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath, OneBotConfigSchema);
|
||||||
@ -79,7 +80,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
this.actions = createActionMap(this, core);
|
this.actions = createActionMap(this, core);
|
||||||
this.networkManager = new OB11NetworkManager();
|
this.networkManager = new OB11NetworkManager();
|
||||||
}
|
}
|
||||||
async creatOneBotLog(ob11Config: OneBotConfig) {
|
async creatOneBotLog (ob11Config: OneBotConfig) {
|
||||||
let log = '[network] 配置加载\n';
|
let log = '[network] 配置加载\n';
|
||||||
for (const key of ob11Config.network.httpServers) {
|
for (const key of ob11Config.network.httpServers) {
|
||||||
log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`;
|
log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`;
|
||||||
@ -98,15 +99,44 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
return log;
|
return log;
|
||||||
}
|
}
|
||||||
async InitOneBot() {
|
async InitOneBot () {
|
||||||
const selfInfo = this.core.selfInfo;
|
const selfInfo = this.core.selfInfo;
|
||||||
const ob11Config = this.configLoader.configData;
|
const ob11Config = this.configLoader.configData;
|
||||||
|
|
||||||
this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid, false)
|
this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid, false)
|
||||||
.then((user) => {
|
.then(async (user) => {
|
||||||
selfInfo.nick = user.nick;
|
selfInfo.nick = user.nick;
|
||||||
this.context.logger.setLogSelfInfo(selfInfo);
|
this.context.logger.setLogSelfInfo(selfInfo);
|
||||||
WebUiDataRuntime.getQQLoginCallback()(true);
|
|
||||||
|
// 检查是否有待发送的token
|
||||||
|
if (pendingTokenToSend) {
|
||||||
|
this.context.logger.log('[NapCat] [OneBot] 🔐 检测到待发送的WebUI Token,开始发送');
|
||||||
|
try {
|
||||||
|
await this.core.apis.MsgApi.sendMsg(
|
||||||
|
{ chatType: ChatType.KCHATTYPEC2C, peerUid: selfInfo.uid, guildId: '' },
|
||||||
|
[{
|
||||||
|
elementType: ElementType.TEXT,
|
||||||
|
elementId: '',
|
||||||
|
textElement: {
|
||||||
|
content:
|
||||||
|
'[NapCat] 温馨提示:\n'+
|
||||||
|
'WebUI密码为默认密码,已进行强制修改\n'+
|
||||||
|
'新密码: ' +pendingTokenToSend,
|
||||||
|
atType: NTMsgAtType.ATTYPEUNKNOWN,
|
||||||
|
atUid: '',
|
||||||
|
atTinyId: '',
|
||||||
|
atNtUid: '',
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
5000
|
||||||
|
);
|
||||||
|
this.context.logger.log('[NapCat] [OneBot] ✅ WebUI Token 消息发送成功');
|
||||||
|
} catch (error) {
|
||||||
|
this.context.logger.logError('[NapCat] [OneBot] ❌ WebUI Token 消息发送失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WebUiDataRuntime.getQQLoginCallback()(true);
|
||||||
})
|
})
|
||||||
.catch(e => this.context.logger.logError(e));
|
.catch(e => this.context.logger.logError(e));
|
||||||
|
|
||||||
@ -120,7 +150,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
// new OB11PluginAdapter('myPlugin', this.core, this,this.actions)
|
// new OB11PluginAdapter('myPlugin', this.core, this,this.actions)
|
||||||
// );
|
// );
|
||||||
if (existsSync(this.context.pathWrapper.pluginPath)) {
|
if (existsSync(this.context.pathWrapper.pluginPath)) {
|
||||||
this.context.logger.log(`[Plugins] 插件目录存在,开始加载插件`);
|
this.context.logger.log('[Plugins] 插件目录存在,开始加载插件');
|
||||||
this.networkManager.registerAdapter(
|
this.networkManager.registerAdapter(
|
||||||
new OB11PluginMangerAdapter('plugin_manager', this.core, this, this.actions)
|
new OB11PluginMangerAdapter('plugin_manager', this.core, this, this.actions)
|
||||||
);
|
);
|
||||||
@ -181,25 +211,6 @@ export class NapCatOneBot11Adapter {
|
|||||||
WebUiDataRuntime.setQQVersion(this.core.context.basicInfoWrapper.getFullQQVersion());
|
WebUiDataRuntime.setQQVersion(this.core.context.basicInfoWrapper.getFullQQVersion());
|
||||||
WebUiDataRuntime.setQQLoginInfo(selfInfo);
|
WebUiDataRuntime.setQQLoginInfo(selfInfo);
|
||||||
WebUiDataRuntime.setQQLoginStatus(true);
|
WebUiDataRuntime.setQQLoginStatus(true);
|
||||||
|
|
||||||
let sendWebUiToken = async (token: string) => {
|
|
||||||
await this.core.apis.MsgApi.sendMsg(
|
|
||||||
{ chatType: ChatType.KCHATTYPEC2C, peerUid: selfInfo.uid, guildId: '' },
|
|
||||||
[{
|
|
||||||
elementType: ElementType.TEXT,
|
|
||||||
elementId: '',
|
|
||||||
textElement: {
|
|
||||||
content: 'Update WebUi Token: ' + token,
|
|
||||||
atType: NTMsgAtType.ATTYPEUNKNOWN,
|
|
||||||
atUid: '',
|
|
||||||
atTinyId: '',
|
|
||||||
atNtUid: '',
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
5000
|
|
||||||
)
|
|
||||||
};
|
|
||||||
WebUiDataRuntime.setWebUiTokenChangeCallback(sendWebUiToken);
|
|
||||||
WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => {
|
WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => {
|
||||||
const prev = this.configLoader.configData;
|
const prev = this.configLoader.configData;
|
||||||
this.configLoader.save(newConfig);
|
this.configLoader.save(newConfig);
|
||||||
@ -209,7 +220,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async reloadNetwork(prev: OneBotConfig, now: OneBotConfig): Promise<void> {
|
private async reloadNetwork (prev: OneBotConfig, now: OneBotConfig): Promise<void> {
|
||||||
const prevLog = await this.creatOneBotLog(prev);
|
const prevLog = await this.creatOneBotLog(prev);
|
||||||
const newLog = await this.creatOneBotLog(now);
|
const newLog = await this.creatOneBotLog(now);
|
||||||
this.context.logger.log(`[Notice] [OneBot11] 配置变更前:\n${prevLog}`);
|
this.context.logger.log(`[Notice] [OneBot11] 配置变更前:\n${prevLog}`);
|
||||||
@ -222,7 +233,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
await this.handleConfigChange(prev.network.websocketClients, now.network.websocketClients, OB11WebSocketClientAdapter);
|
await this.handleConfigChange(prev.network.websocketClients, now.network.websocketClients, OB11WebSocketClientAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleConfigChange<CT extends NetworkAdapterConfig>(
|
private async handleConfigChange<CT extends NetworkAdapterConfig> (
|
||||||
prevConfig: NetworkAdapterConfig[],
|
prevConfig: NetworkAdapterConfig[],
|
||||||
nowConfig: NetworkAdapterConfig[],
|
nowConfig: NetworkAdapterConfig[],
|
||||||
adapterClass: new (
|
adapterClass: new (
|
||||||
@ -254,7 +265,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initMsgListener() {
|
private initMsgListener () {
|
||||||
const msgListener = new NodeIKernelMsgListener();
|
const msgListener = new NodeIKernelMsgListener();
|
||||||
msgListener.onRecvSysMsg = (msg) => {
|
msgListener.onRecvSysMsg = (msg) => {
|
||||||
this.apis.MsgApi.parseSysMessage(msg)
|
this.apis.MsgApi.parseSysMessage(msg)
|
||||||
@ -368,7 +379,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
this.context.session.getMsgService().addKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger));
|
this.context.session.getMsgService().addKernelMsgListener(proxiedListenerOf(msgListener, this.context.logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
private initBuddyListener() {
|
private initBuddyListener () {
|
||||||
const buddyListener = new NodeIKernelBuddyListener();
|
const buddyListener = new NodeIKernelBuddyListener();
|
||||||
|
|
||||||
buddyListener.onBuddyReqChange = async (reqs) => {
|
buddyListener.onBuddyReqChange = async (reqs) => {
|
||||||
@ -399,7 +410,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
.addKernelBuddyListener(proxiedListenerOf(buddyListener, this.context.logger));
|
.addKernelBuddyListener(proxiedListenerOf(buddyListener, this.context.logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
private initGroupListener() {
|
private initGroupListener () {
|
||||||
const groupListener = new NodeIKernelGroupListener();
|
const groupListener = new NodeIKernelGroupListener();
|
||||||
|
|
||||||
groupListener.onGroupNotifiesUpdated = async (_, notifies) => {
|
groupListener.onGroupNotifiesUpdated = async (_, notifies) => {
|
||||||
@ -492,7 +503,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
.addKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger));
|
.addKernelGroupListener(proxiedListenerOf(groupListener, this.context.logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitMsg(message: RawMessage) {
|
private async emitMsg (message: RawMessage) {
|
||||||
const network = await this.networkManager.getAllConfig();
|
const network = await this.networkManager.getAllConfig();
|
||||||
this.context.logger.logDebug('收到新消息 RawMessage', message);
|
this.context.logger.logDebug('收到新消息 RawMessage', message);
|
||||||
await Promise.allSettled([
|
await Promise.allSettled([
|
||||||
@ -501,7 +512,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleMsg(message: RawMessage, network: Array<NetworkAdapterConfig>) {
|
private async handleMsg (message: RawMessage, network: Array<NetworkAdapterConfig>) {
|
||||||
// 过滤无效消息
|
// 过滤无效消息
|
||||||
if (message.msgType === NTMsgType.KMSGTYPENULL) {
|
if (message.msgType === NTMsgType.KMSGTYPENULL) {
|
||||||
return;
|
return;
|
||||||
@ -522,17 +533,17 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private isSelfMessage(ob11Msg: {
|
private isSelfMessage (ob11Msg: {
|
||||||
stringMsg: OB11Message;
|
stringMsg: OB11Message
|
||||||
arrayMsg: OB11Message;
|
arrayMsg: OB11Message
|
||||||
}): boolean {
|
}): boolean {
|
||||||
return ob11Msg.stringMsg.user_id.toString() == this.core.selfInfo.uin ||
|
return ob11Msg.stringMsg.user_id.toString() == this.core.selfInfo.uin ||
|
||||||
ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin;
|
ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createMsgMap(network: Array<NetworkAdapterConfig>, ob11Msg: {
|
private createMsgMap (network: Array<NetworkAdapterConfig>, ob11Msg: {
|
||||||
stringMsg: OB11Message;
|
stringMsg: OB11Message
|
||||||
arrayMsg: OB11Message;
|
arrayMsg: OB11Message
|
||||||
}, isSelfMsg: boolean, message: RawMessage): Map<string, OB11Message> {
|
}, isSelfMsg: boolean, message: RawMessage): Map<string, OB11Message> {
|
||||||
const msgMap: Map<string, OB11Message> = new Map();
|
const msgMap: Map<string, OB11Message> = new Map();
|
||||||
network.filter(e => e.enable).forEach(e => {
|
network.filter(e => e.enable).forEach(e => {
|
||||||
@ -550,7 +561,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
return msgMap;
|
return msgMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleDebugNetwork(network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, message: RawMessage) {
|
private handleDebugNetwork (network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, message: RawMessage) {
|
||||||
const debugNetwork = network.filter(e => e.enable && e.debug);
|
const debugNetwork = network.filter(e => e.enable && e.debug);
|
||||||
if (debugNetwork.length > 0) {
|
if (debugNetwork.length > 0) {
|
||||||
debugNetwork.forEach(adapter => {
|
debugNetwork.forEach(adapter => {
|
||||||
@ -564,7 +575,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleNotReportSelfNetwork(network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, isSelfMsg: boolean) {
|
private handleNotReportSelfNetwork (network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, isSelfMsg: boolean) {
|
||||||
if (isSelfMsg) {
|
if (isSelfMsg) {
|
||||||
const notReportSelfNetwork = network.filter(e => e.enable && (('reportSelfMessage' in e && !e.reportSelfMessage) || !('reportSelfMessage' in e)));
|
const notReportSelfNetwork = network.filter(e => e.enable && (('reportSelfMessage' in e && !e.reportSelfMessage) || !('reportSelfMessage' in e)));
|
||||||
notReportSelfNetwork.forEach(adapter => {
|
notReportSelfNetwork.forEach(adapter => {
|
||||||
@ -573,7 +584,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleGroupEvent(message: RawMessage) {
|
private async handleGroupEvent (message: RawMessage) {
|
||||||
try {
|
try {
|
||||||
// 群名片修改事件解析 任何都该判断
|
// 群名片修改事件解析 任何都该判断
|
||||||
if (message.senderUin && message.senderUin !== '0') {
|
if (message.senderUin && message.senderUin !== '0') {
|
||||||
@ -606,7 +617,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handlePrivateMsgEvent(message: RawMessage) {
|
private async handlePrivateMsgEvent (message: RawMessage) {
|
||||||
try {
|
try {
|
||||||
if (message.msgType === NTMsgType.KMSGTYPEGRAYTIPS) {
|
if (message.msgType === NTMsgType.KMSGTYPEGRAYTIPS) {
|
||||||
// 灰条为单元素消息
|
// 灰条为单元素消息
|
||||||
@ -624,7 +635,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitRecallMsg(message: RawMessage, element: MessageElement) {
|
private async emitRecallMsg (message: RawMessage, element: MessageElement) {
|
||||||
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
|
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
|
||||||
const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId) ?? MessageUnique.createUniqueMsgId(peer, message.msgId);
|
const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId) ?? MessageUnique.createUniqueMsgId(peer, message.msgId);
|
||||||
if (message.chatType == ChatType.KCHATTYPEC2C) {
|
if (message.chatType == ChatType.KCHATTYPEC2C) {
|
||||||
@ -635,7 +646,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitFriendRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
private async emitFriendRecallMsg (message: RawMessage, oriMessageId: number, element: MessageElement) {
|
||||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||||
if (!operatorUid) return undefined;
|
if (!operatorUid) return undefined;
|
||||||
return new OB11FriendRecallNoticeEvent(
|
return new OB11FriendRecallNoticeEvent(
|
||||||
@ -645,7 +656,7 @@ export class NapCatOneBot11Adapter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async emitGroupRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
|
private async emitGroupRecallMsg (message: RawMessage, oriMessageId: number, element: MessageElement) {
|
||||||
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
|
||||||
if (!operatorUid) return undefined;
|
if (!operatorUid) return undefined;
|
||||||
const operatorId = await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
const operatorId = await this.core.apis.UserApi.getUinByUidV2(operatorUid);
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { createServer } from 'http';
|
import { createServer } from 'http';
|
||||||
|
import { randomUUID } from 'node:crypto'
|
||||||
import { createServer as createHttpsServer } from 'https';
|
import { createServer as createHttpsServer } from 'https';
|
||||||
import { LogWrapper } from '@/common/log';
|
import { LogWrapper } from '@/common/log';
|
||||||
import { NapCatPathWrapper } from '@/common/path';
|
import { NapCatPathWrapper } from '@/common/path';
|
||||||
@ -30,17 +31,42 @@ const MAX_PORT_TRY = 100;
|
|||||||
import * as net from 'node:net';
|
import * as net from 'node:net';
|
||||||
import { WebUiDataRuntime } from './src/helper/Data';
|
import { WebUiDataRuntime } from './src/helper/Data';
|
||||||
import { existsSync, readFileSync } from 'node:fs';
|
import { existsSync, readFileSync } from 'node:fs';
|
||||||
|
|
||||||
export let webUiRuntimePort = 6099;
|
export let webUiRuntimePort = 6099;
|
||||||
export async function InitPort(parsedConfig: WebUiConfigType): Promise<[string, number, string]> {
|
// 全局变量:存储需要在QQ登录成功后发送的新token
|
||||||
|
export let pendingTokenToSend: string | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储WebUI启动时的初始token,用于鉴权
|
||||||
|
* - 无论是否在运行时修改密码,都应该使用此token进行鉴权
|
||||||
|
* - 运行时手动修改的密码将会在下次napcat重启后生效
|
||||||
|
* - 如果需要在运行时修改密码并立即生效,则需要在前端调用路由进行修改
|
||||||
|
*/
|
||||||
|
let initialWebUiToken: string = '';
|
||||||
|
|
||||||
|
export function setInitialWebUiToken(token: string) {
|
||||||
|
initialWebUiToken = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getInitialWebUiToken(): string {
|
||||||
|
return initialWebUiToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setPendingTokenToSend(token: string | null) {
|
||||||
|
pendingTokenToSend = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function InitPort(parsedConfig: WebUiConfigType): Promise<[string, number,string]> {
|
||||||
try {
|
try {
|
||||||
await tryUseHost(parsedConfig.host);
|
await tryUseHost(parsedConfig.host);
|
||||||
const port = await tryUsePort(parsedConfig.port, parsedConfig.host);
|
const port = await tryUsePort(parsedConfig.port, parsedConfig.host);
|
||||||
return [parsedConfig.host, port, parsedConfig.token];
|
return [parsedConfig.host, port, parsedConfig.token];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('host或port不可用', error);
|
console.log('host或port不可用', error);
|
||||||
return ['', 0, ''];
|
return ['', 0, randomUUID()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkCertificates(logger: LogWrapper): Promise<{ key: string, cert: string } | null> {
|
async function checkCertificates(logger: LogWrapper): Promise<{ key: string, cert: string } | null> {
|
||||||
try {
|
try {
|
||||||
const certPath = join(webUiPathWrapper.configPath, 'cert.pem');
|
const certPath = join(webUiPathWrapper.configPath, 'cert.pem');
|
||||||
@ -61,7 +87,27 @@ async function checkCertificates(logger: LogWrapper): Promise<{ key: string, cer
|
|||||||
export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapper) {
|
export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapper) {
|
||||||
webUiPathWrapper = pathWrapper;
|
webUiPathWrapper = pathWrapper;
|
||||||
WebUiConfig = new WebUiConfigWrapper();
|
WebUiConfig = new WebUiConfigWrapper();
|
||||||
const config = await WebUiConfig.GetWebUIConfig();
|
let config = await WebUiConfig.GetWebUIConfig();
|
||||||
|
|
||||||
|
// 检查并更新默认密码 - 最高优先级
|
||||||
|
if (config.defaultToken || config.token === 'napcat' || !config.token) {
|
||||||
|
const randomToken = Math.random().toString(36).slice(-8);
|
||||||
|
await WebUiConfig.UpdateWebUIConfig({ token: randomToken, defaultToken: false });
|
||||||
|
logger.log(`[NapCat] [WebUi] 🔐 检测到默认密码,已自动更新为安全密码: ${randomToken}`);
|
||||||
|
|
||||||
|
// 存储token到全局变量,等待QQ登录成功后发送
|
||||||
|
setPendingTokenToSend(randomToken);
|
||||||
|
logger.log(`[NapCat] [WebUi] 📤 新密码将在QQ登录成功后发送给用户`);
|
||||||
|
|
||||||
|
// 重新获取更新后的配置
|
||||||
|
config = await WebUiConfig.GetWebUIConfig();
|
||||||
|
} else {
|
||||||
|
logger.log(`[NapCat] [WebUi] ✅ 当前使用安全密码: ${config.token}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储启动时的初始token用于鉴权
|
||||||
|
setInitialWebUiToken(config.token);
|
||||||
|
logger.log(`[NapCat] [WebUi] 🔑 已缓存启动时的token用于鉴权,运行时手动修改配置文件密码将不会生效`);
|
||||||
|
|
||||||
// 检查是否禁用WebUI
|
// 检查是否禁用WebUI
|
||||||
if (config.disableWebUI) {
|
if (config.disableWebUI) {
|
||||||
@ -90,19 +136,6 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
WebUiDataRuntime.setQQLoginCallback(async (_status: boolean) => {
|
|
||||||
try {
|
|
||||||
if ((await WebUiConfig.GetWebUIConfig()).defaultToken) {
|
|
||||||
let randomToken = Math.random().toString(36).slice(-8);
|
|
||||||
await WebUiConfig.UpdateWebUIConfig({ token: randomToken });
|
|
||||||
console.log(`[NapCat] [WebUi] Update WebUi Token: ${randomToken}`);
|
|
||||||
await WebUiDataRuntime.getWebUiTokenChangeCallback()(randomToken);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(`[NapCat] [WebUi] Update WebUi Token failed.` + error);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
// ------------注册中间件------------
|
// ------------注册中间件------------
|
||||||
// 使用express的json中间件
|
// 使用express的json中间件
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
@ -182,7 +215,6 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp
|
|||||||
|
|
||||||
// ------------启动服务------------
|
// ------------启动服务------------
|
||||||
server.listen(port, host, async () => {
|
server.listen(port, host, async () => {
|
||||||
// 启动后打印出相关地址
|
|
||||||
let searchParams = { token: token };
|
let searchParams = { token: token };
|
||||||
logger.log(
|
logger.log(
|
||||||
`[NapCat] [WebUi] WebUi User Panel Url: ${createUrl('127.0.0.1', port.toString(), '/webui', searchParams)}`
|
`[NapCat] [WebUi] WebUi User Panel Url: ${createUrl('127.0.0.1', port.toString(), '/webui', searchParams)}`
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { RequestHandler } from 'express';
|
import { RequestHandler } from 'express';
|
||||||
|
|
||||||
import { WebUiConfig } from '@/webui';
|
import { WebUiConfig, getInitialWebUiToken, setInitialWebUiToken } from '@/webui';
|
||||||
|
|
||||||
import { AuthHelper } from '@webapi/helper/SignToken';
|
import { AuthHelper } from '@webapi/helper/SignToken';
|
||||||
import { WebUiDataRuntime } from '@webapi/helper/Data';
|
import { WebUiDataRuntime } from '@webapi/helper/Data';
|
||||||
@ -9,10 +9,7 @@ import { isEmpty } from '@webapi/utils/check';
|
|||||||
|
|
||||||
// 检查是否使用默认Token
|
// 检查是否使用默认Token
|
||||||
export const CheckDefaultTokenHandler: RequestHandler = async (_, res) => {
|
export const CheckDefaultTokenHandler: RequestHandler = async (_, res) => {
|
||||||
const webuiToken = await WebUiConfig.GetWebUIConfig();
|
// 由于密码在WebUI启动时已经确保不是默认密码,这里总是返回false
|
||||||
if (webuiToken.defaultToken) {
|
|
||||||
return sendSuccess(res, true);
|
|
||||||
}
|
|
||||||
return sendSuccess(res, false);
|
return sendSuccess(res, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,8 +30,13 @@ export const LoginHandler: RequestHandler = async (req, res) => {
|
|||||||
if (!WebUiDataRuntime.checkLoginRate(clientIP, WebUiConfigData.loginRate)) {
|
if (!WebUiDataRuntime.checkLoginRate(clientIP, WebUiConfigData.loginRate)) {
|
||||||
return sendError(res, 'login rate limit');
|
return sendError(res, 'login rate limit');
|
||||||
}
|
}
|
||||||
//验证config.token hash是否等于token hash
|
// 使用启动时缓存的token进行验证,而不是动态读取配置文件
|
||||||
if (!AuthHelper.comparePasswordHash(WebUiConfigData.token, hash)) {
|
const initialToken = getInitialWebUiToken();
|
||||||
|
if (!initialToken) {
|
||||||
|
return sendError(res, 'Server token not initialized');
|
||||||
|
}
|
||||||
|
//验证初始token hash是否等于提交的token hash
|
||||||
|
if (!AuthHelper.comparePasswordHash(initialToken, hash)) {
|
||||||
return sendError(res, 'token is invalid');
|
return sendError(res, 'token is invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,8 +65,6 @@ export const LogoutHandler: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
// 检查登录状态
|
// 检查登录状态
|
||||||
export const checkHandler: RequestHandler = async (req, res) => {
|
export const checkHandler: RequestHandler = async (req, res) => {
|
||||||
// 获取WebUI配置
|
|
||||||
const WebUiConfigData = await WebUiConfig.GetWebUIConfig();
|
|
||||||
// 获取请求头中的Authorization
|
// 获取请求头中的Authorization
|
||||||
const authorization = req.headers.authorization;
|
const authorization = req.headers.authorization;
|
||||||
// 检查凭证
|
// 检查凭证
|
||||||
@ -79,8 +79,13 @@ export const checkHandler: RequestHandler = async (req, res) => {
|
|||||||
return sendError(res, 'Token has been revoked');
|
return sendError(res, 'Token has been revoked');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 使用启动时缓存的token进行验证
|
||||||
|
const initialToken = getInitialWebUiToken();
|
||||||
|
if (!initialToken) {
|
||||||
|
return sendError(res, 'Server token not initialized');
|
||||||
|
}
|
||||||
// 验证凭证是否在一小时内有效
|
// 验证凭证是否在一小时内有效
|
||||||
const valid = AuthHelper.validateCredentialWithinOneHour(WebUiConfigData.token, Credential);
|
const valid = AuthHelper.validateCredentialWithinOneHour(initialToken, Credential);
|
||||||
// 返回成功信息
|
// 返回成功信息
|
||||||
if (valid) return sendSuccess(res, null);
|
if (valid) return sendSuccess(res, null);
|
||||||
// 返回错误信息
|
// 返回错误信息
|
||||||
@ -120,9 +125,21 @@ export const UpdateTokenHandler: RequestHandler = async (req, res) => {
|
|||||||
return sendError(res, 'Current password is not default password');
|
return sendError(res, 'Current password is not default password');
|
||||||
}
|
}
|
||||||
await WebUiConfig.UpdateWebUIConfig({ token: newToken, defaultToken: false });
|
await WebUiConfig.UpdateWebUIConfig({ token: newToken, defaultToken: false });
|
||||||
|
// 更新内存中的缓存token,使新密码立即生效
|
||||||
|
setInitialWebUiToken(newToken);
|
||||||
} else {
|
} else {
|
||||||
// 正常的密码更新流程
|
// 正常的密码更新流程 - 使用启动时缓存的token进行验证
|
||||||
await WebUiConfig.UpdateToken(oldToken, newToken);
|
const initialToken = getInitialWebUiToken();
|
||||||
|
if (!initialToken) {
|
||||||
|
return sendError(res, 'Server token not initialized');
|
||||||
|
}
|
||||||
|
if (initialToken !== oldToken) {
|
||||||
|
return sendError(res, '旧 token 不匹配');
|
||||||
|
}
|
||||||
|
// 直接更新配置文件中的token,不需要通过WebUiConfig.UpdateToken方法
|
||||||
|
await WebUiConfig.UpdateWebUIConfig({ token: newToken, defaultToken: false });
|
||||||
|
// 更新内存中的缓存token,使新密码立即生效
|
||||||
|
setInitialWebUiToken(newToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sendSuccess(res, 'Token updated successfully');
|
return sendSuccess(res, 'Token updated successfully');
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { webUiPathWrapper } from '@/webui';
|
import { webUiPathWrapper, getInitialWebUiToken } from '@/webui';
|
||||||
import { Type, Static } from '@sinclair/typebox';
|
import { Type, Static } from '@sinclair/typebox';
|
||||||
import Ajv from 'ajv';
|
import Ajv from 'ajv';
|
||||||
import fs, { constants } from 'node:fs/promises';
|
import fs, { constants } from 'node:fs/promises';
|
||||||
@ -63,6 +63,46 @@ export class WebUiConfigWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async GetWebUIConfig(): Promise<WebUiConfigType> {
|
async GetWebUIConfig(): Promise<WebUiConfigType> {
|
||||||
|
if (this.WebUiConfigData) {
|
||||||
|
return this.WebUiConfigData
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const configPath = resolve(webUiPathWrapper.configPath, './webui.json');
|
||||||
|
await this.ensureConfigFileExists(configPath);
|
||||||
|
const parsedConfig = await this.readAndValidateConfig(configPath);
|
||||||
|
// 使用内存中缓存的token进行覆盖,确保强兼容性
|
||||||
|
this.WebUiConfigData = {
|
||||||
|
...parsedConfig,
|
||||||
|
// 首次读取内存中是没有token的,需要进行一层兜底
|
||||||
|
token: getInitialWebUiToken() || parsedConfig.token
|
||||||
|
};
|
||||||
|
return this.WebUiConfigData;
|
||||||
|
} catch (e) {
|
||||||
|
console.log('读取配置文件失败', e);
|
||||||
|
const defaultConfig = this.validateAndApplyDefaults({});
|
||||||
|
return {
|
||||||
|
...defaultConfig,
|
||||||
|
token: defaultConfig.token
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async UpdateWebUIConfig(newConfig: Partial<WebUiConfigType>): Promise<void> {
|
||||||
|
const configPath = resolve(webUiPathWrapper.configPath, './webui.json');
|
||||||
|
// 使用原始配置进行合并,避免内存token覆盖影响配置更新
|
||||||
|
const currentConfig = await this.GetRawWebUIConfig();
|
||||||
|
const mergedConfig = deepMerge({ ...currentConfig }, newConfig);
|
||||||
|
const updatedConfig = this.validateAndApplyDefaults(mergedConfig);
|
||||||
|
await this.writeConfig(configPath, updatedConfig);
|
||||||
|
this.WebUiConfigData = updatedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置文件中实际存储的配置(不被内存token覆盖)
|
||||||
|
* 主要用于配置更新和特殊场景
|
||||||
|
*/
|
||||||
|
async GetRawWebUIConfig(): Promise<WebUiConfigType> {
|
||||||
if (this.WebUiConfigData) {
|
if (this.WebUiConfigData) {
|
||||||
return this.WebUiConfigData;
|
return this.WebUiConfigData;
|
||||||
}
|
}
|
||||||
@ -78,18 +118,12 @@ export class WebUiConfigWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async UpdateWebUIConfig(newConfig: Partial<WebUiConfigType>): Promise<void> {
|
|
||||||
const configPath = resolve(webUiPathWrapper.configPath, './webui.json');
|
|
||||||
const currentConfig = await this.GetWebUIConfig();
|
|
||||||
const mergedConfig = deepMerge({ ...currentConfig }, newConfig);
|
|
||||||
const updatedConfig = this.validateAndApplyDefaults(mergedConfig);
|
|
||||||
await this.writeConfig(configPath, updatedConfig);
|
|
||||||
this.WebUiConfigData = updatedConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
async UpdateToken(oldToken: string, newToken: string): Promise<void> {
|
async UpdateToken(oldToken: string, newToken: string): Promise<void> {
|
||||||
const currentConfig = await this.GetWebUIConfig();
|
// 使用内存中缓存的token进行验证,确保强兼容性
|
||||||
if (currentConfig.token !== oldToken) {
|
const cachedToken = getInitialWebUiToken();
|
||||||
|
const tokenToCheck = cachedToken || (await this.GetWebUIConfig()).token;
|
||||||
|
|
||||||
|
if (tokenToCheck !== oldToken) {
|
||||||
throw new Error('旧 token 不匹配');
|
throw new Error('旧 token 不匹配');
|
||||||
}
|
}
|
||||||
await this.UpdateWebUIConfig({ token: newToken, defaultToken: false });
|
await this.UpdateWebUIConfig({ token: newToken, defaultToken: false });
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
|
|
||||||
import { WebUiConfig } from '@/webui';
|
import { getInitialWebUiToken } from '@/webui';
|
||||||
|
|
||||||
import { AuthHelper } from '@webapi/helper/SignToken';
|
import { AuthHelper } from '@webapi/helper/SignToken';
|
||||||
import { sendError } from '@webapi/utils/response';
|
import { sendError } from '@webapi/utils/response';
|
||||||
@ -30,10 +30,13 @@ export async function auth(req: Request, res: Response, next: NextFunction) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
return sendError(res, 'Unauthorized');
|
return sendError(res, 'Unauthorized');
|
||||||
}
|
}
|
||||||
// 获取配置
|
// 使用启动时缓存的token进行验证,而不是动态读取配置文件 因为有可能运行时手动修改了密码
|
||||||
const config = await WebUiConfig.GetWebUIConfig();
|
const initialToken = getInitialWebUiToken();
|
||||||
|
if (!initialToken) {
|
||||||
|
return sendError(res, 'Server token not initialized');
|
||||||
|
}
|
||||||
// 验证凭证在1小时内有效
|
// 验证凭证在1小时内有效
|
||||||
const credentialJson = AuthHelper.validateCredentialWithinOneHour(config.token, Credential);
|
const credentialJson = AuthHelper.validateCredentialWithinOneHour(initialToken, Credential);
|
||||||
if (credentialJson) {
|
if (credentialJson) {
|
||||||
// 通过验证
|
// 通过验证
|
||||||
return next();
|
return next();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user