fix: 修复NapCat验证码日志窗口

This commit is contained in:
sunlei 2026-06-13 12:47:58 +08:00
parent e5709e00e1
commit f47f27ae4f
2 changed files with 78 additions and 2 deletions

View File

@ -1232,6 +1232,7 @@ export class QqbotNapcatLoginService {
let loginInfo: NapcatLoginInfo | undefined;
let loggedInSelfId = '';
const passwordLogSinceMs = Date.now();
session.passwordMd5 = createHash('md5')
.update(password, 'utf8')
.digest('hex');
@ -1268,7 +1269,7 @@ export class QqbotNapcatLoginService {
);
loginStatus = await this.waitForPasswordLoginStatus(
container,
session.lastRestartedAt,
passwordLogSinceMs,
);
if (loginStatus.isLogin) {
@ -1295,7 +1296,7 @@ export class QqbotNapcatLoginService {
const captchaUrl = await this.resolvePasswordCaptchaUrl(
container,
loginStatus,
session.lastRestartedAt,
passwordLogSinceMs,
);
if (captchaUrl) {
this.keepPasswordCaptchaPending(

View File

@ -748,6 +748,81 @@ describe('QqbotNapcatLoginService', () => {
expect(session.captchaUrl).toBe(captchaUrl);
});
it('anchors password captcha log lookup before runtime env rebuild', async () => {
const captchaUrl =
'https://ti.qq.com/safe/tools/captcha/sms-verify-login?uin=10001';
const container = {
baseUrl: 'http://127.0.0.1:6103/',
id: 'container-password-log-window',
name: 'napcat-10001',
};
const passwordLogSinceMs = 1000;
const envRebuildStartedAt = 5000;
let envRebuildStarted = false;
const containerService = {
ensureRuntimeLoginEnv: jest.fn().mockImplementation(async () => {
envRebuildStarted = true;
return { changed: true, ok: true };
}),
restartRuntimeContainer: jest.fn().mockResolvedValue(true),
};
const refreshService = new QqbotNapcatLoginService(
{
get: jest.fn((key: string) => {
const values: Record<string, string> = {
QQBOT_NAPCAT_LOGIN_POLL_INTERVAL_MS: '1',
QQBOT_NAPCAT_PASSWORD_LOGIN_WAIT_MS: '1',
};
return values[key] || '';
}),
} as unknown as ConfigService,
{} as QqbotAccountService,
containerService as unknown as QqbotNapcatContainerService,
new ToolsService(),
);
const session = (refreshService as any).createSession({
accountId: 'account-1',
container,
expectedSelfId: '10001',
mode: 'refresh',
preparingRelogin: true,
status: 'pending',
});
jest.spyOn(Date, 'now').mockImplementation(() =>
envRebuildStarted ? envRebuildStartedAt : passwordLogSinceMs,
);
jest.spyOn(refreshService as any, 'waitForPasswordLoginStatus')
.mockResolvedValue({
isLogin: false,
loginError: '密码回退需要验证码,请在 WebUi 中继续完成验证',
});
jest
.spyOn(refreshService as any, 'resolvePasswordCaptchaUrl')
.mockResolvedValue(captchaUrl);
const result = await (refreshService as any).tryPasswordRelogin(
session,
container,
'qq-password',
);
expect(result).toBe(true);
expect(
(refreshService as any).waitForPasswordLoginStatus,
).toHaveBeenCalledWith(container, passwordLogSinceMs);
expect(
(refreshService as any).resolvePasswordCaptchaUrl,
).toHaveBeenCalledWith(
container,
expect.objectContaining({ isLogin: false }),
passwordLogSinceMs,
);
expect(session.lastRestartedAt).toBeGreaterThanOrEqual(
envRebuildStartedAt,
);
expect(session.captchaUrl).toBe(captchaUrl);
});
it('does not keep stale captcha from tail logs when current password status is processing', async () => {
const staleCaptchaUrl =
'https://ti.qq.com/safe/tools/captcha/sms-verify-login?uin=10001';