Compare commits

...

8 Commits

Author SHA1 Message Date
手瓜一十雪
93f78f4db5 feat: #780 2025-02-08 17:34:31 +08:00
手瓜一十雪
404bfdd5e6 fix: #783 2025-02-08 17:00:11 +08:00
Mlikiowa
e4577dc2f1 release: v4.5.17 2025-02-07 12:40:47 +00:00
pk5ls20
5c932e5a27 fix: native rkey 2025-02-07 19:20:35 +08:00
Mlikiowa
4bd63c6267 release: v4.5.16 2025-02-07 10:02:35 +00:00
bietiaop
aabe24f903 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2025-02-07 18:00:31 +08:00
bietiaop
69cebd7fbc feat: 提示修改默认密码 2025-02-07 18:00:22 +08:00
Mlikiowa
8da371176a release: v4.5.15 2025-02-07 09:52:51 +00:00
14 changed files with 180 additions and 97 deletions

View File

@@ -4,7 +4,7 @@
"name": "NapCatQQ",
"slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现",
"version": "4.5.14",
"version": "4.5.17",
"icon": "./logo.png",
"authors": [
{

View File

@@ -9,14 +9,6 @@ export interface Log {
message: string
}
export interface TerminalSession {
id: string
}
export interface TerminalInfo {
id: string
}
export default class WebUIManager {
public static async checkWebUiLogined() {
const { data } =
@@ -40,6 +32,13 @@ export default class WebUIManager {
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 = '') {
const data = await serverRequest.get<ServerResponse<string>>(
'/base/proxy?url=' + encodeURIComponent(url)

View File

@@ -1,6 +1,7 @@
import { Card, CardBody } from '@heroui/card'
import { Tab, Tabs } from '@heroui/tabs'
import { useMediaQuery } from 'react-responsive'
import { useNavigate, useSearchParams } from 'react-router-dom'
import ChangePasswordCard from './change_password'
import OneBotConfigCard from './onebot'
@@ -22,6 +23,11 @@ const ConfingPageItem: React.FC<ConfigPageProps> = ({ children }) => {
export default function ConfigPage() {
const isMediumUp = useMediaQuery({ minWidth: 768 })
const navigate = useNavigate()
const search = useSearchParams({
tab: 'onebot'
})[0]
const tab = search.get('tab') ?? 'onebot'
return (
<section className="w-[1000px] max-w-full md:mx-auto gap-4 py-8 px-2 md:py-10">
@@ -30,6 +36,10 @@ export default function ConfigPage() {
fullWidth
className="w-full"
isVertical={isMediumUp}
selectedKey={tab}
onSelectionChange={(key) => {
navigate(`/config?tab=${key}`)
}}
classNames={{
tabList: 'sticky flex top-14 bg-opacity-50 backdrop-blur-sm',
panel: 'w-full relative',

View File

@@ -1,14 +1,46 @@
import { Spinner } from '@heroui/spinner'
import { AnimatePresence, motion } from 'motion/react'
import { Suspense } from 'react'
import { Outlet, useLocation } from 'react-router-dom'
import { Suspense, useEffect } from 'react'
import { Outlet, useLocation, useNavigate } 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'
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')
}
})
}
}
useEffect(() => {
if (isAuth) {
checkDefaultPassword()
}
}, [isAuth])
return null
}
export default function IndexPage() {
const location = useLocation()
return (
<DefaultLayout>
<CheckDefaultPassword />
<Suspense
fallback={
<div className="flex justify-center px-10">

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "4.5.14",
"version": "4.5.17",
"scripts": {
"build:universal": "npm run build:webui && vite build --mode universal || exit 1",
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",

View File

@@ -1 +1 @@
export const napCatVersion = '4.5.14';
export const napCatVersion = '4.5.17';

View File

@@ -434,9 +434,9 @@ export class NTQQFileApi {
};
try {
if (this.core.apis.PacketApi.available && this.packetRkey?.[0] && this.packetRkey?.[1]) {
const rkey_expired_private = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
const rkey_expired_group = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
if (this.core.apis.PacketApi.available) {
const rkey_expired_private = !this.packetRkey || (this.packetRkey[0] && this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000);
const rkey_expired_group = !this.packetRkey || (this.packetRkey[0] && this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000);
if (rkey_expired_private || rkey_expired_group) {
this.packetRkey = await this.fetchRkeyWithRetry();
}

View File

@@ -9,7 +9,7 @@ export const NapcatConfigSchema = Type.Object({
fileLogLevel: Type.String({ default: 'debug' }),
consoleLogLevel: Type.String({ default: 'info' }),
packetBackend: Type.String({ default: 'auto' }),
packetServer: Type.String({ default: '' })
packetServer: Type.String({ default: '' }),
});
export type NapcatConfig = Static<typeof NapcatConfigSchema>;

View File

@@ -1069,7 +1069,7 @@ export class OneBotMsgApi {
}
}
return false;
}, 1, 1000).catch(undefined);
}, 1, 1000).catch(() => undefined);
if (dataNotify) {
return !dataNotify.actionUser.uid ? dataNotify.user2.uid : dataNotify.actionUser.uid;
}

View File

@@ -10,7 +10,7 @@ import { WebUiConfigWrapper } from '@webapi/helper/config';
import { ALLRouter } from '@webapi/router';
import { cors } from '@webapi/middleware/cors';
import { createUrl } from '@webapi/utils/url';
import { sendError, sendSuccess } from '@webapi/utils/response';
import { sendError } from '@webapi/utils/response';
import { join } from 'node:path';
import { terminalManager } from '@webapi/terminal/terminal_manager';
import multer from 'multer'; // 新增引入multer用于错误捕获
@@ -28,6 +28,7 @@ export let WebUiConfig: WebUiConfigWrapper;
export let webUiPathWrapper: NapCatPathWrapper;
const MAX_PORT_TRY = 100;
import * as net from 'node:net';
import { WebUiDataRuntime } from './src/helper/Data';
export async function InitPort(parsedConfig: WebUiConfigType): Promise<[string, number, string]> {
try {
@@ -48,7 +49,20 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp
logger.log('[NapCat] [WebUi] Current WebUi is not run.');
return;
}
setTimeout(async () => {
let autoLoginAccount = process.env['NAPCAT_QUICK_ACCOUNT'] || WebUiConfig.getAutoLoginAccount();
if (autoLoginAccount) {
try {
const { result, message } = await WebUiDataRuntime.requestQuickLogin(autoLoginAccount);
if (!result) {
throw new Error(message);
}
console.log(`[NapCat] [WebUi] Auto login account: ${autoLoginAccount}`);
} catch (error) {
console.log(`[NapCat] [WebUi] Auto login account failed.` + error);
}
}
}, 30000);
// ------------注册中间件------------
// 使用express的json中间件
app.use(express.json());
@@ -112,7 +126,9 @@ export async function InitWebUi(logger: LogWrapper, pathWrapper: NapCatPathWrapp
`[NapCat] [WebUi] WebUi User Panel Url: ${createUrl(host, port.toString(), '/webui', searchParams)}`
);
}
logger.log(`[NapCat] [WebUi] WebUi Local Panel Url: ${createUrl('127.0.0.1', port.toString(), '/webui', searchParams)}`);
logger.log(
`[NapCat] [WebUi] WebUi Local Panel Url: ${createUrl('127.0.0.1', port.toString(), '/webui', searchParams)}`
);
});
// ------------Over------------
}

View File

@@ -7,6 +7,15 @@ import { WebUiDataRuntime } from '@webapi/helper/Data';
import { sendSuccess, sendError } from '@webapi/utils/response';
import { isEmpty } from '@webapi/utils/check';
// 检查是否使用默认Token
export const CheckDefaultTokenHandler: RequestHandler = async (_, res) => {
const webuiToken = await WebUiConfig.GetWebUIConfig();
if (webuiToken.token === 'napcat') {
return sendSuccess(res, true);
}
return sendSuccess(res, false);
};
// 登录
export const LoginHandler: RequestHandler = async (req, res) => {
// 获取WebUI配置
@@ -93,7 +102,7 @@ export const UpdateTokenHandler: RequestHandler = async (req, res) => {
try {
// 注销当前的Token
if (authorization) {
const CredentialBase64: string = authorization.split(' ')[1];
const CredentialBase64: string = authorization.split(' ')[1] as string;
const Credential = JSON.parse(Buffer.from(CredentialBase64, 'base64').toString());
AuthHelper.revokeCredential(Credential);
}

View File

@@ -3,7 +3,8 @@ import { sendError, sendSuccess } from '../utils/response';
import { WebUiConfigWrapper } from '../helper/config';
import { logSubscription } from '@/common/log';
import { terminalManager } from '../terminal/terminal_manager';
// 判断是否是 macos
const isMacOS = process.platform === 'darwin';
// 日志记录
export const LogHandler: RequestHandler = async (req, res) => {
const filename = req.query['id'];
@@ -43,6 +44,9 @@ export const LogRealTimeHandler: RequestHandler = async (req, res) => {
// 终端相关处理器
export const CreateTerminalHandler: RequestHandler = async (req, res) => {
if (isMacOS) {
return sendError(res, 'MacOS不支持终端');
}
try {
const { cols, rows } = req.body;
const { id } = terminalManager.createTerminal(cols, rows);

View File

@@ -13,6 +13,7 @@ const WebUiConfigSchema = Type.Object({
port: Type.Number({ default: 6099 }),
token: Type.String({ default: 'napcat' }),
loginRate: Type.Number({ default: 10 }),
autoLoginAccount: Type.String({ default: '' }),
});
export type WebUiConfigType = Static<typeof WebUiConfigSchema>;
@@ -125,4 +126,8 @@ export class WebUiConfigWrapper {
public static GetWebUIFontPath(): string {
return resolve(webUiPathWrapper.configPath, './fonts/webui.woff');
}
public getAutoLoginAccount(): string | undefined {
return this.WebUiConfigData?.autoLoginAccount;
}
}

View File

@@ -1,6 +1,12 @@
import { Router } from 'express';
import { checkHandler, LoginHandler, LogoutHandler, UpdateTokenHandler } from '@webapi/api/Auth';
import {
CheckDefaultTokenHandler,
checkHandler,
LoginHandler,
LogoutHandler,
UpdateTokenHandler,
} from '@webapi/api/Auth';
const router = Router();
// router:登录
@@ -11,5 +17,7 @@ router.post('/check', checkHandler);
router.post('/logout', LogoutHandler);
// router:更新token
router.post('/update_token', UpdateTokenHandler);
// router:检查默认token
router.get('/check_using_default_token', CheckDefaultTokenHandler);
export { router as AuthRouter };