Files
go_bt/tests/security_combo_skip_matrix.test.js
T

130 lines
4.8 KiB
JavaScript

'use strict';
const assert = require('assert');
const screenshotPath = require.resolve('../src/utils/screenshot');
const screenshotModule = require(screenshotPath);
const originalSaveErrorScreenshot = screenshotModule.saveErrorScreenshot;
screenshotModule.saveErrorScreenshot = async () => null;
const passwordService = require('../src/services/change_password_service');
const twofaService = require('../src/services/change_2fa_service');
const originalPasswordService = passwordService.changePasswordForAccount;
const originalTwofaService = twofaService.change2faForAccount;
let passwordCalls = 0;
let twofaCalls = 0;
passwordService.changePasswordForAccount = async () => {
passwordCalls++;
return [true, '密码更改成功', 'NEW_PASSWORD'];
};
twofaService.change2faForAccount = async () => {
twofaCalls++;
return [true, '2FA密钥更改成功', 'NEW_2FA_KEY'];
};
const passwordStepPath = require.resolve('../src/pipeline/steps/change_password');
const twofaStepPath = require.resolve('../src/pipeline/steps/change_2fa');
delete require.cache[passwordStepPath];
delete require.cache[twofaStepPath];
const changePasswordStep = require(passwordStepPath);
const change2faStep = require(twofaStepPath);
function makeContext(flags, { skip = true, taskType = 'security_chatgpt', missingAccount = false } = {}) {
const state = {
email: 'matrix@example.com',
password: 'CURRENT_PASSWORD',
secret_key: 'CURRENT_2FA_KEY',
password_changed: 0,
fa_changed: 0,
...flags,
};
const statuses = [];
const messages = [];
const ctx = {
account: { ...state },
page: { url: () => 'https://myaccount.google.com/' },
taskType,
params: { skipCompletedSecuritySteps: skip },
log: () => {},
results: {},
shouldStop: false,
keepBrowserOpen: false,
dbWrite: async (name, args) => {
if (name === 'getSetting') return args[1];
if (name === 'getAccount') return missingAccount ? null : { ...state };
if (name === 'updateAccountPassword') {
state.password = args[1];
state.password_changed = 1;
}
if (name === 'updateAccount2faKey') {
state.secret_key = args[1];
state.fa_changed = 1;
}
if (name === 'updateAccountFlag') state[args[1]] = args[2];
return true;
},
updateStatus: async (_email, status) => statuses.push(status),
updateMessage: async (_email, message) => messages.push(message),
};
return { ctx, state, statuses, messages };
}
async function runCombo(flags, skip = true) {
passwordCalls = 0;
twofaCalls = 0;
const run = makeContext(flags, { skip });
await changePasswordStep(run.ctx);
if (!run.ctx.shouldStop) await change2faStep(run.ctx);
return { ...run, passwordCalls, twofaCalls };
}
(async () => {
try {
let run = await runCombo({ password_changed: 0, fa_changed: 0 });
assert.deepStrictEqual([run.passwordCalls, run.twofaCalls], [1, 1], '00应执行改密和2FA');
run = await runCombo({ password_changed: 1, fa_changed: 0 });
assert.deepStrictEqual([run.passwordCalls, run.twofaCalls], [0, 1], '10应只执行2FA');
run = await runCombo({ password_changed: 0, fa_changed: 1 });
assert.deepStrictEqual([run.passwordCalls, run.twofaCalls], [1, 0], '01应只执行改密');
run = await runCombo({ password_changed: 1, fa_changed: 1 });
assert.deepStrictEqual([run.passwordCalls, run.twofaCalls], [0, 0], '11应两项都跳过');
assert.strictEqual(run.statuses.at(-1), '未验证已改密和2FA');
assert.match(run.messages.at(-1), /密码和2FA均已修改/);
run = await runCombo({ password_changed: 1, fa_changed: 1 }, false);
assert.deepStrictEqual([run.passwordCalls, run.twofaCalls], [1, 1], '覆盖模式必须无视完成标记');
passwordCalls = 0;
let standalone = makeContext({ password_changed: 1 }, { taskType: 'change_password', skip: true });
await changePasswordStep(standalone.ctx);
assert.strictEqual(passwordCalls, 1, '单独改密码必须保持原行为');
twofaCalls = 0;
standalone = makeContext({ fa_changed: 1 }, { taskType: 'change_2fa', skip: true });
await change2faStep(standalone.ctx);
assert.strictEqual(twofaCalls, 1, '单独改2FA必须保持原行为');
passwordCalls = 0;
const missing = makeContext({}, { missingAccount: true });
await assert.rejects(
() => changePasswordStep(missing.ctx),
/停止以避免重复修改/,
'跳过模式读取不到数据库账号时必须停止,不能盲目覆盖',
);
assert.strictEqual(passwordCalls, 0);
console.log('security_combo_skip_matrix.test.js: PASS');
} finally {
passwordService.changePasswordForAccount = originalPasswordService;
twofaService.change2faForAccount = originalTwofaService;
screenshotModule.saveErrorScreenshot = originalSaveErrorScreenshot;
}
})().catch(error => {
console.error(error);
process.exitCode = 1;
});