Files
NapCatQQ/packages/napcat-webui-frontend/src/controllers/qq_manager.ts
手瓜一十雪 f9764c9559 Improve new-device QR handling and bypass init
Refactor new-device QR flow and streamline bypass init:

- napcat-shell: stop verbose logging and removed check of enableAllBypasses return value; just invoke native enableAllBypasses when not disabled by env.
- backend (QQLogin): simplify extraction of tokens from jumpUrl (use sig and uin-token), return an error if missing, and send oidbRequest directly (removed nested try/catch and regex fallback).
- frontend (new_device_verify): accept result.str_url without requiring bytes_token and pass an empty string to polling when bytes_token is absent.
- frontend (password_login): change render order to show captcha modal before new-device verification UI.
- frontend (qq_manager): normalize GetNewDeviceQRCode response — derive bytes_token from str_url's str_url query param (base64) when bytes_token is missing, and preserve extra status/error fields in the returned object.

These changes improve robustness when OIDB responses omit bytes_token, reduce noisy logs, and ensure the UI and polling still function.
2026-02-21 13:24:56 +08:00

284 lines
8.5 KiB
TypeScript

import { AxiosRequestConfig } from 'axios';
import { serverRequest } from '@/utils/request';
import { SelfInfo } from '@/types/user';
export default class QQManager {
public static async getOB11Config () {
const data = await serverRequest.post<ServerResponse<OneBotConfig>>(
'/OB11Config/GetConfig'
);
return data.data.data;
}
public static async setOB11Config (config: OneBotConfig) {
await serverRequest.post<ServerResponse<null>>('/OB11Config/SetConfig', {
config: JSON.stringify(config),
});
}
public static async checkQQLoginStatus () {
const data = await serverRequest.post<
ServerResponse<{
isLogin: boolean;
isOffline?: boolean;
qrcodeurl: string;
}>
>('/QQLogin/CheckLoginStatus');
return data.data.data;
}
public static async checkQQLoginStatusWithQrcode () {
const data = await serverRequest.post<
ServerResponse<{ qrcodeurl: string; isLogin: boolean; isOffline?: boolean; loginError?: string; }>
>('/QQLogin/CheckLoginStatus');
return data.data.data;
}
public static async refreshQRCode () {
await serverRequest.post<ServerResponse<null>>('/QQLogin/RefreshQRcode');
}
public static async getQQLoginQrcode () {
const data = await serverRequest.post<
ServerResponse<{
qrcode: string;
}>
>('/QQLogin/GetQQLoginQrcode');
return data.data.data.qrcode;
}
public static async getQQQuickLoginList () {
const data = await serverRequest.post<ServerResponse<string[]>>(
'/QQLogin/GetQuickLoginList'
);
return data.data.data;
}
public static async getQQQuickLoginListNew () {
const data = await serverRequest.post<ServerResponse<LoginListItem[]>>(
'/QQLogin/GetQuickLoginListNew'
);
return data.data.data;
}
public static async setQuickLogin (uin: string) {
await serverRequest.post<ServerResponse<null>>('/QQLogin/SetQuickLogin', {
uin,
});
}
public static async getQQLoginInfo (config?: AxiosRequestConfig) {
const data = await serverRequest.post<ServerResponse<SelfInfo>>(
'/QQLogin/GetQQLoginInfo',
{},
config
);
return data.data.data;
}
public static async getQuickLoginQQ () {
const { data } = await serverRequest.post<ServerResponse<string>>(
'/QQLogin/GetQuickLoginQQ'
);
return data.data;
}
public static async setQuickLoginQQ (uin: string) {
await serverRequest.post<ServerResponse<null>>('/QQLogin/SetQuickLoginQQ', {
uin,
});
}
public static async passwordLogin (uin: string, passwordMd5: string) {
const data = await serverRequest.post<ServerResponse<{
needCaptcha?: boolean;
proofWaterUrl?: string;
needNewDevice?: boolean;
jumpUrl?: string;
newDevicePullQrCodeSig?: string;
} | null>>('/QQLogin/PasswordLogin', {
uin,
passwordMd5,
});
return data.data.data;
}
public static async captchaLogin (uin: string, passwordMd5: string, ticket: string, randstr: string, sid: string) {
const data = await serverRequest.post<ServerResponse<{
needNewDevice?: boolean;
jumpUrl?: string;
newDevicePullQrCodeSig?: string;
} | null>>('/QQLogin/CaptchaLogin', {
uin,
passwordMd5,
ticket,
randstr,
sid,
});
return data.data.data;
}
public static async newDeviceLogin (uin: string, passwordMd5: string, newDevicePullQrCodeSig: string) {
const data = await serverRequest.post<ServerResponse<{
needNewDevice?: boolean;
jumpUrl?: string;
newDevicePullQrCodeSig?: string;
} | null>>('/QQLogin/NewDeviceLogin', {
uin,
passwordMd5,
newDevicePullQrCodeSig,
});
return data.data.data;
}
public static async getNewDeviceQRCode (uin: string, jumpUrl: string) {
const data = await serverRequest.post<ServerResponse<{
str_url?: string;
bytes_token?: string;
uint32_guarantee_status?: number;
ActionStatus?: string;
ErrorCode?: number;
ErrorInfo?: string;
}>>('/QQLogin/GetNewDeviceQRCode', {
uin,
jumpUrl,
});
const result = data.data.data;
if (result?.str_url) {
let bytesToken = result.bytes_token || '';
if (!bytesToken && result.str_url) {
// 只对 str_url 参数值做 base64 编码
try {
const urlObj = new URL(result.str_url);
const strUrlParam = urlObj.searchParams.get('str_url') || '';
bytesToken = strUrlParam ? btoa(strUrlParam) : '';
} catch {
bytesToken = '';
}
}
return {
str_url: result.str_url,
bytes_token: bytesToken,
uint32_guarantee_status: result.uint32_guarantee_status,
ActionStatus: result.ActionStatus,
ErrorCode: result.ErrorCode,
ErrorInfo: result.ErrorInfo,
};
}
return result;
}
public static async pollNewDeviceQR (uin: string, bytesToken: string) {
const data = await serverRequest.post<ServerResponse<{
uint32_guarantee_status?: number;
str_nt_succ_token?: string;
}>>('/QQLogin/PollNewDeviceQR', {
uin,
bytesToken,
});
return data.data.data;
}
public static async resetDeviceID () {
await serverRequest.post<ServerResponse<null>>('/QQLogin/ResetDeviceID');
}
public static async restartNapCat () {
await serverRequest.post<ServerResponse<null>>('/QQLogin/RestartNapCat');
}
public static async getDeviceGUID () {
const data = await serverRequest.post<ServerResponse<{ guid: string; }>>('/QQLogin/GetDeviceGUID');
return data.data.data;
}
public static async setDeviceGUID (guid: string) {
await serverRequest.post<ServerResponse<null>>('/QQLogin/SetDeviceGUID', { guid });
}
public static async getGUIDBackups () {
const data = await serverRequest.post<ServerResponse<string[]>>('/QQLogin/GetGUIDBackups');
return data.data.data;
}
public static async restoreGUIDBackup (backupName: string) {
await serverRequest.post<ServerResponse<null>>('/QQLogin/RestoreGUIDBackup', { backupName });
}
public static async createGUIDBackup () {
const data = await serverRequest.post<ServerResponse<{ path: string; }>>('/QQLogin/CreateGUIDBackup');
return data.data.data;
}
// ============================================================
// 平台信息 & Linux GUID 管理
// ============================================================
public static async getPlatformInfo () {
const data = await serverRequest.post<ServerResponse<{ platform: string; }>>('/QQLogin/GetPlatformInfo');
return data.data.data;
}
public static async getLinuxMAC () {
const data = await serverRequest.post<ServerResponse<{ mac: string; }>>('/QQLogin/GetLinuxMAC');
return data.data.data;
}
public static async setLinuxMAC (mac: string) {
await serverRequest.post<ServerResponse<null>>('/QQLogin/SetLinuxMAC', { mac });
}
public static async getLinuxMachineId () {
const data = await serverRequest.post<ServerResponse<{ machineId: string; }>>('/QQLogin/GetLinuxMachineId');
return data.data.data;
}
public static async computeLinuxGUID (mac?: string, machineId?: string) {
const data = await serverRequest.post<ServerResponse<{ guid: string; machineId: string; mac: string; }>>('/QQLogin/ComputeLinuxGUID', { mac, machineId });
return data.data.data;
}
public static async getLinuxMachineInfoBackups () {
const data = await serverRequest.post<ServerResponse<string[]>>('/QQLogin/GetLinuxMachineInfoBackups');
return data.data.data;
}
public static async createLinuxMachineInfoBackup () {
const data = await serverRequest.post<ServerResponse<{ path: string; }>>('/QQLogin/CreateLinuxMachineInfoBackup');
return data.data.data;
}
public static async restoreLinuxMachineInfoBackup (backupName: string) {
await serverRequest.post<ServerResponse<null>>('/QQLogin/RestoreLinuxMachineInfoBackup', { backupName });
}
public static async resetLinuxDeviceID () {
await serverRequest.post<ServerResponse<null>>('/QQLogin/ResetLinuxDeviceID');
}
// ============================================================
// NapCat 配置管理
// ============================================================
public static async getNapCatConfig () {
const { data } = await serverRequest.get<ServerResponse<NapCatConfig>>(
'/NapCatConfig/GetConfig'
);
return data.data;
}
public static async setNapCatConfig (config: Partial<NapCatConfig>) {
await serverRequest.post<ServerResponse<null>>(
'/NapCatConfig/SetConfig',
config
);
}
}