fix: 修复NapCat更新登录二维码兜底
This commit is contained in:
parent
0a46e44097
commit
d03e7c09a4
@ -1285,6 +1285,10 @@ export class QqbotNapcatLoginService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!loginStatus.isLogin) {
|
if (!loginStatus.isLogin) {
|
||||||
|
if (this.isPasswordQrcodeChallenge(loginStatus)) {
|
||||||
|
await this.keepPasswordQrcodePending(session, container, loginStatus);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const captchaUrl = await this.resolvePasswordCaptchaUrl(
|
const captchaUrl = await this.resolvePasswordCaptchaUrl(
|
||||||
container,
|
container,
|
||||||
loginStatus,
|
loginStatus,
|
||||||
@ -1363,6 +1367,45 @@ export class QqbotNapcatLoginService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async keepPasswordQrcodePending(
|
||||||
|
session: QqbotLoginScanSession,
|
||||||
|
container: QqbotNapcatRuntime,
|
||||||
|
loginStatus: NapcatLoginStatus,
|
||||||
|
) {
|
||||||
|
await this.clearRuntimeLoginPasswordAfterFailedPassword(
|
||||||
|
session,
|
||||||
|
container,
|
||||||
|
session.expectedSelfId,
|
||||||
|
);
|
||||||
|
this.publishScanResultEvent(
|
||||||
|
session,
|
||||||
|
'password-login-qrcode',
|
||||||
|
'processing',
|
||||||
|
'密码登录未完成,已切换到扫码确认',
|
||||||
|
);
|
||||||
|
session.qrcode = await this.refreshOrGetQrcode(container, true, {
|
||||||
|
fallbackStatus: loginStatus,
|
||||||
|
requireFresh: this.toolsService.isNapcatExpiredQrcodeStatus(loginStatus),
|
||||||
|
staleQrcode: loginStatus.qrcodeurl,
|
||||||
|
});
|
||||||
|
session.captchaUrl = undefined;
|
||||||
|
session.errorMessage = undefined;
|
||||||
|
session.expiresAt = Date.now() + this.getSessionTtlMs();
|
||||||
|
this.sessions.set(session.id, session);
|
||||||
|
this.publishScanResultEvent(
|
||||||
|
session,
|
||||||
|
'qrcode-ready',
|
||||||
|
'success',
|
||||||
|
'登录二维码已生成',
|
||||||
|
);
|
||||||
|
this.publishScanResultEvent(
|
||||||
|
session,
|
||||||
|
'waiting-scan',
|
||||||
|
'processing',
|
||||||
|
'等待扫码确认',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private async resolvePasswordCaptchaUrl(
|
private async resolvePasswordCaptchaUrl(
|
||||||
container: QqbotNapcatRuntime,
|
container: QqbotNapcatRuntime,
|
||||||
loginStatus: NapcatLoginStatus,
|
loginStatus: NapcatLoginStatus,
|
||||||
@ -1385,6 +1428,13 @@ export class QqbotNapcatLoginService {
|
|||||||
return this.toolsService.extractNapcatCaptchaUrl(status.loginError);
|
return this.toolsService.extractNapcatCaptchaUrl(status.loginError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isPasswordQrcodeChallenge(status: NapcatLoginStatus) {
|
||||||
|
return (
|
||||||
|
!!this.toolsService.toTrimmedString(status.qrcodeurl) ||
|
||||||
|
this.toolsService.isNapcatExpiredQrcodeStatus(status)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private async clearRuntimeLoginPasswordBeforeQuick(
|
private async clearRuntimeLoginPasswordBeforeQuick(
|
||||||
session: QqbotLoginScanSession,
|
session: QqbotLoginScanSession,
|
||||||
container: QqbotNapcatRuntime,
|
container: QqbotNapcatRuntime,
|
||||||
@ -1666,6 +1716,7 @@ export class QqbotNapcatLoginService {
|
|||||||
latestStatus = await this.getLoginStatus(container, true);
|
latestStatus = await this.getLoginStatus(container, true);
|
||||||
if (
|
if (
|
||||||
latestStatus.isLogin ||
|
latestStatus.isLogin ||
|
||||||
|
this.isPasswordQrcodeChallenge(latestStatus) ||
|
||||||
this.toolsService.isNapcatCaptchaRequiredMessage(
|
this.toolsService.isNapcatCaptchaRequiredMessage(
|
||||||
latestStatus.loginError,
|
latestStatus.loginError,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -132,15 +132,19 @@ export class QqbotNapcatContainerService {
|
|||||||
skipPull: true,
|
skipPull: true,
|
||||||
token: container.webuiToken,
|
token: container.webuiToken,
|
||||||
});
|
});
|
||||||
|
const verified = await this.runtimeMatchesLoginEnv(container.name, {
|
||||||
|
...options,
|
||||||
|
selfId: account,
|
||||||
|
});
|
||||||
await this.containerRepository.update(
|
await this.containerRepository.update(
|
||||||
{ id: container.id },
|
{ id: container.id },
|
||||||
{
|
{
|
||||||
lastError: null,
|
lastError: verified ? null : 'NapCat 运行态登录环境校验失败',
|
||||||
lastStartedAt: new Date(),
|
lastStartedAt: new Date(),
|
||||||
status: 'running',
|
status: 'running',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return { changed: true, ok: true };
|
return { changed: true, ok: verified };
|
||||||
} catch {
|
} catch {
|
||||||
return { changed: false, ok: false };
|
return { changed: false, ok: false };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -748,6 +748,162 @@ describe('QqbotNapcatLoginService', () => {
|
|||||||
expect(session.captchaUrl).toBe(captchaUrl);
|
expect(session.captchaUrl).toBe(captchaUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps qrcode pending when password login falls into NapCat qrcode status', async () => {
|
||||||
|
const container = {
|
||||||
|
baseUrl: 'http://127.0.0.1:6103/',
|
||||||
|
id: 'container-password-qrcode',
|
||||||
|
name: 'napcat-10001',
|
||||||
|
};
|
||||||
|
const containerService = {
|
||||||
|
ensureRuntimeLoginEnv: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce({ changed: false, ok: true })
|
||||||
|
.mockResolvedValueOnce({ changed: true, ok: true })
|
||||||
|
.mockResolvedValueOnce({ changed: true, ok: true }),
|
||||||
|
resetRuntimeLoginState: jest.fn().mockResolvedValue(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: '10',
|
||||||
|
QQBOT_NAPCAT_QUICK_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',
|
||||||
|
});
|
||||||
|
(refreshService as any).sessions.set(session.id, session);
|
||||||
|
jest
|
||||||
|
.spyOn((refreshService as any).toolsService, 'sleep')
|
||||||
|
.mockResolvedValue(undefined);
|
||||||
|
jest
|
||||||
|
.spyOn(refreshService as any, 'getLoginStatus')
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
isLogin: false,
|
||||||
|
loginError: '快速登录未找到历史会话',
|
||||||
|
})
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
isLogin: false,
|
||||||
|
loginError: '二维码已过期,请刷新',
|
||||||
|
qrcodeurl: 'expired-qrcode',
|
||||||
|
});
|
||||||
|
const refreshQrcode = jest
|
||||||
|
.spyOn(refreshService as any, 'refreshOrGetQrcode')
|
||||||
|
.mockResolvedValue('fresh-qrcode');
|
||||||
|
|
||||||
|
await (refreshService as any).prepareReloginQrcode(
|
||||||
|
session,
|
||||||
|
container,
|
||||||
|
'qq-password',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(containerService.resetRuntimeLoginState).not.toHaveBeenCalled();
|
||||||
|
expect(refreshQrcode).toHaveBeenCalledWith(
|
||||||
|
container,
|
||||||
|
true,
|
||||||
|
expect.objectContaining({
|
||||||
|
requireFresh: true,
|
||||||
|
staleQrcode: 'expired-qrcode',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(session.status).toBe('pending');
|
||||||
|
expect(session.captchaUrl).toBeUndefined();
|
||||||
|
expect(session.passwordMd5).toBeUndefined();
|
||||||
|
expect(session.qrcode).toBe('fresh-qrcode');
|
||||||
|
const steps = (
|
||||||
|
(refreshService as any).sessionEventLogs.get(session.id) ?? []
|
||||||
|
).map((event: { step: string }) => event.step);
|
||||||
|
expect(steps).toContain('password-login-qrcode');
|
||||||
|
expect(steps).not.toContain('relogin-reset-start');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('prioritizes current qrcode status over stale captcha URL in runtime logs', async () => {
|
||||||
|
const container = {
|
||||||
|
baseUrl: 'http://127.0.0.1:6103/',
|
||||||
|
id: 'container-password-qrcode-over-captcha-log',
|
||||||
|
name: 'napcat-10001',
|
||||||
|
};
|
||||||
|
const containerService = {
|
||||||
|
detectRuntimeCaptchaUrl: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(
|
||||||
|
'https://ti.qq.com/safe/tools/captcha/sms-verify-login?uin=10001',
|
||||||
|
),
|
||||||
|
ensureRuntimeLoginEnv: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce({ changed: false, ok: true })
|
||||||
|
.mockResolvedValueOnce({ changed: true, ok: true })
|
||||||
|
.mockResolvedValueOnce({ changed: true, ok: true }),
|
||||||
|
resetRuntimeLoginState: jest.fn().mockResolvedValue(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: '10',
|
||||||
|
};
|
||||||
|
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',
|
||||||
|
});
|
||||||
|
(refreshService as any).sessions.set(session.id, session);
|
||||||
|
jest
|
||||||
|
.spyOn((refreshService as any).toolsService, 'sleep')
|
||||||
|
.mockResolvedValue(undefined);
|
||||||
|
jest
|
||||||
|
.spyOn(refreshService as any, 'getLoginStatus')
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
isLogin: false,
|
||||||
|
loginError: '快速登录未找到历史会话',
|
||||||
|
})
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
isLogin: false,
|
||||||
|
loginError: '二维码已过期,请刷新',
|
||||||
|
qrcodeurl: 'expired-qrcode',
|
||||||
|
});
|
||||||
|
jest
|
||||||
|
.spyOn(refreshService as any, 'refreshOrGetQrcode')
|
||||||
|
.mockResolvedValue('fresh-qrcode');
|
||||||
|
|
||||||
|
await (refreshService as any).prepareReloginQrcode(
|
||||||
|
session,
|
||||||
|
container,
|
||||||
|
'qq-password',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(containerService.detectRuntimeCaptchaUrl).not.toHaveBeenCalled();
|
||||||
|
expect(session.status).toBe('pending');
|
||||||
|
expect(session.captchaUrl).toBeUndefined();
|
||||||
|
expect(session.qrcode).toBe('fresh-qrcode');
|
||||||
|
});
|
||||||
|
|
||||||
it('submits captcha result back to NapCat and completes password login', async () => {
|
it('submits captcha result back to NapCat and completes password login', async () => {
|
||||||
const accountService = {
|
const accountService = {
|
||||||
ensureScannedAccount: jest.fn().mockResolvedValue('account-1'),
|
ensureScannedAccount: jest.fn().mockResolvedValue('account-1'),
|
||||||
@ -964,6 +1120,42 @@ describe('QqbotNapcatLoginService', () => {
|
|||||||
expect(sleep).not.toHaveBeenCalled();
|
expect(sleep).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns qrcode status immediately without waiting full password window', async () => {
|
||||||
|
const refreshService = new QqbotNapcatLoginService(
|
||||||
|
{
|
||||||
|
get: jest.fn((key: string) => {
|
||||||
|
const values: Record<string, string> = {
|
||||||
|
QQBOT_NAPCAT_LOGIN_POLL_INTERVAL_MS: '1000',
|
||||||
|
QQBOT_NAPCAT_PASSWORD_LOGIN_WAIT_MS: '3000',
|
||||||
|
};
|
||||||
|
return values[key] || '';
|
||||||
|
}),
|
||||||
|
} as unknown as ConfigService,
|
||||||
|
{} as QqbotAccountService,
|
||||||
|
{} as QqbotNapcatContainerService,
|
||||||
|
new ToolsService(),
|
||||||
|
);
|
||||||
|
const getLoginStatus = jest
|
||||||
|
.spyOn(refreshService as any, 'getLoginStatus')
|
||||||
|
.mockResolvedValue({
|
||||||
|
isLogin: false,
|
||||||
|
loginError: '二维码已过期,请刷新',
|
||||||
|
qrcodeurl: 'expired-qrcode',
|
||||||
|
});
|
||||||
|
const sleep = jest.spyOn((refreshService as any).toolsService, 'sleep');
|
||||||
|
|
||||||
|
const status = await (refreshService as any).waitForPasswordLoginStatus({
|
||||||
|
baseUrl: 'http://127.0.0.1:6103/',
|
||||||
|
id: 'container-qrcode-early',
|
||||||
|
name: 'napcat-10001',
|
||||||
|
webuiToken: 'token',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status.qrcodeurl).toBe('expired-qrcode');
|
||||||
|
expect(getLoginStatus).toHaveBeenCalledTimes(1);
|
||||||
|
expect(sleep).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('does not keep stale captcha pending after captcha submit returns non-captcha failure', async () => {
|
it('does not keep stale captcha pending after captcha submit returns non-captcha failure', async () => {
|
||||||
const container = {
|
const container = {
|
||||||
baseUrl: 'http://127.0.0.1:6103/',
|
baseUrl: 'http://127.0.0.1:6103/',
|
||||||
|
|||||||
@ -418,7 +418,11 @@ describe('QqbotNapcatContainerService', () => {
|
|||||||
service.runProcess = jest
|
service.runProcess = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockRejectedValueOnce(new Error('inspect failed'))
|
.mockRejectedValueOnce(new Error('inspect failed'))
|
||||||
.mockResolvedValueOnce({ stderr: '', stdout: '' });
|
.mockResolvedValueOnce({ stderr: '', stdout: '' })
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
stderr: '',
|
||||||
|
stdout: 'ACCOUNT=2354598417\nNAPCAT_QUICK_PASSWORD=qq-password\n',
|
||||||
|
});
|
||||||
|
|
||||||
const recreated = await service.ensureRuntimeLoginEnv(
|
const recreated = await service.ensureRuntimeLoginEnv(
|
||||||
{ id: 'container-1', name: 'kt-qqbot-napcat-x' },
|
{ id: 'container-1', name: 'kt-qqbot-napcat-x' },
|
||||||
@ -429,7 +433,7 @@ describe('QqbotNapcatContainerService', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(recreated).toEqual({ changed: true, ok: true });
|
expect(recreated).toEqual({ changed: true, ok: true });
|
||||||
expect(service.runProcess).toHaveBeenCalledTimes(2);
|
expect(service.runProcess).toHaveBeenCalledTimes(3);
|
||||||
expect(service.runProcess.mock.calls[1][2]).toContain(
|
expect(service.runProcess.mock.calls[1][2]).toContain(
|
||||||
"NAPCAT_QUICK_PASSWORD='qq-password'",
|
"NAPCAT_QUICK_PASSWORD='qq-password'",
|
||||||
);
|
);
|
||||||
@ -466,7 +470,11 @@ describe('QqbotNapcatContainerService', () => {
|
|||||||
service.runProcess = jest
|
service.runProcess = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockResolvedValueOnce({ stderr: '', stdout: 'ACCOUNT=2354598417\n' })
|
.mockResolvedValueOnce({ stderr: '', stdout: 'ACCOUNT=2354598417\n' })
|
||||||
.mockResolvedValueOnce({ stderr: '', stdout: '' });
|
.mockResolvedValueOnce({ stderr: '', stdout: '' })
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
stderr: '',
|
||||||
|
stdout: 'ACCOUNT=2354598417\nNAPCAT_QUICK_PASSWORD=qq-password\n',
|
||||||
|
});
|
||||||
|
|
||||||
const recreated = await service.ensureRuntimeLoginEnv(
|
const recreated = await service.ensureRuntimeLoginEnv(
|
||||||
{ id: 'container-1', name: 'kt-qqbot-napcat-x' },
|
{ id: 'container-1', name: 'kt-qqbot-napcat-x' },
|
||||||
@ -477,7 +485,7 @@ describe('QqbotNapcatContainerService', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(recreated).toEqual({ changed: true, ok: true });
|
expect(recreated).toEqual({ changed: true, ok: true });
|
||||||
expect(service.runProcess).toHaveBeenCalledTimes(2);
|
expect(service.runProcess).toHaveBeenCalledTimes(3);
|
||||||
expect(service.runProcess.mock.calls[1][2]).toContain(
|
expect(service.runProcess.mock.calls[1][2]).toContain(
|
||||||
"NAPCAT_QUICK_PASSWORD='qq-password'",
|
"NAPCAT_QUICK_PASSWORD='qq-password'",
|
||||||
);
|
);
|
||||||
@ -490,6 +498,59 @@ describe('QqbotNapcatContainerService', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fails login env preparation when recreated container still misses password env', async () => {
|
||||||
|
const containerRepository = {
|
||||||
|
createQueryBuilder: jest.fn(() => ({
|
||||||
|
addSelect: jest.fn().mockReturnThis(),
|
||||||
|
andWhere: jest.fn().mockReturnThis(),
|
||||||
|
getOne: jest.fn().mockResolvedValue({
|
||||||
|
dataDir: '/vol1/docker/kt-qqbot/napcat-instances/kt-qqbot-napcat-x',
|
||||||
|
id: 'container-1',
|
||||||
|
image: 'mlikiowa/napcat-docker:latest',
|
||||||
|
name: 'kt-qqbot-napcat-x',
|
||||||
|
reverseWsUrl: 'ws://127.0.0.1:48085/qqbot/onebot/reverse',
|
||||||
|
webuiPort: 6100,
|
||||||
|
webuiToken: 'token-x',
|
||||||
|
}),
|
||||||
|
where: jest.fn().mockReturnThis(),
|
||||||
|
})),
|
||||||
|
update: jest.fn(),
|
||||||
|
};
|
||||||
|
const service = new QqbotNapcatContainerService(
|
||||||
|
{
|
||||||
|
get: jest.fn((key: string) =>
|
||||||
|
key === 'QQBOT_NAPCAT_CONTAINER_MODE' ? 'ssh' : '',
|
||||||
|
),
|
||||||
|
} as any,
|
||||||
|
containerRepository as any,
|
||||||
|
{} as any,
|
||||||
|
new ToolsService(),
|
||||||
|
) as any;
|
||||||
|
service.runProcess = jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce({ stderr: '', stdout: 'ACCOUNT=2354598417\n' })
|
||||||
|
.mockResolvedValueOnce({ stderr: '', stdout: '' })
|
||||||
|
.mockResolvedValueOnce({ stderr: '', stdout: 'ACCOUNT=2354598417\n' });
|
||||||
|
|
||||||
|
const recreated = await service.ensureRuntimeLoginEnv(
|
||||||
|
{ id: 'container-1', name: 'kt-qqbot-napcat-x' },
|
||||||
|
{
|
||||||
|
loginPassword: 'qq-password',
|
||||||
|
selfId: '2354598417',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(recreated).toEqual({ changed: true, ok: false });
|
||||||
|
expect(service.runProcess).toHaveBeenCalledTimes(3);
|
||||||
|
expect(containerRepository.update).toHaveBeenCalledWith(
|
||||||
|
{ id: 'container-1' },
|
||||||
|
expect.objectContaining({
|
||||||
|
lastError: 'NapCat 运行态登录环境校验失败',
|
||||||
|
status: 'running',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('removes password env for a quick-login-only runtime stage', async () => {
|
it('removes password env for a quick-login-only runtime stage', async () => {
|
||||||
const containerRepository = {
|
const containerRepository = {
|
||||||
createQueryBuilder: jest.fn(() => ({
|
createQueryBuilder: jest.fn(() => ({
|
||||||
@ -524,7 +585,8 @@ describe('QqbotNapcatContainerService', () => {
|
|||||||
stderr: '',
|
stderr: '',
|
||||||
stdout: 'ACCOUNT=2354598417\nNAPCAT_QUICK_PASSWORD=old-password\n',
|
stdout: 'ACCOUNT=2354598417\nNAPCAT_QUICK_PASSWORD=old-password\n',
|
||||||
})
|
})
|
||||||
.mockResolvedValueOnce({ stderr: '', stdout: '' });
|
.mockResolvedValueOnce({ stderr: '', stdout: '' })
|
||||||
|
.mockResolvedValueOnce({ stderr: '', stdout: 'ACCOUNT=2354598417\n' });
|
||||||
|
|
||||||
const recreated = await service.ensureRuntimeLoginEnv(
|
const recreated = await service.ensureRuntimeLoginEnv(
|
||||||
{ id: 'container-1', name: 'kt-qqbot-napcat-x' },
|
{ id: 'container-1', name: 'kt-qqbot-napcat-x' },
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user