diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8885153f..3151d7c7 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,9 +1,10 @@ module.exports = { 'env': { + 'browser': true, 'es2021': true, 'node': true }, - 'ignorePatterns': ['src/core/', 'src/core.lib/'], + 'ignorePatterns': ['src/core/', 'src/core.lib/','src/proto/'], 'extends': [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended' diff --git a/src/common/utils/ConfigBase.ts b/src/common/utils/ConfigBase.ts index 24415c6e..6ea6956b 100644 --- a/src/common/utils/ConfigBase.ts +++ b/src/common/utils/ConfigBase.ts @@ -1,8 +1,8 @@ import path from 'node:path'; import fs from 'node:fs'; import { log, logDebug, logError } from '@/common/utils/log'; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); diff --git a/src/common/utils/cpmodule.ts b/src/common/utils/cpmodule.ts index 744dcaa7..44574b07 100644 --- a/src/common/utils/cpmodule.ts +++ b/src/common/utils/cpmodule.ts @@ -1,8 +1,8 @@ import * as os from 'os'; import path from 'node:path'; import fs from 'fs'; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); @@ -19,6 +19,6 @@ export function cpModule(moduleName: string) { try { fs.copyFileSync(path.join(currentDir, fileName), path.join(currentDir, `${moduleName}.node`)); } catch (e) { - + console.error(e); } } diff --git a/src/common/utils/helper.ts b/src/common/utils/helper.ts index d87a3a4b..c09428b6 100644 --- a/src/common/utils/helper.ts +++ b/src/common/utils/helper.ts @@ -2,8 +2,8 @@ import crypto from 'node:crypto'; import path from 'node:path'; import fs from 'fs/promises'; import { log, logDebug } from './log'; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); @@ -153,12 +153,27 @@ export async function UpdateConfig() { const configFiles = await fs.readdir(path.join(__dirname, 'config')); for (const file of configFiles) { if (file.match(/^onebot11_\d+.json$/)) { - let CurrentConfig = JSON.parse(await fs.readFile(path.join(__dirname, 'config', file), 'utf8')); + const CurrentConfig = JSON.parse(await fs.readFile(path.join(__dirname, 'config', file), 'utf8')); if (isValidOldConfig(CurrentConfig)) { - log("正在迁移旧配置到新配置 File:", file); - let NewConfig = migrateConfig(CurrentConfig); + log('正在迁移旧配置到新配置 File:', file); + const NewConfig = migrateConfig(CurrentConfig); await fs.writeFile(path.join(__dirname, 'config', file), JSON.stringify(NewConfig, null, 2)); } } } +} +export function isEqual(obj1: any, obj2: any) { + if (obj1 === obj2) return true; + if (obj1 == null || obj2 == null) return false; + if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2; + + const keys1 = Object.keys(obj1); + const keys2 = Object.keys(obj2); + + if (keys1.length !== keys2.length) return false; + + for (const key of keys1) { + if (!isEqual(obj1[key], obj2[key])) return false; + } + return true; } \ No newline at end of file diff --git a/src/common/utils/log.ts b/src/common/utils/log.ts index 8408def4..99a5a8bb 100644 --- a/src/common/utils/log.ts +++ b/src/common/utils/log.ts @@ -2,8 +2,8 @@ import log4js, { Configuration } from 'log4js'; import { truncateString } from '@/common/utils/helper'; import path from 'node:path'; import { SelfInfo } from '@/core'; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); diff --git a/src/common/utils/reboot.ts b/src/common/utils/reboot.ts index db5a9258..5e9a7754 100644 --- a/src/common/utils/reboot.ts +++ b/src/common/utils/reboot.ts @@ -1,44 +1,44 @@ -import { resolve } from "node:path"; -import { spawn } from "node:child_process"; +import { resolve } from 'node:path'; +import { spawn } from 'node:child_process'; import { pid, ppid, exit } from 'node:process'; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); export async function rebootWithQuickLogin(uin: string) { - let batScript = resolve(__dirname, './napcat.bat'); - let batUtf8Script = resolve(__dirname, './napcat-utf8.bat'); - let bashScript = resolve(__dirname, './napcat.sh'); - if (process.platform === 'win32') { - const subProcess = spawn(`start ${batUtf8Script} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' }); - subProcess.unref(); - // 子父进程一起送走 有点效果 - spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' }); - spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' }); - } else if (process.platform === 'linux') { - const subProcess = spawn(`${bashScript} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' }); - //还没兼容 - subProcess.unref(); - exit(0); - } - //exit(0); + const batScript = resolve(__dirname, './napcat.bat'); + const batUtf8Script = resolve(__dirname, './napcat-utf8.bat'); + const bashScript = resolve(__dirname, './napcat.sh'); + if (process.platform === 'win32') { + const subProcess = spawn(`start ${batUtf8Script} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' }); + subProcess.unref(); + // 子父进程一起送走 有点效果 + spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' }); + spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' }); + } else if (process.platform === 'linux') { + const subProcess = spawn(`${bashScript} -q ${uin}`, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' }); + //还没兼容 + subProcess.unref(); + exit(0); + } + //exit(0); } export async function rebootWithNormolLogin() { - let batScript = resolve(__dirname, './napcat.bat'); - let batUtf8Script = resolve(__dirname, './napcat-utf8.bat'); - let bashScript = resolve(__dirname, './napcat.sh'); - if (process.platform === 'win32') { - const subProcess = spawn(`start ${batUtf8Script} `, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' }); - subProcess.unref(); - // 子父进程一起送走 有点效果 - spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' }); - spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' }); - } else if (process.platform === 'linux') { - const subProcess = spawn(`${bashScript}`, { detached: true, windowsHide: false, env: process.env, shell: true }); - subProcess.unref(); - exit(0); - } + const batScript = resolve(__dirname, './napcat.bat'); + const batUtf8Script = resolve(__dirname, './napcat-utf8.bat'); + const bashScript = resolve(__dirname, './napcat.sh'); + if (process.platform === 'win32') { + const subProcess = spawn(`start ${batUtf8Script} `, { detached: true, windowsHide: false, env: process.env, shell: true, stdio: 'ignore' }); + subProcess.unref(); + // 子父进程一起送走 有点效果 + spawn('cmd /c taskkill /t /f /pid ' + pid.toString(), { detached: true, shell: true, stdio: 'ignore' }); + spawn('cmd /c taskkill /t /f /pid ' + ppid.toString(), { detached: true, shell: true, stdio: 'ignore' }); + } else if (process.platform === 'linux') { + const subProcess = spawn(`${bashScript}`, { detached: true, windowsHide: false, env: process.env, shell: true }); + subProcess.unref(); + exit(0); + } } \ No newline at end of file diff --git a/src/common/utils/request.ts b/src/common/utils/request.ts index 8ae463d2..8cdebd8f 100644 --- a/src/common/utils/request.ts +++ b/src/common/utils/request.ts @@ -31,7 +31,7 @@ export class RequestUtil { // 请求和回复都是JSON data传原始内容 自动编码json static async HttpGetJson(url: string, method: string = 'GET', data?: any, headers: Record = {}, isJsonRet: boolean = true, isArgJson: boolean = true): Promise { - let option = new URL(url); + const option = new URL(url); const protocol = url.startsWith('https://') ? https : http; const options = { hostname: option.hostname, diff --git a/src/common/utils/type.ts b/src/common/utils/type.ts index bcc54a9b..058e7be4 100644 --- a/src/common/utils/type.ts +++ b/src/common/utils/type.ts @@ -2,30 +2,30 @@ * 运行时类型转换与检查类 */ export class TypeCheck { - static isEmpty(value: any): boolean { - return value === null || value === undefined || value === '' || + static isEmpty(value: any): boolean { + return value === null || value === undefined || value === '' || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0); - } + } } export class TypeConvert { - static toNumber(value: any): number { - const num = Number(value); - if (isNaN(num)) { - throw new Error(`无法将输入转换为数字: ${value}`); - } - return num; + static toNumber(value: any): number { + const num = Number(value); + if (isNaN(num)) { + throw new Error(`无法将输入转换为数字: ${value}`); } + return num; + } - static toString(value: any): string { - return String(value); - } + static toString(value: any): string { + return String(value); + } - static toBoolean(value: any): boolean { - return Boolean(value); - } + static toBoolean(value: any): boolean { + return Boolean(value); + } - static toArray(value: any): any[] { - return Array.isArray(value) ? value : [value]; - } + static toArray(value: any): any[] { + return Array.isArray(value) ? value : [value]; + } } \ No newline at end of file diff --git a/src/hook/frida_lood.ts b/src/hook/frida_lood.ts deleted file mode 100644 index 770e0e1f..00000000 --- a/src/hook/frida_lood.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as frida from 'frida'; -import { promises as fs } from 'fs'; -import path from 'node:path'; - -async function loadFridaScript(scriptPath: string): Promise { - try { - // Attach to the process - const currentPid = process.pid; - console.log('Attaching to process:', currentPid); - const targetProcess = await frida.attach(currentPid); - - // Read the script file - const scriptCode = await fs.readFile(scriptPath, { encoding: 'utf8' }); - - // Create the script in the target process - const script = await targetProcess.createScript(scriptCode); - - // Connect to script messages - script.message.connect((message, data) => { - if (message.type === 'send') { - console.log('[Script]:', message.payload); - } else if (message.type === 'error') { - console.error('[Script Error]:', message.stack); - } - }); - - // Load the script into the target process - await script.load(); - - console.log('Script loaded successfully and is now running.'); - } catch (error) { - console.error('Failed to load script:', error); - } -} - -export function hookInit() { -// Assuming the process name and script file path are correct - loadFridaScript(path.join(path.resolve(__dirname), 'frida_script.js')).catch(console.error); -} diff --git a/src/hook/frida_script.js b/src/hook/frida_script.js deleted file mode 100644 index 0dce7ecf..00000000 --- a/src/hook/frida_script.js +++ /dev/null @@ -1,24 +0,0 @@ -const moduleName = 'wrapper.node'; -const offset = 0x18152AFE0; // 静态地址偏移 - -// 查找模块基地址 -const baseAddress = Module.findBaseAddress(moduleName); -if (!baseAddress) { - throw new Error('Module not found.'); -} - -// 计算绝对地址 -const absoluteAddress = baseAddress.add(offset); - -// 设置拦截器 -Interceptor.attach(absoluteAddress, { - onEnter: function(args) { - console.log(`[+] Function at offset ${offset} in wrapper.node was called`); - console.log('Argument 0:', args[0].toInt32()); - }, - onLeave: function(retval) { - console.log('Return value:', retval.toInt32()); - // 可以在这里修改返回值 - retval.replace(42); - } -}); diff --git a/src/hook/test.cjs b/src/hook/test.cjs deleted file mode 100644 index eb57cf8c..00000000 --- a/src/hook/test.cjs +++ /dev/null @@ -1,23 +0,0 @@ -const frida = require('frida'); -const fs = require('fs'); -const path = require('path'); - -async function main() { - // 获取当前 Node.js 进程的 ID - const pid = process.pid; - const session = await frida.attach(pid); // 附加到当前进程 - - const scriptCode = fs.readFileSync(path.join(path.resolve(__dirname), 'frida_script.js'), 'utf-8'); - const script = await session.createScript(scriptCode); - - script.message.connect(message => { - console.log('Message from Frida:', message); - }); - - await script.load(); - console.log('Frida script has been loaded successfully.'); -} - -main().catch(err => { - console.error(err); -}); diff --git a/src/index.ts b/src/index.ts index 2f39f1e5..42178cc1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,8 +10,8 @@ import { NapCatOnebot11 } from '@/onebot11/main'; import { InitWebUi } from './webui/index'; import { WebUiDataRuntime } from './webui/src/helper/Data'; import { UpdateConfig } from './common/utils/helper'; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); @@ -46,7 +46,7 @@ checkVersion().then(async (remoteVersion: string) => { logError('[NapCat] 检测更新失败', e); }); // 不是很好待优化 -let NapCat_OneBot11 = new NapCatOnebot11(); +const NapCat_OneBot11 = new NapCatOnebot11(); WebUiDataRuntime.setOB11ConfigCall(NapCat_OneBot11.SetConfig); diff --git a/src/onebot11/action/BaseAction.ts b/src/onebot11/action/BaseAction.ts index 11000aa5..c108fdb7 100644 --- a/src/onebot11/action/BaseAction.ts +++ b/src/onebot11/action/BaseAction.ts @@ -20,11 +20,11 @@ class BaseAction { return { valid: false, message: errorMessages.join('\n') as string || '未知错误' - } + }; } return { valid: true - } + }; } public async handle(payload: PayloadType): Promise> { diff --git a/src/onebot11/action/extends/SetOnlineStatus.ts b/src/onebot11/action/extends/SetOnlineStatus.ts index 99248dbf..a9ed54db 100644 --- a/src/onebot11/action/extends/SetOnlineStatus.ts +++ b/src/onebot11/action/extends/SetOnlineStatus.ts @@ -5,7 +5,7 @@ import BaseAction from '../BaseAction'; import { ActionName, BaseCheckResult } from '../types'; import { NTQQUserApi } from '@/core/apis'; import { FromSchema, JSONSchema } from 'json-schema-to-ts'; -import Ajv from "ajv" +import Ajv from 'ajv'; // 设置在线状态 const SchemaData = { diff --git a/src/onebot11/action/extends/SetQQAvatar.ts b/src/onebot11/action/extends/SetQQAvatar.ts index 397a2528..ad0553fd 100644 --- a/src/onebot11/action/extends/SetQQAvatar.ts +++ b/src/onebot11/action/extends/SetQQAvatar.ts @@ -13,7 +13,7 @@ export default class SetAvatar extends BaseAction { actionName = ActionName.SetQQAvatar; // 用不着复杂检测 protected async check(payload: Payload): Promise { - if (!payload.file || typeof payload.file != "string") { + if (!payload.file || typeof payload.file != 'string') { return { valid: false, message: 'file字段不能为空或者类型错误', diff --git a/src/onebot11/action/go-cqhttp/DownloadFile.ts b/src/onebot11/action/go-cqhttp/DownloadFile.ts index 3276d0c6..e6916c27 100644 --- a/src/onebot11/action/go-cqhttp/DownloadFile.ts +++ b/src/onebot11/action/go-cqhttp/DownloadFile.ts @@ -17,9 +17,9 @@ const SchemaData = { base64: { type: 'string' }, name: { type: 'string' }, headers: { - type: ["string", "array"], + type: ['string', 'array'], items: { - type: "string" + type: 'string' } } }, diff --git a/src/onebot11/action/go-cqhttp/QuickAction.ts b/src/onebot11/action/go-cqhttp/QuickAction.ts index 094cee00..49d90988 100644 --- a/src/onebot11/action/go-cqhttp/QuickAction.ts +++ b/src/onebot11/action/go-cqhttp/QuickAction.ts @@ -1,6 +1,6 @@ import { log } from '@/common/utils/log'; -import BaseAction from '../BaseAction' -import { ActionName } from '../types' +import BaseAction from '../BaseAction'; +import { ActionName } from '../types'; import { QuickAction, QuickActionEvent, handleQuickOperation } from '@/onebot11/server/postOB11Event'; interface Payload{ @@ -9,9 +9,9 @@ interface Payload{ } export class GoCQHTTHandleQuickAction extends BaseAction{ - actionName = ActionName.GoCQHTTP_HandleQuickAction + actionName = ActionName.GoCQHTTP_HandleQuickAction; protected async _handle(payload: Payload): Promise { handleQuickOperation(payload.context, payload.operation).then().catch(log); - return null + return null; } } \ No newline at end of file diff --git a/src/onebot11/action/go-cqhttp/SendGroupNotice.ts b/src/onebot11/action/go-cqhttp/SendGroupNotice.ts index f9d10ee0..50621128 100644 --- a/src/onebot11/action/go-cqhttp/SendGroupNotice.ts +++ b/src/onebot11/action/go-cqhttp/SendGroupNotice.ts @@ -5,61 +5,57 @@ import { NTQQGroupApi, WebApi } from '@/core/apis'; import { unlink } from 'node:fs'; import { FromSchema, JSONSchema } from 'json-schema-to-ts'; const SchemaData = { - type: 'object', - properties: { - group_id: { type: 'number' }, - content: { type: 'string' }, - image: { type: 'string' }, - pinned: { type: 'number' }, - confirmRequired: { type: 'number' } - }, - required: ['group_id', 'content'] + type: 'object', + properties: { + group_id: { type: 'number' }, + content: { type: 'string' }, + image: { type: 'string' }, + pinned: { type: 'number' }, + confirmRequired: { type: 'number' } + }, + required: ['group_id', 'content'] } as const satisfies JSONSchema; type Payload = FromSchema; export class SendGroupNotice extends BaseAction { - actionName = ActionName.GoCQHTTP_SendGroupNotice; - protected async _handle(payload: Payload) { - let UploadImage: { id: string, width: number, height: number } | undefined = undefined; - if (payload.image) { - //公告图逻辑 - let Image_path, Image_errMsg, Image_IsLocal = false; - let Uri2LocalRet = (await uri2local(payload.image)); - Image_errMsg = Uri2LocalRet.errMsg; - Image_path = Uri2LocalRet.path; - Image_IsLocal = Uri2LocalRet.isLocal; - if (Image_errMsg) { - throw `群公告${payload.image}设置失败,image字段可能格式不正确`; - } - if (!Image_path) { - throw `群公告${payload.image}设置失败,获取资源失败`; - } - await checkFileReceived(Image_path, 5000); // 文件不存在QQ会崩溃,需要提前判断 - let ImageUploadResult = await NTQQGroupApi.uploadGroupBulletinPic(payload.group_id.toString(), Image_path); - if (ImageUploadResult.errCode != 0) { - throw `群公告${payload.image}设置失败,图片上传失败`; - } - if (!Image_IsLocal) { - unlink(Image_path, () => { }); - } - UploadImage = ImageUploadResult.picInfo; - } - let Notice_Pinned = 0; - let Notice_confirmRequired = 0; - if (!payload.pinned) { - Notice_Pinned = 0; - } - if (!payload.confirmRequired) { - Notice_confirmRequired = 0; - } - let PublishGroupBulletinResult = await NTQQGroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, Notice_Pinned, Notice_confirmRequired); - - if (PublishGroupBulletinResult.result! = 0) { - throw `设置群公告失败,错误信息:${PublishGroupBulletinResult.errMsg}`; - } - // 下面实现扬了 - //await WebApi.setGroupNotice(payload.group_id, payload.content) ; - return null; + actionName = ActionName.GoCQHTTP_SendGroupNotice; + protected async _handle(payload: Payload) { + let UploadImage: { id: string, width: number, height: number } | undefined = undefined; + if (payload.image) { + //公告图逻辑 + const { errMsg, path, isLocal } = (await uri2local(payload.image)); + if (errMsg) { + throw `群公告${payload.image}设置失败,image字段可能格式不正确`; + } + if (!path) { + throw `群公告${payload.image}设置失败,获取资源失败`; + } + await checkFileReceived(path, 5000); // 文件不存在QQ会崩溃,需要提前判断 + const ImageUploadResult = await NTQQGroupApi.uploadGroupBulletinPic(payload.group_id.toString(), path); + if (ImageUploadResult.errCode != 0) { + throw `群公告${payload.image}设置失败,图片上传失败`; + } + if (!isLocal) { + unlink(path, () => { }); + } + UploadImage = ImageUploadResult.picInfo; } + let Notice_Pinned = 0; + let Notice_confirmRequired = 0; + if (!payload.pinned) { + Notice_Pinned = 0; + } + if (!payload.confirmRequired) { + Notice_confirmRequired = 0; + } + const PublishGroupBulletinResult = await NTQQGroupApi.publishGroupBulletin(payload.group_id.toString(), payload.content, UploadImage, Notice_Pinned, Notice_confirmRequired); + + if (PublishGroupBulletinResult.result != 0) { + throw `设置群公告失败,错误信息:${PublishGroupBulletinResult.errMsg}`; + } + // 下面实现扬了 + //await WebApi.setGroupNotice(payload.group_id, payload.content) ; + return null; + } } diff --git a/src/onebot11/action/group/GetGroupSystemMsg.ts b/src/onebot11/action/group/GetGroupSystemMsg.ts index 50a0af9d..9984709c 100644 --- a/src/onebot11/action/group/GetGroupSystemMsg.ts +++ b/src/onebot11/action/group/GetGroupSystemMsg.ts @@ -18,8 +18,8 @@ export class GetGroupSystemMsg extends BaseAction { actionName = ActionName.GetGroupSystemMsg; protected async _handle(payload: void) { // 默认10条 该api未完整实现 包括响应数据规范化 类型规范化 - let SingleScreenNotifies = await NTQQGroupApi.getSingleScreenNotifies(10); - let retData: any = { InvitedRequest: [], join_requests: [] }; + const SingleScreenNotifies = await NTQQGroupApi.getSingleScreenNotifies(10); + const retData: any = { InvitedRequest: [], join_requests: [] }; for (const SSNotify of SingleScreenNotifies) { if (SSNotify.type == 1) { retData.InvitedRequest.push({ diff --git a/src/onebot11/action/msg/SendMsg/create-send-elements.ts b/src/onebot11/action/msg/SendMsg/create-send-elements.ts index 17fe8aa5..e138b1d2 100644 --- a/src/onebot11/action/msg/SendMsg/create-send-elements.ts +++ b/src/onebot11/action/msg/SendMsg/create-send-elements.ts @@ -104,7 +104,7 @@ const _handlers: { // File service [OB11MessageDataType.image]: async (sendMsg, context) => { - let PicEle = await SendMsgElementConstructor.pic( + const PicEle = await SendMsgElementConstructor.pic( (await handleOb11FileLikeMessage(sendMsg, context)).path, sendMsg.data.summary || '', sendMsg.data.subType || 0 diff --git a/src/onebot11/action/msg/SendMsg/index.ts b/src/onebot11/action/msg/SendMsg/index.ts index ed8ae849..c60149d5 100644 --- a/src/onebot11/action/msg/SendMsg/index.ts +++ b/src/onebot11/action/msg/SendMsg/index.ts @@ -51,16 +51,16 @@ export async function sendMsg(peer: Peer, sendElements: SendMessageElement[], de totalSize += fs.statSync(fileElement.videoElement.filePath).size; } if (fileElement.elementType === ElementType.PIC) { - totalSize += fs.statSync(fileElement.picElement.sourcePath).size + totalSize += fs.statSync(fileElement.picElement.sourcePath).size; } } //且 PredictTime ((totalSize / 1024 / 512) * 1000)不等于Nan - let PredictTime = totalSize / 1024 / 512 * 1000; + const PredictTime = totalSize / 1024 / 512 * 1000; if (!Number.isNaN(PredictTime)) { - timeout += PredictTime// 5S Basic Timeout + PredictTime( For File 512kb/s ) + timeout += PredictTime;// 5S Basic Timeout + PredictTime( For File 512kb/s ) } } catch (e) { - logError("发送消息计算预计时间异常", e); + logError('发送消息计算预计时间异常', e); } const returnMsg = await NTQQMsgApi.sendMsg(peer, sendElements, waitComplete, timeout); try { diff --git a/src/onebot11/action/system/Reboot.ts b/src/onebot11/action/system/Reboot.ts index 4d2cb34c..61d4001e 100644 --- a/src/onebot11/action/system/Reboot.ts +++ b/src/onebot11/action/system/Reboot.ts @@ -5,40 +5,40 @@ import { selfInfo } from '@/core/data'; import { FromSchema, JSONSchema } from 'json-schema-to-ts'; const SchemaData = { - type: 'object', - properties: { - delay: { type: 'number' } - }, - required: ['delay'] + type: 'object', + properties: { + delay: { type: 'number' } + }, + required: ['delay'] } as const satisfies JSONSchema; type Payload = FromSchema; export class Reboot extends BaseAction { - actionName = ActionName.Reboot; + actionName = ActionName.Reboot; - protected async _handle(payload: Payload): Promise { - if (payload.delay) { - setTimeout(() => { - rebootWithQuickLogin(selfInfo.uin); - }, payload.delay); - } else { - rebootWithQuickLogin(selfInfo.uin); - } - return null; + protected async _handle(payload: Payload): Promise { + if (payload.delay) { + setTimeout(() => { + rebootWithQuickLogin(selfInfo.uin); + }, payload.delay); + } else { + rebootWithQuickLogin(selfInfo.uin); } + return null; + } } export class RebootNormol extends BaseAction { - actionName = ActionName.RebootNormol; + actionName = ActionName.RebootNormol; - protected async _handle(payload: Payload): Promise { - if (payload.delay) { - setTimeout(() => { - rebootWithNormolLogin(); - }, payload.delay); - } else { - rebootWithNormolLogin(); - } - return null; + protected async _handle(payload: Payload): Promise { + if (payload.delay) { + setTimeout(() => { + rebootWithNormolLogin(); + }, payload.delay); + } else { + rebootWithNormolLogin(); } + return null; + } } diff --git a/src/onebot11/action/types.ts b/src/onebot11/action/types.ts index 3a3e574f..0b071a5e 100644 --- a/src/onebot11/action/types.ts +++ b/src/onebot11/action/types.ts @@ -60,7 +60,7 @@ export enum ActionName { CleanCache = 'clean_cache', GetCookies = 'get_cookies', // 以下为go-cqhttp api - GoCQHTTP_HandleQuickAction = ".handle_quick_operation", + GoCQHTTP_HandleQuickAction = '.handle_quick_operation', GetGroupHonorInfo = 'get_group_honor_info', GoCQHTTP_GetEssenceMsg = 'get_essence_msg_list', GoCQHTTP_SendGroupNotice = '_send_group_notice', @@ -78,5 +78,5 @@ export enum ActionName { GoCQHTTP_GetGroupMsgHistory = 'get_group_msg_history', GoCQHTTP_GetForwardMsg = 'get_forward_msg', GetFriendMsgHistory = 'get_friend_msg_history', - GetGroupSystemMsg = "get_group_system_msg" + GetGroupSystemMsg = 'get_group_system_msg' } diff --git a/src/onebot11/config.ts b/src/onebot11/config.ts index d1137558..01ad1de8 100644 --- a/src/onebot11/config.ts +++ b/src/onebot11/config.ts @@ -1,9 +1,9 @@ -import fs from "node:fs"; -import path from "node:path"; -import { selfInfo } from "@/core/data"; -import { logDebug, logError } from "@/common/utils/log"; -import { ConfigBase } from "@/common/utils/ConfigBase"; -import { json } from "stream/consumers"; +import fs from 'node:fs'; +import path from 'node:path'; +import { selfInfo } from '@/core/data'; +import { logDebug, logError } from '@/common/utils/log'; +import { ConfigBase } from '@/common/utils/ConfigBase'; +import { json } from 'stream/consumers'; export interface OB11Config { http: { @@ -27,7 +27,7 @@ export interface OB11Config { debug: boolean; heartInterval: number; - messagePostFormat: "array" | "string"; + messagePostFormat: 'array' | 'string'; enableLocalFile2Url: boolean; musicSignUrl: string; reportSelfMessage: boolean; @@ -41,16 +41,16 @@ export interface OB11Config { class Config extends ConfigBase implements OB11Config { http = { enable: false, - host: "", + host: '', port: 3000, - secret: "", + secret: '', enableHeart: false, enablePost: false, postUrls: [], }; ws = { enable: false, - host: "", + host: '', port: 3001, }; reverseWs = { @@ -59,11 +59,11 @@ class Config extends ConfigBase implements OB11Config { }; debug = false; heartInterval = 30000; - messagePostFormat: "array" | "string" = "array"; + messagePostFormat: 'array' | 'string' = 'array'; enableLocalFile2Url = true; - musicSignUrl = ""; + musicSignUrl = ''; reportSelfMessage = false; - token = ""; + token = ''; getConfigPath() { return path.join(this.getConfigDir(), `onebot11_${selfInfo.uin}.json`); diff --git a/src/onebot11/main.ts b/src/onebot11/main.ts index 86ce569c..1ec8b7fe 100644 --- a/src/onebot11/main.ts +++ b/src/onebot11/main.ts @@ -31,10 +31,11 @@ import { OB11GroupRecallNoticeEvent } from '@/onebot11/event/notice/OB11GroupRec import { logMessage, logNotice, logRequest } from '@/onebot11/log'; import { OB11Message } from '@/onebot11/types'; import { OB11LifeCycleEvent } from './event/meta/OB11LifeCycleEvent'; -import { Data as SysData } from '@/proto/SysMessage' +import { Data as SysData } from '@/proto/SysMessage'; import { OB11FriendPokeEvent, OB11GroupPokeEvent } from './event/notice/OB11PokeEvent'; +import { isEqual } from '@/common/utils/helper'; //peer->cached(boolen) -let PokeCache = new Map(); +const PokeCache = new Map(); export class NapCatOnebot11 { private bootTime: number = Date.now() / 1000; // 秒 @@ -92,12 +93,12 @@ export class NapCatOnebot11 { // } // }; try { - let sysMsg = SysData.fromBinary(Buffer.from(protobufData)); - let peeruin = sysMsg.header[0].groupNumber; - let peeruid = sysMsg.header[0].groupString; - let MsgType = sysMsg.body[0].msgType; - let subType0 = sysMsg.body[0].subType0; - let subType1 = sysMsg.body[0].subType1; + const sysMsg = SysData.fromBinary(Buffer.from(protobufData)); + const peeruin = sysMsg.header[0].groupNumber; + const peeruid = sysMsg.header[0].groupString; + const MsgType = sysMsg.body[0].msgType; + const subType0 = sysMsg.body[0].subType0; + const subType1 = sysMsg.body[0].subType1; let pokeEvent: OB11FriendPokeEvent | OB11GroupPokeEvent; //console.log(peeruid); if (MsgType == 528 && subType0 == 290) { @@ -106,7 +107,7 @@ export class NapCatOnebot11 { PokeCache.delete(peeruid); } else { PokeCache.set(peeruid, false); - log("[私聊] 用户 ", peeruin, " 对你戳一戳"); + log('[私聊] 用户 ', peeruin, ' 对你戳一戳'); pokeEvent = new OB11FriendPokeEvent(peeruin); postOB11Event(pokeEvent); } @@ -117,13 +118,13 @@ export class NapCatOnebot11 { PokeCache.delete(peeruid); } else { PokeCache.set(peeruid, false); - log("[群聊] 群组 ", peeruin, " 戳一戳"); + log('[群聊] 群组 ', peeruin, ' 戳一戳'); pokeEvent = new OB11GroupPokeEvent(peeruin); postOB11Event(pokeEvent); } } } catch (e) { - log("解析SysMsg异常", e); + log('解析SysMsg异常', e); // console.log(e); // } @@ -184,15 +185,15 @@ export class NapCatOnebot11 { }; groupListener.onMemberInfoChange = async (groupCode: string, changeType: number, members: Map) => { // 如果自身是非管理员也许要从这里获取Delete 成员变动 待测试与验证 - let role = (await getGroupMember(groupCode, selfInfo.uin))?.role; - let isPrivilege = role === 3 || role === 4; + const role = (await getGroupMember(groupCode, selfInfo.uin))?.role; + const isPrivilege = role === 3 || role === 4; for (const member of members.values()) { if (member?.isDelete && !isPrivilege) { const groupDecreaseEvent = new OB11GroupDecreaseEvent(parseInt(groupCode), parseInt(member.uin), 0, 'leave');// 不知道怎么出去的 postOB11Event(groupDecreaseEvent, true); } } - } + }; groupListener.onJoinGroupNotify = (...notify) => { // console.log('ob11 onJoinGroupNotify', notify); }; @@ -253,21 +254,6 @@ export class NapCatOnebot11 { } async SetConfig(NewOb11: OB11Config) { try { - function isEqual(obj1: any, obj2: any) { - if (obj1 === obj2) return true; - if (obj1 == null || obj2 == null) return false; - if (typeof obj1 !== 'object' || typeof obj2 !== 'object') return obj1 === obj2; - - const keys1 = Object.keys(obj1); - const keys2 = Object.keys(obj2); - - if (keys1.length !== keys2.length) return false; - - for (let key of keys1) { - if (!isEqual(obj1[key], obj2[key])) return false; - } - return true; - } // if (!NewOb11 || typeof NewOb11 !== 'object') { // throw new Error('Invalid configuration object'); // } diff --git a/src/onebot11/server/postOB11Event.ts b/src/onebot11/server/postOB11Event.ts index 6f82ee25..365a4af4 100644 --- a/src/onebot11/server/postOB11Event.ts +++ b/src/onebot11/server/postOB11Event.ts @@ -170,26 +170,26 @@ async function handleGroupRequest(request: OB11GroupRequestEvent, quickAction: Q groupNotifies[request.flag], quickAction.approve ? GroupRequestOperateTypes.approve : GroupRequestOperateTypes.reject, quickAction.reason, - ).then().catch(logError) + ).then().catch(logError); } } async function handleFriendRequest(request: OB11FriendRequestEvent, quickAction: QuickActionFriendRequest) { if (!isNull(quickAction.approve)) { - NTQQFriendApi.handleFriendRequest(friendRequests[request.flag], !!quickAction.approve).then().catch(logError) + NTQQFriendApi.handleFriendRequest(friendRequests[request.flag], !!quickAction.approve).then().catch(logError); } } export async function handleQuickOperation(context: QuickActionEvent, quickAction: QuickAction) { if (context.post_type === 'message') { - handleMsg(context as OB11Message, quickAction).then().catch(logError) + handleMsg(context as OB11Message, quickAction).then().catch(logError); } if (context.post_type === 'request') { const friendRequest = context as OB11FriendRequestEvent; const groupRequest = context as OB11GroupRequestEvent; if ((friendRequest).request_type === 'friend') { - handleFriendRequest(friendRequest, quickAction).then().catch(logError) + handleFriendRequest(friendRequest, quickAction).then().catch(logError); } else if (groupRequest.request_type === 'group') { - handleGroupRequest(groupRequest, quickAction).then().catch(logError) + handleGroupRequest(groupRequest, quickAction).then().catch(logError); } } } \ No newline at end of file diff --git a/src/proto/SysMessage.ts b/src/proto/SysMessage.ts index 0a592b3e..34933a00 100644 --- a/src/proto/SysMessage.ts +++ b/src/proto/SysMessage.ts @@ -1,15 +1,15 @@ // @generated by protobuf-ts 2.9.4 // @generated from protobuf file "SysMessage.proto" (package "SysMessage", syntax proto3) // tslint:disable -import type { BinaryWriteOptions } from "@protobuf-ts/runtime"; -import type { IBinaryWriter } from "@protobuf-ts/runtime"; -import { WireType } from "@protobuf-ts/runtime"; -import type { BinaryReadOptions } from "@protobuf-ts/runtime"; -import type { IBinaryReader } from "@protobuf-ts/runtime"; -import { UnknownFieldHandler } from "@protobuf-ts/runtime"; -import type { PartialMessage } from "@protobuf-ts/runtime"; -import { reflectionMergePartial } from "@protobuf-ts/runtime"; -import { MessageType } from "@protobuf-ts/runtime"; +import type { BinaryWriteOptions } from '@protobuf-ts/runtime'; +import type { IBinaryWriter } from '@protobuf-ts/runtime'; +import { WireType } from '@protobuf-ts/runtime'; +import type { BinaryReadOptions } from '@protobuf-ts/runtime'; +import type { IBinaryReader } from '@protobuf-ts/runtime'; +import { UnknownFieldHandler } from '@protobuf-ts/runtime'; +import type { PartialMessage } from '@protobuf-ts/runtime'; +import { reflectionMergePartial } from '@protobuf-ts/runtime'; +import { MessageType } from '@protobuf-ts/runtime'; /** * @generated from protobuf message SysMessage.Data */ @@ -79,54 +79,54 @@ export interface Body { } // @generated message type with reflection information, may provide speed optimized methods class Data$Type extends MessageType { - constructor() { - super("SysMessage.Data", [ - { no: 1, name: "header", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => Header }, - { no: 2, name: "body", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => Body } - ]); - } - create(value?: PartialMessage): Data { - const message = globalThis.Object.create((this.messagePrototype!)); - message.header = []; - message.body = []; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Data): Data { - let message = target ?? this.create(), end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* repeated SysMessage.Header header */ 1: - message.header.push(Header.internalBinaryRead(reader, reader.uint32(), options)); - break; - case /* repeated SysMessage.Body body */ 2: - message.body.push(Body.internalBinaryRead(reader, reader.uint32(), options)); - break; - default: - let u = options.readUnknownField; - if (u === "throw") - throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); - } - } - return message; - } - internalBinaryWrite(message: Data, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { - /* repeated SysMessage.Header header = 1; */ - for (let i = 0; i < message.header.length; i++) - Header.internalBinaryWrite(message.header[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join(); - /* repeated SysMessage.Body body = 2; */ - for (let i = 0; i < message.body.length; i++) - Body.internalBinaryWrite(message.body[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); - let u = options.writeUnknownFields; + constructor() { + super('SysMessage.Data', [ + { no: 1, name: 'header', kind: 'message', repeat: 1 /*RepeatType.PACKED*/, T: () => Header }, + { no: 2, name: 'body', kind: 'message', repeat: 1 /*RepeatType.PACKED*/, T: () => Body } + ]); + } + create(value?: PartialMessage): Data { + const message = globalThis.Object.create((this.messagePrototype!)); + message.header = []; + message.body = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Data): Data { + const message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + const [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated SysMessage.Header header */ 1: + message.header.push(Header.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* repeated SysMessage.Body body */ 2: + message.body.push(Body.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + const u = options.readUnknownField; + if (u === 'throw') + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + const d = reader.skip(wireType); if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); - return writer; + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } } + return message; + } + internalBinaryWrite(message: Data, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated SysMessage.Header header = 1; */ + for (let i = 0; i < message.header.length; i++) + Header.internalBinaryWrite(message.header[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* repeated SysMessage.Body body = 2; */ + for (let i = 0; i < message.body.length; i++) + Body.internalBinaryWrite(message.body[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + const u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } } /** * @generated MessageType for protobuf message SysMessage.Data @@ -134,69 +134,69 @@ class Data$Type extends MessageType { export const Data = new Data$Type(); // @generated message type with reflection information, may provide speed optimized methods class Header$Type extends MessageType
{ - constructor() { - super("SysMessage.Header", [ - { no: 1, name: "GroupNumber", kind: "scalar", jsonName: "GroupNumber", T: 13 /*ScalarType.UINT32*/ }, - { no: 2, name: "GroupString", kind: "scalar", jsonName: "GroupString", T: 9 /*ScalarType.STRING*/ }, - { no: 5, name: "QQ", kind: "scalar", jsonName: "QQ", T: 13 /*ScalarType.UINT32*/ }, - { no: 6, name: "Uid", kind: "scalar", jsonName: "Uid", opt: true, T: 9 /*ScalarType.STRING*/ } - ]); - } - create(value?: PartialMessage
): Header { - const message = globalThis.Object.create((this.messagePrototype!)); - message.groupNumber = 0; - message.groupString = ""; - message.qQ = 0; - if (value !== undefined) - reflectionMergePartial
(this, message, value); - return message; - } - internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Header): Header { - let message = target ?? this.create(), end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* uint32 GroupNumber = 1 [json_name = "GroupNumber"];*/ 1: - message.groupNumber = reader.uint32(); - break; - case /* string GroupString = 2 [json_name = "GroupString"];*/ 2: - message.groupString = reader.string(); - break; - case /* uint32 QQ = 5 [json_name = "QQ"];*/ 5: - message.qQ = reader.uint32(); - break; - case /* optional string Uid = 6 [json_name = "Uid"];*/ 6: - message.uid = reader.string(); - break; - default: - let u = options.readUnknownField; - if (u === "throw") - throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); - } - } - return message; - } - internalBinaryWrite(message: Header, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { - /* uint32 GroupNumber = 1 [json_name = "GroupNumber"]; */ - if (message.groupNumber !== 0) - writer.tag(1, WireType.Varint).uint32(message.groupNumber); - /* string GroupString = 2 [json_name = "GroupString"]; */ - if (message.groupString !== "") - writer.tag(2, WireType.LengthDelimited).string(message.groupString); - /* uint32 QQ = 5 [json_name = "QQ"]; */ - if (message.qQ !== 0) - writer.tag(5, WireType.Varint).uint32(message.qQ); - /* optional string Uid = 6 [json_name = "Uid"]; */ - if (message.uid !== undefined) - writer.tag(6, WireType.LengthDelimited).string(message.uid); - let u = options.writeUnknownFields; + constructor() { + super('SysMessage.Header', [ + { no: 1, name: 'GroupNumber', kind: 'scalar', jsonName: 'GroupNumber', T: 13 /*ScalarType.UINT32*/ }, + { no: 2, name: 'GroupString', kind: 'scalar', jsonName: 'GroupString', T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: 'QQ', kind: 'scalar', jsonName: 'QQ', T: 13 /*ScalarType.UINT32*/ }, + { no: 6, name: 'Uid', kind: 'scalar', jsonName: 'Uid', opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage
): Header { + const message = globalThis.Object.create((this.messagePrototype!)); + message.groupNumber = 0; + message.groupString = ''; + message.qQ = 0; + if (value !== undefined) + reflectionMergePartial
(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Header): Header { + const message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + const [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint32 GroupNumber = 1 [json_name = "GroupNumber"];*/ 1: + message.groupNumber = reader.uint32(); + break; + case /* string GroupString = 2 [json_name = "GroupString"];*/ 2: + message.groupString = reader.string(); + break; + case /* uint32 QQ = 5 [json_name = "QQ"];*/ 5: + message.qQ = reader.uint32(); + break; + case /* optional string Uid = 6 [json_name = "Uid"];*/ 6: + message.uid = reader.string(); + break; + default: + const u = options.readUnknownField; + if (u === 'throw') + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + const d = reader.skip(wireType); if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); - return writer; + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } } + return message; + } + internalBinaryWrite(message: Header, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint32 GroupNumber = 1 [json_name = "GroupNumber"]; */ + if (message.groupNumber !== 0) + writer.tag(1, WireType.Varint).uint32(message.groupNumber); + /* string GroupString = 2 [json_name = "GroupString"]; */ + if (message.groupString !== '') + writer.tag(2, WireType.LengthDelimited).string(message.groupString); + /* uint32 QQ = 5 [json_name = "QQ"]; */ + if (message.qQ !== 0) + writer.tag(5, WireType.Varint).uint32(message.qQ); + /* optional string Uid = 6 [json_name = "Uid"]; */ + if (message.uid !== undefined) + writer.tag(6, WireType.LengthDelimited).string(message.uid); + const u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } } /** * @generated MessageType for protobuf message SysMessage.Header @@ -204,94 +204,94 @@ class Header$Type extends MessageType
{ export const Header = new Header$Type(); // @generated message type with reflection information, may provide speed optimized methods class Body$Type extends MessageType { - constructor() { - super("SysMessage.Body", [ - { no: 1, name: "MsgType", kind: "scalar", jsonName: "MsgType", T: 13 /*ScalarType.UINT32*/ }, - { no: 2, name: "SubType_0", kind: "scalar", jsonName: "SubType0", T: 13 /*ScalarType.UINT32*/ }, - { no: 3, name: "SubType_1", kind: "scalar", jsonName: "SubType1", T: 13 /*ScalarType.UINT32*/ }, - { no: 5, name: "MsgSeq", kind: "scalar", jsonName: "MsgSeq", T: 13 /*ScalarType.UINT32*/ }, - { no: 6, name: "Time", kind: "scalar", jsonName: "Time", T: 13 /*ScalarType.UINT32*/ }, - { no: 12, name: "MsgID", kind: "scalar", jsonName: "MsgID", T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, - { no: 13, name: "Other", kind: "scalar", jsonName: "Other", T: 13 /*ScalarType.UINT32*/ } - ]); - } - create(value?: PartialMessage): Body { - const message = globalThis.Object.create((this.messagePrototype!)); - message.msgType = 0; - message.subType0 = 0; - message.subType1 = 0; - message.msgSeq = 0; - message.time = 0; - message.msgID = 0n; - message.other = 0; - if (value !== undefined) - reflectionMergePartial(this, message, value); - return message; - } - internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Body): Body { - let message = target ?? this.create(), end = reader.pos + length; - while (reader.pos < end) { - let [fieldNo, wireType] = reader.tag(); - switch (fieldNo) { - case /* uint32 MsgType = 1 [json_name = "MsgType"];*/ 1: - message.msgType = reader.uint32(); - break; - case /* uint32 SubType_0 = 2 [json_name = "SubType0"];*/ 2: - message.subType0 = reader.uint32(); - break; - case /* uint32 SubType_1 = 3 [json_name = "SubType1"];*/ 3: - message.subType1 = reader.uint32(); - break; - case /* uint32 MsgSeq = 5 [json_name = "MsgSeq"];*/ 5: - message.msgSeq = reader.uint32(); - break; - case /* uint32 Time = 6 [json_name = "Time"];*/ 6: - message.time = reader.uint32(); - break; - case /* uint64 MsgID = 12 [json_name = "MsgID"];*/ 12: - message.msgID = reader.uint64().toBigInt(); - break; - case /* uint32 Other = 13 [json_name = "Other"];*/ 13: - message.other = reader.uint32(); - break; - default: - let u = options.readUnknownField; - if (u === "throw") - throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); - let d = reader.skip(wireType); - if (u !== false) - (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); - } - } - return message; - } - internalBinaryWrite(message: Body, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { - /* uint32 MsgType = 1 [json_name = "MsgType"]; */ - if (message.msgType !== 0) - writer.tag(1, WireType.Varint).uint32(message.msgType); - /* uint32 SubType_0 = 2 [json_name = "SubType0"]; */ - if (message.subType0 !== 0) - writer.tag(2, WireType.Varint).uint32(message.subType0); - /* uint32 SubType_1 = 3 [json_name = "SubType1"]; */ - if (message.subType1 !== 0) - writer.tag(3, WireType.Varint).uint32(message.subType1); - /* uint32 MsgSeq = 5 [json_name = "MsgSeq"]; */ - if (message.msgSeq !== 0) - writer.tag(5, WireType.Varint).uint32(message.msgSeq); - /* uint32 Time = 6 [json_name = "Time"]; */ - if (message.time !== 0) - writer.tag(6, WireType.Varint).uint32(message.time); - /* uint64 MsgID = 12 [json_name = "MsgID"]; */ - if (message.msgID !== 0n) - writer.tag(12, WireType.Varint).uint64(message.msgID); - /* uint32 Other = 13 [json_name = "Other"]; */ - if (message.other !== 0) - writer.tag(13, WireType.Varint).uint32(message.other); - let u = options.writeUnknownFields; + constructor() { + super('SysMessage.Body', [ + { no: 1, name: 'MsgType', kind: 'scalar', jsonName: 'MsgType', T: 13 /*ScalarType.UINT32*/ }, + { no: 2, name: 'SubType_0', kind: 'scalar', jsonName: 'SubType0', T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: 'SubType_1', kind: 'scalar', jsonName: 'SubType1', T: 13 /*ScalarType.UINT32*/ }, + { no: 5, name: 'MsgSeq', kind: 'scalar', jsonName: 'MsgSeq', T: 13 /*ScalarType.UINT32*/ }, + { no: 6, name: 'Time', kind: 'scalar', jsonName: 'Time', T: 13 /*ScalarType.UINT32*/ }, + { no: 12, name: 'MsgID', kind: 'scalar', jsonName: 'MsgID', T: 4 /*ScalarType.UINT64*/, L: 0 /*LongType.BIGINT*/ }, + { no: 13, name: 'Other', kind: 'scalar', jsonName: 'Other', T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): Body { + const message = globalThis.Object.create((this.messagePrototype!)); + message.msgType = 0; + message.subType0 = 0; + message.subType1 = 0; + message.msgSeq = 0; + message.time = 0; + message.msgID = 0n; + message.other = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Body): Body { + const message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + const [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint32 MsgType = 1 [json_name = "MsgType"];*/ 1: + message.msgType = reader.uint32(); + break; + case /* uint32 SubType_0 = 2 [json_name = "SubType0"];*/ 2: + message.subType0 = reader.uint32(); + break; + case /* uint32 SubType_1 = 3 [json_name = "SubType1"];*/ 3: + message.subType1 = reader.uint32(); + break; + case /* uint32 MsgSeq = 5 [json_name = "MsgSeq"];*/ 5: + message.msgSeq = reader.uint32(); + break; + case /* uint32 Time = 6 [json_name = "Time"];*/ 6: + message.time = reader.uint32(); + break; + case /* uint64 MsgID = 12 [json_name = "MsgID"];*/ 12: + message.msgID = reader.uint64().toBigInt(); + break; + case /* uint32 Other = 13 [json_name = "Other"];*/ 13: + message.other = reader.uint32(); + break; + default: + const u = options.readUnknownField; + if (u === 'throw') + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + const d = reader.skip(wireType); if (u !== false) - (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); - return writer; + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } } + return message; + } + internalBinaryWrite(message: Body, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint32 MsgType = 1 [json_name = "MsgType"]; */ + if (message.msgType !== 0) + writer.tag(1, WireType.Varint).uint32(message.msgType); + /* uint32 SubType_0 = 2 [json_name = "SubType0"]; */ + if (message.subType0 !== 0) + writer.tag(2, WireType.Varint).uint32(message.subType0); + /* uint32 SubType_1 = 3 [json_name = "SubType1"]; */ + if (message.subType1 !== 0) + writer.tag(3, WireType.Varint).uint32(message.subType1); + /* uint32 MsgSeq = 5 [json_name = "MsgSeq"]; */ + if (message.msgSeq !== 0) + writer.tag(5, WireType.Varint).uint32(message.msgSeq); + /* uint32 Time = 6 [json_name = "Time"]; */ + if (message.time !== 0) + writer.tag(6, WireType.Varint).uint32(message.time); + /* uint64 MsgID = 12 [json_name = "MsgID"]; */ + if (message.msgID !== 0n) + writer.tag(12, WireType.Varint).uint64(message.msgID); + /* uint32 Other = 13 [json_name = "Other"]; */ + if (message.other !== 0) + writer.tag(13, WireType.Varint).uint32(message.other); + const u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } } /** * @generated MessageType for protobuf message SysMessage.Body diff --git a/src/webui/index.ts b/src/webui/index.ts index 9264c890..00154f7a 100644 --- a/src/webui/index.ts +++ b/src/webui/index.ts @@ -5,8 +5,8 @@ import { resolve } from 'node:path'; import { ALLRouter } from './src/router'; import { WebUiConfig } from './src/helper/config'; const app = express(); -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); @@ -19,21 +19,21 @@ const __dirname = dirname(__filename); * @returns {Promise} 无返回值。 */ export async function InitWebUi() { - let config = await WebUiConfig.GetWebUIConfig(); - app.use(express.json()); - // 初始服务 - app.all('/', (_req, res) => { - res.json({ - msg: 'NapCat WebAPI is now running!', - }); + const config = await WebUiConfig.GetWebUIConfig(); + app.use(express.json()); + // 初始服务 + app.all('/', (_req, res) => { + res.json({ + msg: 'NapCat WebAPI is now running!', }); - // 配置静态文件服务,提供./static目录下的文件服务,访问路径为/webui - app.use('/webui', express.static(resolve(__dirname, './static'))); - //挂载API接口 - app.use('/api', ALLRouter); - app.listen(config.port, async () => { - console.log(`[NapCat] [WebUi] Current WebUi is running at IP:${config.port}`); - console.log(`[NapCat] [WebUi] Login Token is ${config.token}`); - }) + }); + // 配置静态文件服务,提供./static目录下的文件服务,访问路径为/webui + app.use('/webui', express.static(resolve(__dirname, './static'))); + //挂载API接口 + app.use('/api', ALLRouter); + app.listen(config.port, async () => { + console.log(`[NapCat] [WebUi] Current WebUi is running at IP:${config.port}`); + console.log(`[NapCat] [WebUi] Login Token is ${config.token}`); + }); } \ No newline at end of file diff --git a/src/webui/src/api/Auth.ts b/src/webui/src/api/Auth.ts index 49a9e04d..7f8e9d8c 100644 --- a/src/webui/src/api/Auth.ts +++ b/src/webui/src/api/Auth.ts @@ -1,68 +1,68 @@ -import { RequestHandler } from "express"; -import { AuthHelper } from "../helper/SignToken"; -import { WebUiConfig } from "../helper/config"; -import { WebUiDataRuntime } from "../helper/Data"; +import { RequestHandler } from 'express'; +import { AuthHelper } from '../helper/SignToken'; +import { WebUiConfig } from '../helper/config'; +import { WebUiDataRuntime } from '../helper/Data'; const isEmpty = (data: any) => data === undefined || data === null || data === ''; export const LoginHandler: RequestHandler = async (req, res) => { - let WebUiConfigData = await WebUiConfig.GetWebUIConfig(); - const { token } = req.body; - if (isEmpty(token)) { - res.json({ - code: -1, - message: 'token is empty' - }); - return; - } - if (!await WebUiDataRuntime.checkLoginRate(WebUiConfigData.loginRate)) { - res.json({ - code: -1, - message: 'login rate limit' - }); - return; - } - //验证config.token是否等于token - if (WebUiConfigData.token !== token) { - res.json({ - code: -1, - message: 'token is invalid' - }); - return; - } - let signCredential = Buffer.from(JSON.stringify(await AuthHelper.signCredential(WebUiConfigData.token))).toString('base64'); + const WebUiConfigData = await WebUiConfig.GetWebUIConfig(); + const { token } = req.body; + if (isEmpty(token)) { res.json({ - code: 0, - message: 'success', - data: { - "Credential": signCredential - } + code: -1, + message: 'token is empty' }); return; + } + if (!await WebUiDataRuntime.checkLoginRate(WebUiConfigData.loginRate)) { + res.json({ + code: -1, + message: 'login rate limit' + }); + return; + } + //验证config.token是否等于token + if (WebUiConfigData.token !== token) { + res.json({ + code: -1, + message: 'token is invalid' + }); + return; + } + const signCredential = Buffer.from(JSON.stringify(await AuthHelper.signCredential(WebUiConfigData.token))).toString('base64'); + res.json({ + code: 0, + message: 'success', + data: { + 'Credential': signCredential + } + }); + return; }; export const LogoutHandler: RequestHandler = (req, res) => { - // 这玩意无状态销毁个灯 得想想办法 - res.json({ - code: 0, - message: 'success' - }); - return; + // 这玩意无状态销毁个灯 得想想办法 + res.json({ + code: 0, + message: 'success' + }); + return; }; export const checkHandler: RequestHandler = async (req, res) => { - let WebUiConfigData = await WebUiConfig.GetWebUIConfig(); - const authorization = req.headers.authorization; - try { - let CredentialBase64:string = authorization?.split(' ')[1] as string; - let Credential = JSON.parse(Buffer.from(CredentialBase64, 'base64').toString()); - await AuthHelper.validateCredentialWithinOneHour(WebUiConfigData.token,Credential) - res.json({ - code: 0, - message: 'success' - }); - return; - } catch (e) { - res.json({ - code: -1, - message: 'failed' - }); - } + const WebUiConfigData = await WebUiConfig.GetWebUIConfig(); + const authorization = req.headers.authorization; + try { + const CredentialBase64:string = authorization?.split(' ')[1] as string; + const Credential = JSON.parse(Buffer.from(CredentialBase64, 'base64').toString()); + await AuthHelper.validateCredentialWithinOneHour(WebUiConfigData.token,Credential); + res.json({ + code: 0, + message: 'success' + }); return; + } catch (e) { + res.json({ + code: -1, + message: 'failed' + }); + } + return; }; diff --git a/src/webui/src/api/LogConsole.ts b/src/webui/src/api/LogConsole.ts index 423b111c..68eec759 100644 --- a/src/webui/src/api/LogConsole.ts +++ b/src/webui/src/api/LogConsole.ts @@ -1,54 +1,54 @@ -import { RequestHandler } from "express"; -import { resolve } from "path"; -import { readdir, stat } from "fs/promises"; -import { existsSync } from "fs"; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { RequestHandler } from 'express'; +import { resolve } from 'path'; +import { readdir, stat } from 'fs/promises'; +import { existsSync } from 'fs'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); export const GetLogFileListHandler: RequestHandler = async (req, res) => { - try { - let LogsPath = resolve(__dirname, "./logs/"); - let LogFiles = await readdir(LogsPath); - res.json({ - code: 0, - data: LogFiles - }); - } catch (error) { - res.json({ code: -1, msg: "Failed to retrieve log file list." }); - } + try { + const LogsPath = resolve(__dirname, './logs/'); + const LogFiles = await readdir(LogsPath); + res.json({ + code: 0, + data: LogFiles + }); + } catch (error) { + res.json({ code: -1, msg: 'Failed to retrieve log file list.' }); + } }; export const GetLogFileHandler: RequestHandler = async (req, res) => { - let LogsPath = resolve(__dirname, "./logs/"); - let LogFile = req.query.file as string; + const LogsPath = resolve(__dirname, './logs/'); + const LogFile = req.query.file as string; - if (!isValidFileName(LogFile)) { - res.json({ code: -1, msg: "LogFile is not safe" }); - return; + // if (!isValidFileName(LogFile)) { + // res.json({ code: -1, msg: 'LogFile is not safe' }); + // return; + // } + + const filePath = `${LogsPath}/${LogFile}`; + if (!existsSync(filePath)) { + res.status(404).json({ code: -1, msg: 'LogFile does not exist' }); + return; + } + + try { + const fileStats = await stat(filePath); + if (!fileStats.isFile()) { + res.json({ code: -1, msg: 'LogFile must be a file' }); + return; } - let filePath = `${LogsPath}/${LogFile}`; - if (!existsSync(filePath)) { - res.status(404).json({ code: -1, msg: "LogFile does not exist" }); - return; - } - - try { - let fileStats = await stat(filePath); - if (!fileStats.isFile()) { - res.json({ code: -1, msg: "LogFile must be a file" }); - return; - } - - res.sendFile(filePath); - } catch (error) { - res.json({ code: -1, msg: "Failed to send log file." }); - } + res.sendFile(filePath); + } catch (error) { + res.json({ code: -1, msg: 'Failed to send log file.' }); + } }; -export function isValidFileName(fileName: string): boolean { - const invalidChars = /[\.\:\*\?\"\<\>\|\/\\]/; - return !invalidChars.test(fileName); -} \ No newline at end of file +// export function isValidFileName(fileName: string): boolean { +// const invalidChars = /[\.\:\*\?\"\<\>\|\/\\]/; +// return !invalidChars.test(fileName); +// } \ No newline at end of file diff --git a/src/webui/src/api/OB11Config.ts b/src/webui/src/api/OB11Config.ts index e9614c6b..1a3ffd50 100644 --- a/src/webui/src/api/OB11Config.ts +++ b/src/webui/src/api/OB11Config.ts @@ -1,64 +1,64 @@ -import { RequestHandler } from "express"; -import { WebUiDataRuntime } from "../helper/Data"; -import { existsSync, readFileSync, writeFileSync } from "node:fs"; -import { resolve } from "node:path"; -import { OB11Config } from "@/webui/ui/components/WebUiApiOB11Config"; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { RequestHandler } from 'express'; +import { WebUiDataRuntime } from '../helper/Data'; +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { OB11Config } from '@/webui/ui/components/WebUiApiOB11Config'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const isEmpty = (data: any) => - data === undefined || data === null || data === ""; + data === undefined || data === null || data === ''; export const OB11GetConfigHandler: RequestHandler = async (req, res) => { - let isLogin = await WebUiDataRuntime.getQQLoginStatus(); + const isLogin = await WebUiDataRuntime.getQQLoginStatus(); if (!isLogin) { res.send({ code: -1, - message: "Not Login", + message: 'Not Login', }); return; } const uin = await WebUiDataRuntime.getQQLoginUin(); - let configFilePath = resolve(__dirname, `./config/onebot11_${uin}.json`); + const configFilePath = resolve(__dirname, `./config/onebot11_${uin}.json`); //console.log(configFilePath); let data: OB11Config; try { data = JSON.parse( existsSync(configFilePath) ? readFileSync(configFilePath).toString() - : readFileSync(resolve(__dirname, `./config/onebot11.json`)).toString() + : readFileSync(resolve(__dirname, './config/onebot11.json')).toString() ); } catch (e) { data = {} as OB11Config; res.send({ code: -1, - message: "Config Get Error", + message: 'Config Get Error', }); return; } res.send({ code: 0, - message: "success", + message: 'success', data: data, }); return; }; export const OB11SetConfigHandler: RequestHandler = async (req, res) => { - let isLogin = await WebUiDataRuntime.getQQLoginStatus(); + const isLogin = await WebUiDataRuntime.getQQLoginStatus(); if (!isLogin) { res.send({ code: -1, - message: "Not Login", + message: 'Not Login', }); return; } if (isEmpty(req.body.config)) { res.send({ code: -1, - message: "config is empty", + message: 'config is empty', }); return; } @@ -84,12 +84,12 @@ export const OB11SetConfigHandler: RequestHandler = async (req, res) => { if (SetResult) { res.send({ code: 0, - message: "success", + message: 'success', }); } else { res.send({ code: -1, - message: "Config Set Error", + message: 'Config Set Error', }); } diff --git a/src/webui/src/api/QQLogin.ts b/src/webui/src/api/QQLogin.ts index c7c905a4..84355f62 100644 --- a/src/webui/src/api/QQLogin.ts +++ b/src/webui/src/api/QQLogin.ts @@ -1,77 +1,77 @@ -import { RequestHandler } from "express"; -import { WebUiDataRuntime } from "../helper/Data"; -import { sleep } from "@/common/utils/helper"; +import { RequestHandler } from 'express'; +import { WebUiDataRuntime } from '../helper/Data'; +import { sleep } from '@/common/utils/helper'; const isEmpty = (data: any) => data === undefined || data === null || data === ''; export const QQGetQRcodeHandler: RequestHandler = async (req, res) => { - if (await WebUiDataRuntime.getQQLoginStatus()) { - res.send({ - code: -1, - message: 'QQ Is Logined' - }); - return; - } - let qrcodeUrl = await WebUiDataRuntime.getQQLoginQrcodeURL(); - if (isEmpty(qrcodeUrl)) { - res.send({ - code: -1, - message: 'QRCode Get Error' - }); - return; - } + if (await WebUiDataRuntime.getQQLoginStatus()) { res.send({ - code: 0, - message: 'success', - data: { - qrcode: qrcodeUrl - } + code: -1, + message: 'QQ Is Logined' }); return; + } + const qrcodeUrl = await WebUiDataRuntime.getQQLoginQrcodeURL(); + if (isEmpty(qrcodeUrl)) { + res.send({ + code: -1, + message: 'QRCode Get Error' + }); + return; + } + res.send({ + code: 0, + message: 'success', + data: { + qrcode: qrcodeUrl + } + }); + return; }; export const QQCheckLoginStatusHandler: RequestHandler = async (req, res) => { - res.send({ - code: 0, - message: 'success', - data: { - isLogin: await WebUiDataRuntime.getQQLoginStatus() - } - }); + res.send({ + code: 0, + message: 'success', + data: { + isLogin: await WebUiDataRuntime.getQQLoginStatus() + } + }); }; export const QQSetQuickLoginHandler: RequestHandler = async (req, res) => { - let { uin } = req.body; - let isLogin = await WebUiDataRuntime.getQQLoginStatus(); - if (isLogin) { - res.send({ - code: -1, - message: 'QQ Is Logined' - }); - return; - } - if (isEmpty(uin)) { - res.send({ - code: -1, - message: 'uin is empty' - }); - return; - } - const { result, message } = await WebUiDataRuntime.getQQQuickLogin(uin); - if (!result) { - res.send({ - code: -1, - message: message - }); - return; - } - //本来应该验证 但是http不宜这么搞 建议前端验证 - //isLogin = await WebUiDataRuntime.getQQLoginStatus(); + const { uin } = req.body; + const isLogin = await WebUiDataRuntime.getQQLoginStatus(); + if (isLogin) { res.send({ - code: 0, - message: 'success' + code: -1, + message: 'QQ Is Logined' }); -} + return; + } + if (isEmpty(uin)) { + res.send({ + code: -1, + message: 'uin is empty' + }); + return; + } + const { result, message } = await WebUiDataRuntime.getQQQuickLogin(uin); + if (!result) { + res.send({ + code: -1, + message: message + }); + return; + } + //本来应该验证 但是http不宜这么搞 建议前端验证 + //isLogin = await WebUiDataRuntime.getQQLoginStatus(); + res.send({ + code: 0, + message: 'success' + }); +}; export const QQGetQuickLoginListHandler: RequestHandler = async (req, res) => { - const quickLoginList = await WebUiDataRuntime.getQQQuickLoginList(); - res.send({ - code: 0, - data: quickLoginList - }); -} \ No newline at end of file + const quickLoginList = await WebUiDataRuntime.getQQQuickLoginList(); + res.send({ + code: 0, + data: quickLoginList + }); +}; \ No newline at end of file diff --git a/src/webui/src/helper/Data.ts b/src/webui/src/helper/Data.ts index 38e11a95..8be898c5 100644 --- a/src/webui/src/helper/Data.ts +++ b/src/webui/src/helper/Data.ts @@ -1,4 +1,4 @@ -import { OB11Config } from "@/onebot11/config"; +import { OB11Config } from '@/onebot11/config'; interface LoginRuntimeType { LoginCurrentTime: number; @@ -12,72 +12,72 @@ interface LoginRuntimeType { QQLoginList: string[] } } -let LoginRuntime: LoginRuntimeType = { - LoginCurrentTime: Date.now(), - LoginCurrentRate: 0, - QQLoginStatus: false, //已实现 但太傻了 得去那边注册个回调刷新 - QQQRCodeURL: "", - QQLoginUin: "", - NapCatHelper: { - SetOb11ConfigCall: async (ob11: OB11Config) => { return; }, - CoreQuickLoginCall: async (uin: string) => { return { result: false, message: '' }; }, - QQLoginList: [] - } -} +const LoginRuntime: LoginRuntimeType = { + LoginCurrentTime: Date.now(), + LoginCurrentRate: 0, + QQLoginStatus: false, //已实现 但太傻了 得去那边注册个回调刷新 + QQQRCodeURL: '', + QQLoginUin: '', + NapCatHelper: { + SetOb11ConfigCall: async (ob11: OB11Config) => { return; }, + CoreQuickLoginCall: async (uin: string) => { return { result: false, message: '' }; }, + QQLoginList: [] + } +}; export const WebUiDataRuntime = { - checkLoginRate: async function (RateLimit: number): Promise { - LoginRuntime.LoginCurrentRate++; - //console.log(RateLimit, LoginRuntime.LoginCurrentRate, Date.now() - LoginRuntime.LoginCurrentTime); - if (Date.now() - LoginRuntime.LoginCurrentTime > 1000 * 60) { - LoginRuntime.LoginCurrentRate = 0;//超出时间重置限速 - LoginRuntime.LoginCurrentTime = Date.now(); - return true; - } - if (LoginRuntime.LoginCurrentRate <= RateLimit) { - return true; - } - return false; + checkLoginRate: async function (RateLimit: number): Promise { + LoginRuntime.LoginCurrentRate++; + //console.log(RateLimit, LoginRuntime.LoginCurrentRate, Date.now() - LoginRuntime.LoginCurrentTime); + if (Date.now() - LoginRuntime.LoginCurrentTime > 1000 * 60) { + LoginRuntime.LoginCurrentRate = 0;//超出时间重置限速 + LoginRuntime.LoginCurrentTime = Date.now(); + return true; } - , - getQQLoginStatus: async function (): Promise { - return LoginRuntime.QQLoginStatus; + if (LoginRuntime.LoginCurrentRate <= RateLimit) { + return true; } - , - setQQLoginStatus: async function (status: boolean): Promise { - LoginRuntime.QQLoginStatus = status; - } - , - setQQLoginQrcodeURL: async function (url: string): Promise { - LoginRuntime.QQQRCodeURL = url; - } - , - getQQLoginQrcodeURL: async function (): Promise { - return LoginRuntime.QQQRCodeURL; - } - , - setQQLoginUin: async function (uin: string): Promise { - LoginRuntime.QQLoginUin = uin; - } - , - getQQLoginUin: async function (): Promise { - return LoginRuntime.QQLoginUin; - }, - getQQQuickLoginList: async function (): Promise { - return LoginRuntime.NapCatHelper.QQLoginList; - }, - setQQQuickLoginList: async function (list: string[]): Promise { - LoginRuntime.NapCatHelper.QQLoginList = list; - }, - setQQQuickLoginCall(func: (uin: string) => Promise<{ result: boolean, message: string }>): void { - LoginRuntime.NapCatHelper.CoreQuickLoginCall = func; - }, - getQQQuickLogin: async function (uin: string): Promise<{ result: boolean, message: string }> { - return await LoginRuntime.NapCatHelper.CoreQuickLoginCall(uin); - }, - setOB11ConfigCall: async function (func: (ob11: OB11Config) => Promise): Promise { - LoginRuntime.NapCatHelper.SetOb11ConfigCall = func; - }, - setOB11Config: async function (ob11: OB11Config): Promise { - await LoginRuntime.NapCatHelper.SetOb11ConfigCall(ob11); - } -} \ No newline at end of file + return false; + } + , + getQQLoginStatus: async function (): Promise { + return LoginRuntime.QQLoginStatus; + } + , + setQQLoginStatus: async function (status: boolean): Promise { + LoginRuntime.QQLoginStatus = status; + } + , + setQQLoginQrcodeURL: async function (url: string): Promise { + LoginRuntime.QQQRCodeURL = url; + } + , + getQQLoginQrcodeURL: async function (): Promise { + return LoginRuntime.QQQRCodeURL; + } + , + setQQLoginUin: async function (uin: string): Promise { + LoginRuntime.QQLoginUin = uin; + } + , + getQQLoginUin: async function (): Promise { + return LoginRuntime.QQLoginUin; + }, + getQQQuickLoginList: async function (): Promise { + return LoginRuntime.NapCatHelper.QQLoginList; + }, + setQQQuickLoginList: async function (list: string[]): Promise { + LoginRuntime.NapCatHelper.QQLoginList = list; + }, + setQQQuickLoginCall(func: (uin: string) => Promise<{ result: boolean, message: string }>): void { + LoginRuntime.NapCatHelper.CoreQuickLoginCall = func; + }, + getQQQuickLogin: async function (uin: string): Promise<{ result: boolean, message: string }> { + return await LoginRuntime.NapCatHelper.CoreQuickLoginCall(uin); + }, + setOB11ConfigCall: async function (func: (ob11: OB11Config) => Promise): Promise { + LoginRuntime.NapCatHelper.SetOb11ConfigCall = func; + }, + setOB11Config: async function (ob11: OB11Config): Promise { + await LoginRuntime.NapCatHelper.SetOb11ConfigCall(ob11); + } +}; \ No newline at end of file diff --git a/src/webui/src/helper/SignToken.ts b/src/webui/src/helper/SignToken.ts index a369df02..8803a9e1 100644 --- a/src/webui/src/helper/SignToken.ts +++ b/src/webui/src/helper/SignToken.ts @@ -11,58 +11,58 @@ interface WebUiCredentialJson { } export class AuthHelper { - private static secretKey = Math.random().toString(36).slice(2); + private static secretKey = Math.random().toString(36).slice(2); - /** + /** * 签名凭证方法。 * @param token 待签名的凭证字符串。 * @returns 签名后的凭证对象。 */ - public static async signCredential(token: string): Promise { - const innerJson: WebUiCredentialInnerJson = { - CreatedTime: Date.now(), - TokenEncoded: token, - }; - const jsonString = JSON.stringify(innerJson); - const hmac = crypto.createHmac('sha256', AuthHelper.secretKey) - .update(jsonString, 'utf8') - .digest('hex'); - return { Data: innerJson, Hmac: hmac }; - } + public static async signCredential(token: string): Promise { + const innerJson: WebUiCredentialInnerJson = { + CreatedTime: Date.now(), + TokenEncoded: token, + }; + const jsonString = JSON.stringify(innerJson); + const hmac = crypto.createHmac('sha256', AuthHelper.secretKey) + .update(jsonString, 'utf8') + .digest('hex'); + return { Data: innerJson, Hmac: hmac }; + } - /** + /** * 检查凭证是否被篡改的方法。 * @param credentialJson 凭证的JSON对象。 * @returns 布尔值,表示凭证是否有效。 */ - public static async checkCredential(credentialJson: WebUiCredentialJson): Promise { - try { - const jsonString = JSON.stringify(credentialJson.Data); - const calculatedHmac = crypto.createHmac('sha256', AuthHelper.secretKey) - .update(jsonString, 'utf8') - .digest('hex'); - return calculatedHmac === credentialJson.Hmac; - } catch (error) { - return false; - } + public static async checkCredential(credentialJson: WebUiCredentialJson): Promise { + try { + const jsonString = JSON.stringify(credentialJson.Data); + const calculatedHmac = crypto.createHmac('sha256', AuthHelper.secretKey) + .update(jsonString, 'utf8') + .digest('hex'); + return calculatedHmac === credentialJson.Hmac; + } catch (error) { + return false; } + } - /** + /** * 验证凭证在1小时内有效且token与原始token相同。 * @param token 待验证的原始token。 * @param credentialJson 已签名的凭证JSON对象。 * @returns 布尔值,表示凭证是否有效且token匹配。 */ - public static async validateCredentialWithinOneHour(token: string, credentialJson: WebUiCredentialJson): Promise { - const isValid = await AuthHelper.checkCredential(credentialJson); - if (!isValid) { - return false; - } - - const currentTime = Date.now() / 1000; - const createdTime = credentialJson.Data.CreatedTime; - const timeDifference = currentTime - createdTime; - - return timeDifference <= 3600 && credentialJson.Data.TokenEncoded === token; + public static async validateCredentialWithinOneHour(token: string, credentialJson: WebUiCredentialJson): Promise { + const isValid = await AuthHelper.checkCredential(credentialJson); + if (!isValid) { + return false; } + + const currentTime = Date.now() / 1000; + const createdTime = credentialJson.Data.CreatedTime; + const timeDifference = currentTime - createdTime; + + return timeDifference <= 3600 && credentialJson.Data.TokenEncoded === token; + } } \ No newline at end of file diff --git a/src/webui/src/helper/config.ts b/src/webui/src/helper/config.ts index 93758a9f..58e1df7c 100644 --- a/src/webui/src/helper/config.ts +++ b/src/webui/src/helper/config.ts @@ -1,8 +1,8 @@ -import { existsSync, readFileSync, writeFileSync } from "node:fs"; -import { resolve } from "node:path"; -import * as net from "node:net"; -import { dirname } from "node:path" -import { fileURLToPath } from "node:url" +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import * as net from 'node:net'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); @@ -12,34 +12,34 @@ const __dirname = dirname(__filename); const MAX_PORT_TRY = 100; async function tryUsePort(port: number, tryCount: number = 0): Promise { - return new Promise(async (resolve, reject) => { - try { - let server = net.createServer(); - server.on('listening', () => { - server.close(); - resolve(port); - }); + return new Promise(async (resolve, reject) => { + try { + const server = net.createServer(); + server.on('listening', () => { + server.close(); + resolve(port); + }); - server.on('error', (err: any) => { - if (err.code === 'EADDRINUSE') { - if (tryCount < MAX_PORT_TRY) { - // 使用循环代替递归 - resolve(tryUsePort(port + 1, tryCount + 1)); - } else { - reject(`端口尝试失败,达到最大尝试次数: ${MAX_PORT_TRY}`); - } - } else { - reject(`遇到错误: ${err.code}`); - } - }); - - // 尝试监听端口 - server.listen(port); - } catch (error) { - // 这里捕获到的错误应该是启动服务器时的同步错误 - reject(`服务器启动时发生错误: ${error}`); + server.on('error', (err: any) => { + if (err.code === 'EADDRINUSE') { + if (tryCount < MAX_PORT_TRY) { + // 使用循环代替递归 + resolve(tryUsePort(port + 1, tryCount + 1)); + } else { + reject(`端口尝试失败,达到最大尝试次数: ${MAX_PORT_TRY}`); + } + } else { + reject(`遇到错误: ${err.code}`); } - }); + }); + + // 尝试监听端口 + server.listen(port); + } catch (error) { + // 这里捕获到的错误应该是启动服务器时的同步错误 + reject(`服务器启动时发生错误: ${error}`); + } + }); } export interface WebUiConfigType { @@ -49,38 +49,38 @@ export interface WebUiConfigType { } // 读取当前目录下名为 webui.json 的配置文件,如果不存在则创建初始化配置文件 class WebUiConfigWrapper { - WebUiConfigData: WebUiConfigType | undefined = undefined; - async GetWebUIConfig(): Promise { - if (this.WebUiConfigData) { - return this.WebUiConfigData; - } - try { - let configPath = resolve(__dirname, "./config/webui.json"); - let config: WebUiConfigType = { - port: 6099, - token: Math.random().toString(36).slice(2),//生成随机密码 - loginRate: 3 - }; - - if (!existsSync(configPath)) { - writeFileSync(configPath, JSON.stringify(config, null, 4)); - } - - let fileContent = readFileSync(configPath, "utf-8"); - let parsedConfig = JSON.parse(fileContent) as WebUiConfigType; - - // 修正端口占用情况 - const [err, data] = await tryUsePort(parsedConfig.port).then(data => [null, data as number]).catch(err => [err, null]); - parsedConfig.port = data; - if (err) { - //一般没那么离谱 如果真有这么离谱 考虑下 向外抛出异常 - } - this.WebUiConfigData = parsedConfig; - return this.WebUiConfigData; - } catch (e) { - console.error("读取配置文件失败", e); - } - return {} as WebUiConfigType; // 理论上这行代码到不了,为了保持函数完整性而保留 + WebUiConfigData: WebUiConfigType | undefined = undefined; + async GetWebUIConfig(): Promise { + if (this.WebUiConfigData) { + return this.WebUiConfigData; } + try { + const configPath = resolve(__dirname, './config/webui.json'); + const config: WebUiConfigType = { + port: 6099, + token: Math.random().toString(36).slice(2),//生成随机密码 + loginRate: 3 + }; + + if (!existsSync(configPath)) { + writeFileSync(configPath, JSON.stringify(config, null, 4)); + } + + const fileContent = readFileSync(configPath, 'utf-8'); + const parsedConfig = JSON.parse(fileContent) as WebUiConfigType; + + // 修正端口占用情况 + const [err, data] = await tryUsePort(parsedConfig.port).then(data => [null, data as number]).catch(err => [err, null]); + parsedConfig.port = data; + if (err) { + //一般没那么离谱 如果真有这么离谱 考虑下 向外抛出异常 + } + this.WebUiConfigData = parsedConfig; + return this.WebUiConfigData; + } catch (e) { + console.error('读取配置文件失败', e); + } + return {} as WebUiConfigType; // 理论上这行代码到不了,为了保持函数完整性而保留 + } } export const WebUiConfig = new WebUiConfigWrapper(); \ No newline at end of file diff --git a/src/webui/src/router/OB11Config.ts b/src/webui/src/router/OB11Config.ts index ef82681f..c9fae805 100644 --- a/src/webui/src/router/OB11Config.ts +++ b/src/webui/src/router/OB11Config.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; -import { OB11GetConfigHandler,OB11SetConfigHandler} from '../api/OB11Config'; +import { OB11GetConfigHandler,OB11SetConfigHandler } from '../api/OB11Config'; const router = Router(); -router.post('/GetConfig', OB11GetConfigHandler) +router.post('/GetConfig', OB11GetConfigHandler); router.post('/SetConfig', OB11SetConfigHandler); export { router as OB11ConfigRouter }; \ No newline at end of file diff --git a/src/webui/src/router/QQLogin.ts b/src/webui/src/router/QQLogin.ts index 438e6c3e..61fccd80 100644 --- a/src/webui/src/router/QQLogin.ts +++ b/src/webui/src/router/QQLogin.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import { QQCheckLoginStatusHandler, QQGetQRcodeHandler, QQGetQuickLoginListHandler, QQSetQuickLoginHandler } from '../api/QQLogin'; const router = Router(); -router.all('/GetQuickLoginList', QQGetQuickLoginListHandler) +router.all('/GetQuickLoginList', QQGetQuickLoginListHandler); router.post('/CheckLoginStatus', QQCheckLoginStatusHandler); router.post('/GetQQLoginQrcode', QQGetQRcodeHandler); router.post('/SetQuickLogin', QQSetQuickLoginHandler); diff --git a/src/webui/src/router/index.ts b/src/webui/src/router/index.ts index 148ec0d2..6efd6e76 100644 --- a/src/webui/src/router/index.ts +++ b/src/webui/src/router/index.ts @@ -1,65 +1,65 @@ -import { Router } from "express"; +import { Router } from 'express'; import { AuthHelper } from '../../src/helper/SignToken'; import { NextFunction, Request, Response } from 'express'; -import { QQLoginRouter } from "./QQLogin"; -import { AuthRouter } from "./auth"; -import { OB11ConfigRouter } from "./OB11Config"; -import { WebUiConfig } from "../helper/config"; +import { QQLoginRouter } from './QQLogin'; +import { AuthRouter } from './auth'; +import { OB11ConfigRouter } from './OB11Config'; +import { WebUiConfig } from '../helper/config'; const router = Router(); export async function AuthApi(req: Request, res: Response, next: NextFunction) { - //判断当前url是否为/login 如果是跳过鉴权 - if (req.url == '/auth/login') { - next(); - return; - } - if (req.headers?.authorization) { - let authorization = req.headers.authorization.split(' '); - if (authorization.length < 2) { - res.json({ - code: -1, - msg: 'Unauthorized', - }); - return; - } - let token = authorization[1]; - let Credential: any; - try { - Credential = JSON.parse(Buffer.from(token, 'base64').toString('utf-8')); - } catch (e) { - res.json({ - code: -1, - msg: 'Unauthorized', - }); - return; - } - let config = await WebUiConfig.GetWebUIConfig(); - let credentialJson = await AuthHelper.validateCredentialWithinOneHour(config.token, Credential); - if (credentialJson) { - //通过验证 - next(); - return; - } - res.json({ - code: -1, - msg: 'Unauthorized', - }); - return; - } - - res.json({ + //判断当前url是否为/login 如果是跳过鉴权 + if (req.url == '/auth/login') { + next(); + return; + } + if (req.headers?.authorization) { + const authorization = req.headers.authorization.split(' '); + if (authorization.length < 2) { + res.json({ code: -1, - msg: 'Server Error', + msg: 'Unauthorized', + }); + return; + } + const token = authorization[1]; + let Credential: any; + try { + Credential = JSON.parse(Buffer.from(token, 'base64').toString('utf-8')); + } catch (e) { + res.json({ + code: -1, + msg: 'Unauthorized', + }); + return; + } + const config = await WebUiConfig.GetWebUIConfig(); + const credentialJson = await AuthHelper.validateCredentialWithinOneHour(config.token, Credential); + if (credentialJson) { + //通过验证 + next(); + return; + } + res.json({ + code: -1, + msg: 'Unauthorized', }); return; + } + + res.json({ + code: -1, + msg: 'Server Error', + }); + return; } router.use(AuthApi); -router.all("/test", (req, res) => { - res.json({ - code: 0, - msg: 'ok', - }); +router.all('/test', (req, res) => { + res.json({ + code: 0, + msg: 'ok', + }); }); router.use('/auth', AuthRouter); router.use('/QQLogin', QQLoginRouter); router.use('/OB11Config', OB11ConfigRouter); -export { router as ALLRouter } \ No newline at end of file +export { router as ALLRouter }; \ No newline at end of file diff --git a/src/webui/ui/NapCat.ts b/src/webui/ui/NapCat.ts index 026377df..240033eb 100644 --- a/src/webui/ui/NapCat.ts +++ b/src/webui/ui/NapCat.ts @@ -1,15 +1,15 @@ -import { SettingList } from "./components/SettingList"; -import { SettingItem } from "./components/SettingItem"; -import { SettingButton } from "./components/SettingButton"; -import { SettingSwitch } from "./components/SettingSwitch"; -import { SettingSelect } from "./components/SettingSelect"; -import { OB11Config, OB11ConfigWrapper } from "./components/WebUiApiOB11Config"; +import { SettingList } from './components/SettingList'; +import { SettingItem } from './components/SettingItem'; +import { SettingButton } from './components/SettingButton'; +import { SettingSwitch } from './components/SettingSwitch'; +import { SettingSelect } from './components/SettingSelect'; +import { OB11Config, OB11ConfigWrapper } from './components/WebUiApiOB11Config'; async function onSettingWindowCreated(view: Element) { - const isEmpty = (value: any) => value === undefined || value === undefined || value === ""; - await OB11ConfigWrapper.Init(localStorage.getItem("auth") as string); - let ob11Config: OB11Config = await OB11ConfigWrapper.GetOB11Config(); + const isEmpty = (value: any) => value === undefined || value === undefined || value === ''; + await OB11ConfigWrapper.Init(localStorage.getItem('auth') as string); + const ob11Config: OB11Config = await OB11ConfigWrapper.GetOB11Config(); const setOB11Config = (key: string, value: any) => { - const configKey = key.split("."); + const configKey = key.split('.'); if (configKey.length === 2) { ob11Config[configKey[1]] = value; } else if (configKey.length === 3) { @@ -21,7 +21,7 @@ async function onSettingWindowCreated(view: Element) { const parser = new DOMParser(); const doc = parser.parseFromString( [ - "
", + '
', `
`, @@ -29,39 +29,39 @@ async function onSettingWindowCreated(view: Element) { SettingItem( 'Napcat', undefined, - SettingButton("V1.4.0", "napcat-update-button", "secondary") + SettingButton('V1.4.0', 'napcat-update-button', 'secondary') ), ]), SettingList([ SettingItem( - "启用 HTTP 服务", + '启用 HTTP 服务', undefined, - SettingSwitch("ob11.http.enable", ob11Config.http.enable, { - "control-display-id": "config-ob11-http-port", + SettingSwitch('ob11.http.enable', ob11Config.http.enable, { + 'control-display-id': 'config-ob11-http-port', }) ), SettingItem( - "HTTP 服务监听端口", + 'HTTP 服务监听端口', undefined, `
`, - "config-ob11-http-port", + 'config-ob11-http-port', ob11Config.http.enable ), SettingItem( - "启用 HTTP 心跳", + '启用 HTTP 心跳', undefined, - SettingSwitch("ob11.http.enableHeart", ob11Config.http.enableHeart, { - "control-display-id": "config-ob11-HTTP.enableHeart", + SettingSwitch('ob11.http.enableHeart', ob11Config.http.enableHeart, { + 'control-display-id': 'config-ob11-HTTP.enableHeart', }) ), SettingItem( - "启用 HTTP 事件上报", + '启用 HTTP 事件上报', undefined, - SettingSwitch("ob11.http.enablePost", ob11Config.http.enablePost, { - "control-display-id": "config-ob11-http-postUrls", + SettingSwitch('ob11.http.enablePost', ob11Config.http.enablePost, { + 'control-display-id': 'config-ob11-http-postUrls', }) ), - `
@@ -69,7 +69,7 @@ async function onSettingWindowCreated(view: Element) {
+}" placeholder="未设置" />
@@ -81,27 +81,27 @@ async function onSettingWindowCreated(view: Element) {
`, SettingItem( - "启用正向 WebSocket 服务", + '启用正向 WebSocket 服务', undefined, - SettingSwitch("ob11.ws.enable", ob11Config.ws.enable, { - "control-display-id": "config-ob11-ws-port", + SettingSwitch('ob11.ws.enable', ob11Config.ws.enable, { + 'control-display-id': 'config-ob11-ws-port', }) ), SettingItem( - "正向 WebSocket 服务监听端口", + '正向 WebSocket 服务监听端口', undefined, `
`, - "config-ob11-ws-port", + 'config-ob11-ws-port', ob11Config.ws.enable ), SettingItem( - "启用反向 WebSocket 服务", + '启用反向 WebSocket 服务', undefined, - SettingSwitch("ob11.reverseWs.enable", ob11Config.reverseWs.enable, { - "control-display-id": "config-ob11-reverseWs-urls", + SettingSwitch('ob11.reverseWs.enable', ob11Config.reverseWs.enable, { + 'control-display-id': 'config-ob11-reverseWs-urls', }) ), - `
@@ -112,81 +112,81 @@ async function onSettingWindowCreated(view: Element) {
`, SettingItem( - " WebSocket 服务心跳间隔", - "控制每隔多久发送一个心跳包,单位为毫秒", + ' WebSocket 服务心跳间隔', + '控制每隔多久发送一个心跳包,单位为毫秒', `
` ), SettingItem( - "Access token", + 'Access token', undefined, `
` ), SettingItem( - "新消息上报格式", - "如客户端无特殊需求推荐保持默认设置,两者的详细差异可参考 OneBot v11 文档", + '新消息上报格式', + '如客户端无特殊需求推荐保持默认设置,两者的详细差异可参考 OneBot v11 文档', SettingSelect( [ - { text: "消息段", value: "array" }, - { text: "CQ码", value: "string" }, + { text: '消息段', value: 'array' }, + { text: 'CQ码', value: 'string' }, ], - "ob11.messagePostFormat", + 'ob11.messagePostFormat', ob11Config.messagePostFormat ) ), SettingItem( - "音乐卡片签名地址", + '音乐卡片签名地址', undefined, `
`, - "ob11.musicSignUrl" + 'ob11.musicSignUrl' ), SettingItem( - "", + '', undefined, - SettingButton("保存", "config-ob11-save", "primary") + SettingButton('保存', 'config-ob11-save', 'primary') ), ]), SettingList([ SettingItem( - "上报 Bot 自身发送的消息", - "上报 event 为 message_sent", - SettingSwitch("ob11.reportSelfMessage", ob11Config.reportSelfMessage) + '上报 Bot 自身发送的消息', + '上报 event 为 message_sent', + SettingSwitch('ob11.reportSelfMessage', ob11Config.reportSelfMessage) ), ]), SettingList([ SettingItem( - "GitHub 仓库", - `https://github.com/NapNeko/NapCatQQ`, - SettingButton("点个星星", "open-github") + 'GitHub 仓库', + 'https://github.com/NapNeko/NapCatQQ', + SettingButton('点个星星', 'open-github') ), - SettingItem("NapCat 文档", ``, SettingButton("看看文档", "open-docs")), + SettingItem('NapCat 文档', '', SettingButton('看看文档', 'open-docs')), SettingItem( - "Telegram 群", - `https://t.me/+nLZEnpne-pQ1OWFl`, - SettingButton("进去逛逛", "open-telegram") + 'Telegram 群', + 'https://t.me/+nLZEnpne-pQ1OWFl', + SettingButton('进去逛逛', 'open-telegram') ), SettingItem( - "QQ 群", - `545402644`, - SettingButton("我要进去", "open-qq-group") + 'QQ 群', + '545402644', + SettingButton('我要进去', 'open-qq-group') ), ]), - "
", - ].join(""), - "text/html" + '
', + ].join(''), + 'text/html' ); // 外链按钮 - doc.querySelector("#open-github")?.addEventListener("click", () => { - window.open("https://napneko.github.io/", "_blank"); + doc.querySelector('#open-github')?.addEventListener('click', () => { + window.open('https://napneko.github.io/', '_blank'); }); - doc.querySelector("#open-telegram")?.addEventListener("click", () => { - window.open("https://t.me/+nLZEnpne-pQ1OWFl"); + doc.querySelector('#open-telegram')?.addEventListener('click', () => { + window.open('https://t.me/+nLZEnpne-pQ1OWFl'); }); - doc.querySelector("#open-qq-group")?.addEventListener("click", () => { - window.open("https://qm.qq.com/q/bDnHRG38aI"); + doc.querySelector('#open-qq-group')?.addEventListener('click', () => { + window.open('https://qm.qq.com/q/bDnHRG38aI'); }); - doc.querySelector("#open-docs")?.addEventListener("click", () => { - window.open("https://github.com/NapNeko/NapCatQQ"); + doc.querySelector('#open-docs')?.addEventListener('click', () => { + window.open('https://github.com/NapNeko/NapCatQQ'); }); // 生成反向地址列表 const buildHostListItem = ( @@ -196,29 +196,29 @@ async function onSettingWindowCreated(view: Element) { inputAttrs: any = {} ) => { const dom = { - container: document.createElement("setting-item"), - input: document.createElement("input"), - inputContainer: document.createElement("div"), - deleteBtn: document.createElement("setting-button"), + container: document.createElement('setting-item'), + input: document.createElement('input'), + inputContainer: document.createElement('div'), + deleteBtn: document.createElement('setting-button'), }; - dom.container.classList.add("setting-host-list-item"); - dom.container.dataset.direction = "row"; + dom.container.classList.add('setting-host-list-item'); + dom.container.dataset.direction = 'row'; Object.assign(dom.input, inputAttrs); - dom.input.classList.add("q-input__inner"); - dom.input.type = "url"; + dom.input.classList.add('q-input__inner'); + dom.input.type = 'url'; dom.input.value = host; - dom.input.addEventListener("input", () => { - ob11Config[type.split("-")[0]][type.split("-")[1]][index] = + dom.input.addEventListener('input', () => { + ob11Config[type.split('-')[0]][type.split('-')[1]][index] = dom.input.value; }); - dom.inputContainer.classList.add("q-input"); + dom.inputContainer.classList.add('q-input'); dom.inputContainer.appendChild(dom.input); - dom.deleteBtn.innerHTML = "删除"; - dom.deleteBtn.dataset.type = "secondary"; - dom.deleteBtn.addEventListener("click", () => { - ob11Config[type.split("-")[0]][type.split("-")[1]].splice(index, 1); + dom.deleteBtn.innerHTML = '删除'; + dom.deleteBtn.dataset.type = 'secondary'; + dom.deleteBtn.addEventListener('click', () => { + ob11Config[type.split('-')[0]][type.split('-')[1]].splice(index, 1); initReverseHost(type); }); @@ -245,7 +245,7 @@ async function onSettingWindowCreated(view: Element) { doc: Document = document, inputAttr: any = {} ) => { - type = type.replace(/\./g, "-");//替换操作 + type = type.replace(/\./g, '-');//替换操作 const hostContainerDom = doc.body.querySelector( `#config-ob11-${type}-list` @@ -253,22 +253,22 @@ async function onSettingWindowCreated(view: Element) { hostContainerDom?.appendChild( buildHostListItem( type, - "", - ob11Config[type.split("-")[0]][type.split("-")[1]].length, + '', + ob11Config[type.split('-')[0]][type.split('-')[1]].length, inputAttr ) ); - ob11Config[type.split("-")[0]][type.split("-")[1]].push(""); + ob11Config[type.split('-')[0]][type.split('-')[1]].push(''); }; const initReverseHost = (type: string, doc: Document = document) => { - type = type.replace(/\./g, "-");//替换操作 + type = type.replace(/\./g, '-');//替换操作 const hostContainerDom = doc.body?.querySelector( `#config-ob11-${type}-list` ); if (hostContainerDom) { [...hostContainerDom.childNodes].forEach((dom) => dom.remove()); buildHostList( - ob11Config[type.split("-")[0]][type.split("-")[1]], + ob11Config[type.split('-')[0]][type.split('-')[1]], type ).forEach((dom) => { hostContainerDom?.appendChild(dom); @@ -276,51 +276,51 @@ async function onSettingWindowCreated(view: Element) { } }; - initReverseHost("http.postUrls", doc); - initReverseHost("reverseWs.urls", doc); + initReverseHost('http.postUrls', doc); + initReverseHost('reverseWs.urls', doc); doc - .querySelector("#config-ob11-http-postUrls-add") - ?.addEventListener("click", () => - addReverseHost("http.postUrls", document, { - placeholder: "如:http://127.0.0.1:5140/onebot", + .querySelector('#config-ob11-http-postUrls-add') + ?.addEventListener('click', () => + addReverseHost('http.postUrls', document, { + placeholder: '如:http://127.0.0.1:5140/onebot', }) ); doc - .querySelector("#config-ob11-reverseWs-urls-add") - ?.addEventListener("click", () => - addReverseHost("reverseWs.urls", document, { - placeholder: "如:ws://127.0.0.1:5140/onebot", + .querySelector('#config-ob11-reverseWs-urls-add') + ?.addEventListener('click', () => + addReverseHost('reverseWs.urls', document, { + placeholder: '如:ws://127.0.0.1:5140/onebot', }) ); - doc.querySelector("#config-ffmpeg-select")?.addEventListener("click", () => { + doc.querySelector('#config-ffmpeg-select')?.addEventListener('click', () => { //选择ffmpeg }); - doc.querySelector("#config-open-log-path")?.addEventListener("click", () => { + doc.querySelector('#config-open-log-path')?.addEventListener('click', () => { //打开日志 }); // 开关 doc - .querySelectorAll("setting-switch[data-config-key]") + .querySelectorAll('setting-switch[data-config-key]') .forEach((dom: Element) => { - dom.addEventListener("click", () => { - const active = dom.getAttribute("is-active") == undefined; - //@ts-ignore 扩展 + dom.addEventListener('click', () => { + const active = dom.getAttribute('is-active') == undefined; + //@ts-expect-error 等待修复 setOB11Config(dom.dataset.configKey, active); - if (active) dom.setAttribute("is-active", ""); - else dom.removeAttribute("is-active"); - //@ts-ignore 等待修复 + if (active) dom.setAttribute('is-active', ''); + else dom.removeAttribute('is-active'); + //@ts-expect-error 等待修复 if (!isEmpty(dom.dataset.controlDisplayId)) { const displayDom = document.querySelector( - //@ts-ignore 等待修复 + //@ts-expect-error 等待修复 `#${dom.dataset.controlDisplayId}` ); - if (active) displayDom?.removeAttribute("is-hidden"); - else displayDom?.setAttribute("is-hidden", ""); + if (active) displayDom?.removeAttribute('is-hidden'); + else displayDom?.setAttribute('is-hidden', ''); } }); }); @@ -328,15 +328,15 @@ async function onSettingWindowCreated(view: Element) { // 输入框 doc .querySelectorAll( - "setting-item .q-input input.q-input__inner[data-config-key]" + 'setting-item .q-input input.q-input__inner[data-config-key]' ) .forEach((dom: Element) => { - dom.addEventListener("input", () => { - const Type = dom.getAttribute("type"); - //@ts-ignore 等待修复 + dom.addEventListener('input', () => { + const Type = dom.getAttribute('type'); + //@ts-expect-error等待修复 const configKey = dom.dataset.configKey; const configValue = - Type === "number" + Type === 'number' ? parseInt((dom as HTMLInputElement).value) >= 1 ? parseInt((dom as HTMLInputElement).value) : 1 @@ -348,11 +348,11 @@ async function onSettingWindowCreated(view: Element) { // 下拉框 doc - .querySelectorAll("ob-setting-select[data-config-key]") + .querySelectorAll('ob-setting-select[data-config-key]') .forEach((dom: Element) => { - //@ts-ignore 等待修复 - dom?.addEventListener("selected", (e: CustomEvent) => { - //@ts-ignore 等待修复 + //@ts-expect-error等待修复 + dom?.addEventListener('selected', (e: CustomEvent) => { + //@ts-expect-error等待修复 const configKey = dom.dataset.configKey; const configValue = e.detail.value; setOB11Config(configKey, configValue); @@ -360,9 +360,9 @@ async function onSettingWindowCreated(view: Element) { }); // 保存按钮 - doc.querySelector("#config-ob11-save")?.addEventListener("click", () => { + doc.querySelector('#config-ob11-save')?.addEventListener('click', () => { OB11ConfigWrapper.SetOB11Config(ob11Config); - alert("保存成功"); + alert('保存成功'); }); doc.body.childNodes.forEach((node) => { view.appendChild(node); diff --git a/src/webui/ui/components/SettingButton.ts b/src/webui/ui/components/SettingButton.ts index 4dc0ff37..35f6bc87 100644 --- a/src/webui/ui/components/SettingButton.ts +++ b/src/webui/ui/components/SettingButton.ts @@ -1,3 +1,3 @@ export const SettingButton = (text: string, id?: string, type: string = 'secondary') => { - return `${text}` -} \ No newline at end of file + return `${text}`; +}; \ No newline at end of file diff --git a/src/webui/ui/components/SettingItem.ts b/src/webui/ui/components/SettingItem.ts index 26055f3c..40c573ae 100644 --- a/src/webui/ui/components/SettingItem.ts +++ b/src/webui/ui/components/SettingItem.ts @@ -11,5 +11,5 @@ export const SettingItem = ( ${subtitle ? `${subtitle}` : ''}
${action ? `
${action}
` : ''} - ` -} \ No newline at end of file + `; +}; \ No newline at end of file diff --git a/src/webui/ui/components/SettingList.ts b/src/webui/ui/components/SettingList.ts index 35c09664..2357773a 100644 --- a/src/webui/ui/components/SettingList.ts +++ b/src/webui/ui/components/SettingList.ts @@ -1,14 +1,14 @@ export const SettingList = ( - items: string[], - title?: string, - isCollapsible: boolean = false, - direction: string = 'column', - ) => { - return ` + items: string[], + title?: string, + isCollapsible: boolean = false, + direction: string = 'column', +) => { + return ` ${items.join('')} - ` - } \ No newline at end of file + `; +}; \ No newline at end of file diff --git a/src/webui/ui/components/SettingOption.ts b/src/webui/ui/components/SettingOption.ts index a5a6fc03..ccb0654b 100644 --- a/src/webui/ui/components/SettingOption.ts +++ b/src/webui/ui/components/SettingOption.ts @@ -1,3 +1,3 @@ export const SettingOption = (text: string, value?: string, isSelected: boolean = false) => { - return `${text}` - } \ No newline at end of file + return `${text}`; +}; \ No newline at end of file diff --git a/src/webui/ui/components/SettingSelect.ts b/src/webui/ui/components/SettingSelect.ts index 0831d8be..7764cd4a 100644 --- a/src/webui/ui/components/SettingSelect.ts +++ b/src/webui/ui/components/SettingSelect.ts @@ -1,11 +1,11 @@ -import { SettingOption } from './SettingOption' +import { SettingOption } from './SettingOption'; interface MouseEventExtend extends MouseEvent { target: HTMLElement } // -const SelectTemplate = document.createElement('template') +const SelectTemplate = document.createElement('template'); SelectTemplate.innerHTML = ` @@ -17,19 +17,19 @@ SelectTemplate.innerHTML = `