161 lines
7.5 KiB
JavaScript
161 lines
7.5 KiB
JavaScript
const assert = require('assert');
|
|
|
|
const {
|
|
classifyFailure,
|
|
getFailureLabel,
|
|
isOAuthWait7DaysOutcome,
|
|
resolveFailureOutcome,
|
|
} = require('../src/utils/error_classifier');
|
|
const { detectOAuthReauthProblem } = require('../src/services/ag_verify_service');
|
|
|
|
function codeFor(message, url = '') {
|
|
return classifyFailure({ message, url }).code;
|
|
}
|
|
|
|
assert.strictEqual(codeFor('密码错误'), 'PASSWORD_WRONG');
|
|
assert.strictEqual(codeFor('Your password was changed 10 days ago'), 'PASSWORD_CHANGED_RECENTLY');
|
|
assert.strictEqual(codeFor('需要 2FA 验证但未提供密钥'), 'TOTP_KEY_INVALID');
|
|
assert.strictEqual(codeFor('Wrong code. Try again.'), 'TOTP_KEY_INCORRECT');
|
|
assert.strictEqual(codeFor('2fa密钥不正确'), 'TOTP_KEY_INCORRECT');
|
|
assert.strictEqual(codeFor('触发人机认证'), 'CAPTCHA');
|
|
assert.strictEqual(codeFor('Please try again later'), 'UNKNOWN', '普通 try again 不得误归2FA错误');
|
|
assert.strictEqual(codeFor('密码近期已更改'), 'PASSWORD_CHANGED_RECENTLY');
|
|
assert.strictEqual(codeFor('OAuth 暂无2FA认证选项'), 'OAUTH_WAIT_7_DAYS');
|
|
assert.strictEqual(codeFor('验证方式列表中没有 Google Authenticator 选项'), 'TOTP_OPTION_UNAVAILABLE');
|
|
assert.strictEqual(codeFor('需要辅助邮箱验证但未提供'), 'RECOVERY_EMAIL_REQUIRED');
|
|
assert.strictEqual(codeFor('需要备用码验证,且页面无法切换到 Google Authenticator'), 'BACKUP_CODE_REQUIRED');
|
|
assert.strictEqual(codeFor('Google拒绝本次登录', 'https://accounts.google.com/signin/rejected'), 'SIGNIN_REJECTED');
|
|
assert.strictEqual(
|
|
classifyFailure({ url: 'https://accounts.google.com/signin/rejected', message: 'Google拒绝本次登录' }).shouldRotateProxy,
|
|
true,
|
|
'signin/rejected 应触发自动更换代理后重试',
|
|
);
|
|
|
|
// 账号列表统一使用处理结论,避免同一类问题出现多种可见文案。
|
|
assert.strictEqual(classifyFailure({ message: '密码错误' }).label, '密码错误');
|
|
assert.strictEqual(classifyFailure({ message: 'Your password was changed 10 days ago' }).label, '密码已被修改');
|
|
assert.strictEqual(classifyFailure({ message: 'Your password was changed 10 days ago' }).shouldKeepOpen, false);
|
|
assert.strictEqual(classifyFailure({ message: 'Your password was changed 10 days ago' }).shouldRotateProxy, false);
|
|
assert.strictEqual(classifyFailure({ message: 'Wrong code. Try again.' }).label, '2fa密钥不正确');
|
|
assert.strictEqual(classifyFailure({ message: 'Wrong code. Try again.' }).shouldKeepOpen, false);
|
|
assert.strictEqual(classifyFailure({ message: 'Wrong code. Try again.' }).shouldRotateProxy, false);
|
|
assert.strictEqual(classifyFailure({ message: "Confirm you're not a robot" }).label, '人机验证');
|
|
assert.strictEqual(getFailureLabel('CAPTCHA'), '人机验证');
|
|
assert.strictEqual(getFailureLabel('PHONE_TABLET_VERIFY'), '要等7天');
|
|
assert.strictEqual(getFailureLabel('CHATGPT_ACCOUNT_DEACTIVATED'), '账号已删除/停用');
|
|
assert.strictEqual(
|
|
classifyFailure({ message: 'You do not have an account because it has been deleted or deactivated.' }).label,
|
|
'账号已删除/停用',
|
|
);
|
|
assert.strictEqual(
|
|
classifyFailure({ message: '需手机/平板验证' }).code,
|
|
'PHONE_TABLET_VERIFY',
|
|
);
|
|
assert.strictEqual(
|
|
classifyFailure({ message: '需手机/平板验证' }).label,
|
|
'要等7天',
|
|
);
|
|
assert.strictEqual(isOAuthWait7DaysOutcome('PHONE_TABLET_VERIFY'), true);
|
|
assert.strictEqual(classifyFailure({ message: '检测到风险登录,无法登录' }).label, '无法登录');
|
|
assert.strictEqual(classifyFailure({ message: 'net::ERR_CONNECTION_TIMED_OUT' }).label, '切换ip重试');
|
|
assert.strictEqual(classifyFailure({ message: '测速失败' }).label, '切换ip重试');
|
|
assert.strictEqual(
|
|
classifyFailure({ message: 'OAuth身份验证页面无法切换到其它方式:/v3/signin/challenge/dp' }).label,
|
|
'要等7天',
|
|
'OAuth 验证方式卡在 dp challenge 时应直接归入等待7天',
|
|
);
|
|
assert.strictEqual(
|
|
codeFor('OAuth身份验证页面无法切换到其它方式:/v3/signin/challenge/dp'),
|
|
'OAUTH_CHALLENGE_STUCK',
|
|
);
|
|
assert.strictEqual(getFailureLabel('OAUTH_CHALLENGE_STUCK'), '要等7天');
|
|
assert.strictEqual(getFailureLabel('GCP_NO_PERMISSION'), '无权限');
|
|
assert.strictEqual(getFailureLabel('GOOGLE_UNDER_18'), '未满18岁');
|
|
assert.strictEqual(classifyFailure({ message: 'OAuth授权超时' }).label, '要等7天');
|
|
assert.strictEqual(isOAuthWait7DaysOutcome('OAUTH_NO_AUTHENTICATOR'), true);
|
|
assert.strictEqual(isOAuthWait7DaysOutcome('OAUTH_CHALLENGE_STUCK'), true);
|
|
assert.strictEqual(isOAuthWait7DaysOutcome('OAUTH_TIMEOUT'), true);
|
|
assert.strictEqual(isOAuthWait7DaysOutcome('NETWORK_PROXY'), false);
|
|
assert.strictEqual(
|
|
isOAuthWait7DaysOutcome('TOKEN_EXCHANGE_FAILED', { message: 'network timeout' }),
|
|
false,
|
|
'Token 网络失败不得误进等待7天分组',
|
|
);
|
|
assert.strictEqual(classifyFailure({ message: 'OAuth token exchange network error' }).label, '切换ip重试');
|
|
assert.strictEqual(
|
|
resolveFailureOutcome({
|
|
code: 'OAUTH_CHALLENGE_STUCK',
|
|
message: 'OAuth身份验证页面无法切换到其它方式:/v3/signin/challenge/dp',
|
|
}).displayMessage,
|
|
'要等7天',
|
|
);
|
|
|
|
function fakeOAuthPage({ url = 'https://accounts.google.com/signin/challenge/pwd', body = '', frameBox = null, frameBoxes = null } = {}) {
|
|
const boxes = frameBoxes || (frameBox ? [frameBox] : []);
|
|
return {
|
|
url: () => url,
|
|
locator: selector => {
|
|
if (selector === 'body') {
|
|
return { innerText: async () => body };
|
|
}
|
|
return {
|
|
count: async () => boxes.length,
|
|
nth: index => ({
|
|
isVisible: async () => !!boxes[index],
|
|
boundingBox: async () => boxes[index] || null,
|
|
}),
|
|
};
|
|
},
|
|
};
|
|
}
|
|
|
|
(async () => {
|
|
let result = await detectOAuthReauthProblem(fakeOAuthPage({ body: 'Wrong password. Try again.' }), {
|
|
passwordSubmitted: false,
|
|
});
|
|
assert.strictEqual(result, null, '提交前不得只凭页面文字判密码错误');
|
|
|
|
result = await detectOAuthReauthProblem(fakeOAuthPage({ body: 'Wrong password. Try again.' }), {
|
|
passwordSubmitted: true,
|
|
});
|
|
assert.deepStrictEqual(result, { reasonCode: 'PASSWORD_WRONG', msg: '密码错误' });
|
|
|
|
result = await detectOAuthReauthProblem(fakeOAuthPage({ body: 'Forgot password? Please try again.' }), {
|
|
passwordSubmitted: true,
|
|
});
|
|
assert.strictEqual(result, null, '普通忘记密码/重试文字不得误判');
|
|
|
|
result = await detectOAuthReauthProblem(fakeOAuthPage({
|
|
url: 'https://accounts.google.com/o/oauth2/auth',
|
|
body: 'This site is protected by reCAPTCHA and the Google Privacy Policy.',
|
|
frameBox: { width: 70, height: 60 },
|
|
}));
|
|
assert.strictEqual(result, null, '正常 reCAPTCHA 条款和小徽标不得误报人机验证');
|
|
|
|
result = await detectOAuthReauthProblem(fakeOAuthPage({
|
|
url: 'https://accounts.google.com/o/oauth2/auth',
|
|
frameBoxes: [{ width: 70, height: 60 }, { width: 320, height: 120 }],
|
|
}));
|
|
assert.deepStrictEqual(
|
|
result,
|
|
{ reasonCode: 'CAPTCHA', msg: '触发人机验证' },
|
|
'小徽标之后的真挑战框不得被漏掉',
|
|
);
|
|
|
|
result = await detectOAuthReauthProblem(fakeOAuthPage({
|
|
url: 'https://accounts.google.com/o/oauth2/auth',
|
|
body: 'Verify you are not a robot',
|
|
}));
|
|
assert.deepStrictEqual(result, { reasonCode: 'CAPTCHA', msg: '触发人机验证' });
|
|
|
|
result = await detectOAuthReauthProblem(fakeOAuthPage({
|
|
url: 'https://accounts.google.com/signin/challenge/recaptcha',
|
|
}));
|
|
assert.deepStrictEqual(result, { reasonCode: 'CAPTCHA', msg: '触发人机验证' });
|
|
|
|
console.log('problem_reason_classification.test.js: PASS');
|
|
})().catch(error => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
});
|