Skip to content

Commit da4ebd9

Browse files
committed
feat: enhance QQ account setup with secure token and update initialization wizard
- Updated `setQqAccount` method in `DesktopBridge` and related interfaces to accept an optional `websocketToken`. - Integrated secure token generation for QQ account setup using `createSecureToken`. - Modified `InitializationWizard` to handle the new QQ account setup flow, including UI updates and error handling. - Removed unused `initializePtyLogStore` call from `DesktopShell`. - Improved button styles for better responsiveness in `DesktopShell`. - Refactored `TerminalPanel` to utilize new terminal handling logic and improved session management. - Added clipboard copy functionality for terminal selections. - Updated keyboard shortcut handling in `Kbd` component to support compact mode.
1 parent aa19a8b commit da4ebd9

11 files changed

Lines changed: 471 additions & 444 deletions

File tree

resources/installer.nsh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
1+
!macro customPageAfterChangeDir
2+
!define MUI_PAGE_CUSTOMFUNCTION_SHOW maibotShowInstallDetails
3+
!macroend
4+
15
!macro customHeader
26
ShowInstDetails show
37
!ifdef BUILD_UNINSTALLER
48
ShowUninstDetails show
59
!endif
610
!macroend
11+
12+
!macro customInstall
13+
SetDetailsView show
14+
!macroend
15+
16+
Function maibotShowInstallDetails
17+
SetDetailsView show
18+
FunctionEnd

src/main/ipc/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ export function registerAppIpc({
104104
return result;
105105
});
106106

