130 lines
4.8 KiB
JavaScript
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;
|
|
});
|