feat: 自动登录失败后回退密码登录并补充独立配置 (#1638)

* feat: 自动登录失败后回退密码登录并补充独立配置

改动文件:
- packages/napcat-webui-backend/src/helper/config.ts
- packages/napcat-webui-backend/src/utils/auto_login.ts
- packages/napcat-webui-backend/src/utils/auto_login_config.ts
- packages/napcat-webui-backend/index.ts
- packages/napcat-webui-backend/src/api/QQLogin.ts
- packages/napcat-webui-backend/src/router/QQLogin.ts
- packages/napcat-webui-frontend/src/controllers/qq_manager.ts
- packages/napcat-webui-frontend/src/pages/dashboard/config/login.tsx
- packages/napcat-test/autoPasswordFallback.test.ts

目的:
- 在启动阶段将自动登录流程从“仅快速登录”扩展为“快速登录失败后自动回退密码登录”,并保持二维码兜底。
- 在 WebUI 登录配置页新增独立的自动回退账号/密码配置,密码仅提交与存储 MD5,不回显明文。

效果:
- 后端配置新增 autoPasswordLoginAccount 与 autoPasswordLoginPasswordMd5 字段,并提供读取、更新(空密码不覆盖)和清空能力。
- 新增 QQLogin API:GetAutoPasswordLoginConfig / SetAutoPasswordLoginConfig / ClearAutoPasswordLoginConfig。
- WebUI 登录配置页新增自动回退密码登录区块,支持保存、刷新、清空及“留空不修改密码”交互。
- 新增自动登录回退逻辑单测与配置补丁构造单测,覆盖快速成功、回退成功、回退失败、无密码兜底等场景。

* feat: 精简为环境变量驱动的快速登录失败密码回退

改动目的:
- 按维护者建议将方案收敛为后端环境变量驱动,不新增 WebUI 配置与路由
- 保留“快速登录失败 -> 密码回退 -> 二维码兜底”核心能力
- 兼容快速启动参数场景,降低评审复杂度

主要改动文件:
- packages/napcat-webui-backend/index.ts
- packages/napcat-shell/base.ts
- packages/napcat-webui-backend/src/api/QQLogin.ts
- packages/napcat-webui-backend/src/helper/config.ts
- packages/napcat-webui-backend/src/router/QQLogin.ts
- packages/napcat-webui-frontend/src/controllers/qq_manager.ts
- packages/napcat-webui-frontend/src/pages/dashboard/config/login.tsx
- 删除:packages/napcat-webui-backend/src/utils/auto_login.ts
- 删除:packages/napcat-webui-backend/src/utils/auto_login_config.ts
- 删除:packages/napcat-test/autoPasswordFallback.test.ts

实现细节:
1. WebUI 启动自动登录链路
- 保留 NAPCAT_QUICK_ACCOUNT 优先逻辑
- 快速登录失败后触发密码回退
- 回退密码来源优先级:
  a) NAPCAT_QUICK_PASSWORD_MD5(32 位 MD5)
  b) NAPCAT_QUICK_PASSWORD(运行时自动计算 MD5)
- 未配置回退密码时保持二维码兜底,并输出带 QQ 号的引导日志

2. Shell 快速登录链路
- quickLoginWithUin 失败判定统一基于 result 码 + errMsg
- 覆盖历史账号不存在、凭证失效、快速登录异常等场景
- 失败后统一进入同一密码回退逻辑,再兜底二维码

3. 文案与可运维性
- 日志明确推荐优先使用 ACCOUNT + NAPCAT_QUICK_PASSWORD
- NAPCAT_QUICK_PASSWORD_MD5 作为备用方式

效果:
- 满足自动回退登录需求,且改动面显著缩小
- 不修改 napcat-docker 仓库代码,直接兼容现有容器启动参数
- 便于上游快速审阅与合并

* fix: 修复 napcat-framework 未使用变量导致的 CI typecheck 失败

改动文件:
- packages/napcat-framework/napcat.ts

问题背景:
- 上游代码中声明了变量 bypassEnabled,但后续未使用
- 在 CI 的全量 TypeScript 检查中触发 TS6133(声明但未读取)
- 导致 PR Build 机器人评论显示构建失败(Type check failed)

具体修复:
- 将以下语句从“赋值后未使用”改为“直接调用”
- 原:const bypassEnabled = napi2nativeLoader.nativeExports.enableAllBypasses?.(bypassOptions);
- 现:napi2nativeLoader.nativeExports.enableAllBypasses?.(bypassOptions);