107-
ipcMain.handle("init:setQqAccount", async (_event, qqAccount: string): Promise<InitState> => {
108-
const state = await initManager.setQqAccount(qqAccount);
107+
ipcMain.handle("init:setQqAccount", async (_event, qqAccount: string, websocketToken?: string): Promise<InitState> => {
108+
const state = await initManager.setQqAccount(qqAccount, websocketToken);
109109
logStore.append("desktop", "system", `机器人 QQ 号已配置: ${qqAccount}`);
110110
await broadcastSnapshot();
111111
return state;

src/main/services/init-manager.ts

Lines changed: 94 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ function toDetail(error: unknown): string {
6363
return error instanceof Error ? error.message : String(error);
6464
}
6565

66+
function createWebsocketToken(): string {
67+
return randomBytes(24).toString("base64url").slice(0, 32);
68+
}
69+
6670
async function runWithoutAsar<T>(operation: () => Promise<T>): Promise<T> {
6771
const electronProcess = process as NodeJS.Process & { noAsar?: boolean };
6872
const previousNoAsar = electronProcess.noAsar;
@@ -126,7 +130,7 @@ export class InitManager {
126130
return { state, changedFiles };
127131
}
128132

129-
async setQqAccount(qqAccount: string): Promise<InitState> {
133+
async setQqAccount(qqAccount: string, websocketToken = createWebsocketToken()): Promise<InitState> {
130134
if (!isDigits(qqAccount)) {
131135
throw new Error("QQ 号必须是纯数字");
132136
}
@@ -148,7 +152,7 @@ export class InitManager {
148152

149153
await mkdir(dirname(botConfigPath), { recursive: true });
150154
await writeFile(botConfigPath, content, "utf8");
151-
await this.createNapCatConfigs(qqAccount);
155+
await this.createNapCatConfigs(qqAccount, websocketToken);
152156
await this.ensureNapCatWebUiConfig();
153157
return this.getState();
154158
}
@@ -476,8 +480,16 @@ export class InitManager {
476480
};
477481
}
478482

479-
private async createNapCatConfigs(qqAccount: string): Promise<void> {
480-
const versions = await this.findNapCatVersions();
483+
private async createNapCatConfigs(qqAccount: string, websocketToken: string): Promise<void> {
484+
const versions = await this.findNapCatConfigVersions();
485+
const napcatProtocolConfig = {
486+
enable: false,
487+
network: {
488+
httpServers: [],
489+
websocketServers: [],
490+
websocketClients: [],
491+
},
492+
};
481493
const napcatConfig = {
482494
fileLog: false,
483495
consoleLog: true,
@@ -486,63 +498,68 @@ export class InitManager {
486498
packetBackend: "auto",
487499
packetServer: "",
488500
o3HookMode: 1,
501+
bypass: {
502+
hook: false,
503+
window: false,
504+
module: false,
505+
process: false,
506+
container: false,
507+
js: false,
508+
},
509+
autoTimeSync: true,
489510
};
490511
const onebotConfig = {
491512
network: {
492513
httpServers: [],
493514
httpSseServers: [],
494515
httpClients: [],
495-
websocketServers: [],
496-
websocketClients: [
516+
websocketServers: [
497517
{
498518
enable: true,
499519
name: "MaiBot Main",
500-
url: "ws://localhost:8095",
520+
host: "127.0.0.1",
521+
port: 7998,
501522
reportSelfMessage: false,
523+
enableForcePushEvent: true,
502524
messagePostFormat: "array",
503-
token: "",
525+
token: websocketToken,
504526
debug: false,
505527
heartInterval: 30000,
506-
reconnectInterval: 30000,
507528
},
508529
],
530+
websocketClients: [],
509531
plugins: [],
510532
},
511533
musicSignUrl: "",
512534
enableLocalFile2Url: false,
513535
parseMultMsg: false,
536+
imageDownloadProxy: "",
537+
timeout: {
538+
baseTimeout: 10000,
539+
uploadSpeedKBps: 256,
540+
downloadSpeedKBps: 256,
541+
maxTimeout: 1800000,
542+
},
514543
};
515544

516545
for (const version of versions) {
517-
const configDirs = [
518-
join(this.paths.modulesRoot, "napcat", "versions", version, "resources", "app", "napcat", "config"),
519-
join(
520-
this.paths.modulesRoot,
521-
"napcatframework",
522-
"versions",
523-
version,
524-
"resources",
525-
"app",
526-
"LiteLoader",
527-
"plugins",
528-
"NapCat",
529-
"config",
530-
),
531-
];
532-
533-
for (const configDir of configDirs) {
534-
await mkdir(configDir, { recursive: true });
535-
await writeFile(
536-
join(configDir, `napcat_${qqAccount}.json`),
537-
JSON.stringify(napcatConfig, null, 2),
538-
"utf8",
539-
);
540-
await writeFile(
541-
join(configDir, `onebot11_${qqAccount}.json`),
542-
JSON.stringify(onebotConfig, null, 2),
543-
"utf8",
544-
);
545-
}
546+
const configDir = join(this.paths.modulesRoot, "napcat", "versions", version, "resources", "app", "napcat", "config");
547+
await mkdir(configDir, { recursive: true });
548+
await writeFile(
549+
join(configDir, `napcat_protocol_${qqAccount}.json`),
550+
JSON.stringify(napcatProtocolConfig, null, 2),
551+
"utf8",
552+
);
553+
await writeFile(
554+
join(configDir, `onebot11_${qqAccount}.json`),
555+
JSON.stringify(onebotConfig, null, 2),
556+
"utf8",
557+
);
558+
await writeFile(
559+
join(configDir, `napcat_${qqAccount}.json`),
560+
JSON.stringify(napcatConfig, null, 2),
561+
"utf8",
562+
);
546563
}
547564
}
548565

@@ -594,4 +611,43 @@ export class InitManager {
594611

595612
return versions.size > 0 ? [...versions] : [NAPCAT_FALLBACK_VERSION];
596613
}
614+
615+
private async findNapCatConfigVersions(): Promise<string[]> {
616+
const versions = await this.findNapCatVersions();
617+
const comparable = versions.map((version) => ({
618+
version,
619+
parts: this.parseNapCatVersion(version),
620+
}));
621+
622+
if (comparable.some((item) => !item.parts)) {
623+
return versions;
624+
}
625+
626+
const sorted = comparable.toSorted((left, right) => this.compareVersionParts(left.parts ?? [], right.parts ?? []));
627+
return [sorted[sorted.length - 1]?.version ?? NAPCAT_FALLBACK_VERSION];
628+
}
629+
630+
private parseNapCatVersion(version: string): number[] | undefined {
631+
const match = version.match(/^(\d+(?:\.\d+)*)(?:-(\d+))?$/u);
632+
if (!match) {
633+
return undefined;
634+
}
635+
636+
return [
637+
...match[1].split(".").map((part) => Number(part)),
638+
match[2] ? Number(match[2]) : 0,
639+
];
640+
}
641+
642+
private compareVersionParts(left: number[], right: number[]): number {
643+
const length = Math.max(left.length, right.length);
644+
for (let index = 0; index < length; index += 1) {
645+
const diff = (left[index] ?? 0) - (right[index] ?? 0);
646+
if (diff !== 0) {
647+
return diff;
648+
}
649+
}
650+
651+
return 0;
652+
}
597653
}

src/preload/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ const desktopBridge: DesktopBridge = {
6060
init: {
6161
getState: () => ipcRenderer.invoke("init:getState") as Promise<InitState>,
6262
repair: () => ipcRenderer.invoke("init:repair") as Promise<InitRepairResult>,
63-
setQqAccount: (qqAccount: string) =>
64-
ipcRenderer.invoke("init:setQqAccount", qqAccount) as Promise<InitState>,
63+
setQqAccount: (qqAccount: string, websocketToken?: string) =>
64+
ipcRenderer.invoke("init:setQqAccount", qqAccount, websocketToken) as Promise<InitState>,
6565
},
6666
services: {
6767
start: (serviceId: ServiceId) =>

src/renderer/src/components/app/DesktopShell.tsx

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import type { ComponentProps } from "react";
1414
import { useCallback, useEffect, useMemo, useState } from "react";
1515
import type { DesktopSnapshot, ServiceDescriptor, ServiceId, ServiceStatus } from "@shared/contracts";
1616
import { getDesktopSnapshot, normalizeDesktopSnapshot } from "@/lib/desktop-api";
17-
import { initializePtyLogStore } from "@/lib/pty-log-store";
1817
import { useShortcut } from "@/lib/use-shortcut";
1918
import { useSidebar } from "@/lib/use-sidebar";
2019
import { useTheme } from "@/lib/use-theme";
@@ -162,8 +161,6 @@ export function DesktopShell(): React.JSX.Element {
162161
useEffect(() => {
163162
let mounted = true;
164163

165-
initializePtyLogStore();
166-
167164
refreshSnapshot().then((nextSnapshot) => {
168165
if (mounted) {
169166
setSnapshot(nextSnapshot);
@@ -354,27 +351,27 @@ export function DesktopShell(): React.JSX.Element {
354351

355352
<div className="grid gap-2 px-4 py-4">
356353
<Button
357-
className="w-full justify-between"
354+
className="w-full min-w-0 justify-between"
358355
disabled={actionBusy !== null}
359356
onClick={startAll}
360357
>
361-
<span className="flex items-center gap-2">
358+
<span className="flex min-w-0 flex-1 items-center gap-2">
362359
{actionBusy === "all:start" ? <Loader2 className="animate-spin" /> : <Power />}
363-
启动全部服务
360+
<span className="min-w-0 truncate">启动全部服务</span>
364361
</span>
365-
<Kbd keys="Mod+Shift+S" tone="inverse" />
362+
<Kbd className="ml-2 shrink-0" compact keys="Mod+Shift+S" size="xs" tone="inverse" />
366363
</Button>
367364
<Button
368-
className="w-full justify-between"
365+
className="w-full min-w-0 justify-between"
369366
disabled={actionBusy !== null}
370367
onClick={stopAll}
371368
variant="outline"
372369
>
373-
<span className="flex items-center gap-2">
370+
<span className="flex min-w-0 flex-1 items-center gap-2">
374371
{actionBusy === "all:stop" ? <Loader2 className="animate-spin" /> : <Square />}
375-
停止全部服务
372+
<span className="min-w-0 truncate">停止全部服务</span>
376373
</span>
377-
<Kbd keys="Mod+Shift+X" />
374+
<Kbd className="ml-2 shrink-0" compact keys="Mod+Shift+X" size="xs" />
378375
</Button>
379376
<Button
380377
className="w-full justify-center"

0 commit comments

Comments
 (0)