影响与效果:
- 不改变运行时行为(仍会执行 enableAllBypasses)
- 消除 TS6133 报错,恢复 typecheck 可通过

本地验证:
- pnpm run typecheck:通过
- pnpm run build:framework:通过
- pnpm run build:shell:通过

---------

Co-authored-by: 手瓜一十雪 <nanaeonn@outlook.com>
This commit is contained in:
Eric-Terminal
2026-02-21 14:18:34 +08:00
committed by GitHub
parent 964fd98914
commit eb07cdb715
2 changed files with 126 additions and 20 deletions

View File

@@ -5,7 +5,7 @@
import express from 'express';
import type { WebUiConfigType } from './src/types';
import { createServer } from 'http';
import { randomUUID } from 'node:crypto';
import { createHash, randomUUID } from 'node:crypto';
import { createServer as createHttpsServer } from 'https';
import { NapCatPathWrapper } from 'napcat-common/src/path';
import { WebUiConfigWrapper } from '@/napcat-webui-backend/src/helper/config';
@@ -156,16 +156,60 @@ export async function InitWebUi (logger: ILogWrapper, pathWrapper: NapCatPathWra
WebUiDataRuntime.setWebUiConfigQuickFunction(
async () => {
const autoLoginAccount = process.env['NAPCAT_QUICK_ACCOUNT'] || WebUiConfig.getAutoLoginAccount();
if (autoLoginAccount) {
try {
const { result, message } = await WebUiDataRuntime.requestQuickLogin(autoLoginAccount);
if (!result) {
throw new Error(message);
const resolveQuickPasswordMd5 = (): string | undefined => {
const quickPasswordMd5FromEnv = process.env['NAPCAT_QUICK_PASSWORD_MD5']?.trim();
if (quickPasswordMd5FromEnv) {
if (/^[a-fA-F0-9]{32}$/.test(quickPasswordMd5FromEnv)) {
return quickPasswordMd5FromEnv.toLowerCase();
}
console.log(`[NapCat] [WebUi] Auto login account: ${autoLoginAccount}`);
} catch (error) {
console.log('[NapCat] [WebUi] Auto login account failed.' + error);
console.log('[NapCat] [WebUi] NAPCAT_QUICK_PASSWORD_MD5 格式无效(需为 32 位 MD5');
}
const quickPassword = process.env['NAPCAT_QUICK_PASSWORD'];
if (typeof quickPassword === 'string' && quickPassword.length > 0) {
console.log('[NapCat] [WebUi] 检测到 NAPCAT_QUICK_PASSWORD已在内存中计算 MD5 用于回退登录');
return createHash('md5').update(quickPassword, 'utf8').digest('hex');
}
return undefined;
};
if (!autoLoginAccount) {
return;
}
const quickPasswordMd5 = resolveQuickPasswordMd5();
try {
const { result, message } = await WebUiDataRuntime.requestQuickLogin(autoLoginAccount);
if (result) {
console.log(`[NapCat] [WebUi] 自动快速登录成功: ${autoLoginAccount}`);
return;
}
console.log(`[NapCat] [WebUi] 自动快速登录失败: ${message || '未知错误'}`);
} catch (error) {
console.log('[NapCat] [WebUi] 自动快速登录异常:' + error);
}
if (!quickPasswordMd5) {
console.log(`[NapCat] [WebUi] QQ ${autoLoginAccount} 未配置回退密码环境变量,建议优先使用 ACCOUNT + NAPCAT_QUICK_PASSWORDNAPCAT_QUICK_PASSWORD_MD5 作为备用),保持二维码登录兜底`);
return;
}
try {
const { result, message, needCaptcha, needNewDevice } = await WebUiDataRuntime.requestPasswordLogin(autoLoginAccount, quickPasswordMd5);
if (result) {
console.log(`[NapCat] [WebUi] 自动密码回退登录成功: ${autoLoginAccount}`);
return;
}
if (needCaptcha) {
console.log(`[NapCat] [WebUi] 自动密码回退登录需要验证码,请在登录页面继续完成: ${autoLoginAccount}`);
return;
}
if (needNewDevice) {
console.log(`[NapCat] [WebUi] 自动密码回退登录需要新设备验证,请在登录页面继续完成: ${autoLoginAccount}`);
return;
}
console.log(`[NapCat] [WebUi] 自动密码回退登录失败: ${message || '未知错误'}`);
} catch (error) {
console.log('[NapCat] [WebUi] 自动密码回退登录异常:' + error);
}
});
// ------------注册中间件------------