修改登陆及后续逻辑,统一使用一个逻辑

This commit is contained in:
QLHazyCoder
2026-04-26 05:22:36 +08:00
parent ef52ff806b
commit 88ceb79af6
21 changed files with 868 additions and 370 deletions
+204 -274
View File
@@ -1803,6 +1803,13 @@ function inspectLoginAuthState() {
};
}
if (consentReady) {
return {
...baseState,
state: 'oauth_consent_page',
};
}
return baseState;
}
@@ -1830,7 +1837,7 @@ function serializeLoginAuthState(snapshot) {
}
function getLoginAuthStateLabel(snapshot) {
const state = snapshot?.state === 'oauth_consent_page' ? 'unknown' : snapshot?.state;
const state = snapshot?.state;
switch (state) {
case 'verification_page':
return '登录验证码页';
@@ -1887,13 +1894,32 @@ async function waitForLoginVerificationPageReady(timeout = 10000) {
}
function createStep6SuccessResult(snapshot, options = {}) {
return {
const result = {
step6Outcome: 'success',
state: snapshot?.state || 'verification_page',
url: snapshot?.url || location.href,
via: options.via || '',
loginVerificationRequestedAt: options.loginVerificationRequestedAt || null,
};
if (options.skipLoginVerificationStep) {
result.skipLoginVerificationStep = true;
}
if (options.directOAuthConsentPage) {
result.directOAuthConsentPage = true;
}
return result;
}
function createStep6OAuthConsentSuccessResult(snapshot, options = {}) {
return createStep6SuccessResult(snapshot, {
...options,
via: options.via || 'oauth_consent_page',
loginVerificationRequestedAt: null,
skipLoginVerificationStep: true,
directOAuthConsentPage: true,
});
}
function createStep6RecoverableResult(reason, snapshot, options = {}) {
@@ -1948,6 +1974,15 @@ async function createStep6LoginTimeoutRecoveryTransition(reason, snapshot, messa
};
}
if (resolvedSnapshot.state === 'oauth_consent_page') {
return {
action: 'done',
result: createStep6OAuthConsentSuccessResult(resolvedSnapshot, {
via,
}),
};
}
if (resolvedSnapshot.state === 'password_page') {
log('步骤 7:登录超时报错页恢复后已进入密码页,继续当前登录流程。', 'warn');
return { action: 'password', snapshot: resolvedSnapshot };
@@ -2007,6 +2042,13 @@ async function finalizeStep6VerificationReady(options = {}) {
});
}
if (snapshot.state === 'oauth_consent_page') {
log(`${logLabel}:认证页已直接进入 OAuth 授权页,跳过登录验证码步骤。`, 'ok');
return createStep6OAuthConsentSuccessResult(snapshot, {
via: `${via}_oauth_consent`,
});
}
if (snapshot.state === 'login_timeout_error_page') {
log(`${logLabel}:页面进入登录超时报错页,准备自动恢复后重试步骤 7。`, 'warn');
return createStep6LoginTimeoutRecoverableResult(
@@ -2037,6 +2079,12 @@ async function finalizeStep6VerificationReady(options = {}) {
loginVerificationRequestedAt,
});
}
if (snapshot.state === 'oauth_consent_page') {
log(`${logLabel}:认证页已直接进入 OAuth 授权页,跳过登录验证码步骤。`, 'ok');
return createStep6OAuthConsentSuccessResult(snapshot, {
via: `${via}_oauth_consent`,
});
}
if (snapshot.state === 'login_timeout_error_page') {
log(`${logLabel}:页面进入登录超时报错页,准备自动恢复后重试步骤 7。`, 'warn');
return createStep6LoginTimeoutRecoverableResult(
@@ -2059,21 +2107,14 @@ async function finalizeStep6VerificationReady(options = {}) {
}
function normalizeStep6Snapshot(snapshot) {
if (snapshot?.state !== 'oauth_consent_page') {
return snapshot;
}
return {
...snapshot,
state: 'unknown',
};
return snapshot;
}
function throwForStep6FatalState(snapshot) {
snapshot = normalizeStep6Snapshot(snapshot);
switch (snapshot?.state) {
case 'oauth_consent_page':
throw new Error(`当前页面已进入 OAuth 授权页,未经过登录验证码页,无法完成步骤 7。URL: ${snapshot.url}`);
return;
case 'add_phone_page':
throw new Error(`当前页面已进入手机号页面,未经过登录验证码页,无法完成步骤 7。URL: ${snapshot.url}`);
case 'unknown':
@@ -2595,88 +2636,55 @@ async function fillVerificationCode(step, payload) {
// Step 7: Login with registered account (on OAuth auth page)
// ============================================================
async function waitForStep6EmailSubmitTransition(emailSubmittedAt, timeout = 12000) {
const start = Date.now();
let snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
function getStep6OptionMessage(value, snapshot) {
return typeof value === 'function' ? value(snapshot) : String(value || '');
}
while (Date.now() - start < timeout) {
throwIfStopped();
snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
async function resolveStep6PostSubmitSnapshot(snapshot, options = {}) {
const normalizedSnapshot = normalizeStep6Snapshot(snapshot || inspectLoginAuthState());
const {
via = 'post_submit',
loginVerificationRequestedAt = null,
oauthConsentVia = `${via}_oauth_consent`,
timeoutRecoveryReason = 'login_timeout_error_page',
timeoutRecoveryMessage = '登录提交后进入登录超时报错页。',
timeoutRecoveryVia = `${via}_timeout_recovered`,
allowPasswordAction = false,
allowEmailAction = false,
allowFinalPasswordAction = false,
allowFinalEmailAction = false,
allowFinalSwitchAction = false,
final = false,
addPhoneMessage,
} = options;
if (snapshot.state === 'verification_page') {
return {
action: 'done',
result: createStep6SuccessResult(snapshot, {
via: 'email_submit',
loginVerificationRequestedAt: emailSubmittedAt,
}),
};
}
if (snapshot.state === 'password_page') {
return { action: 'password', snapshot };
}
if (snapshot.state === 'login_timeout_error_page') {
const transition = await createStep6LoginTimeoutRecoveryTransition(
'login_timeout_error_page',
snapshot,
'提交邮箱后进入登录超时报错页。',
{
loginVerificationRequestedAt: emailSubmittedAt,
via: 'email_submit_timeout_recovered',
}
);
if (transition.action === 'done') {
return {
action: 'done',
result: transition.result,
};
}
if (transition.action === 'password') {
return { action: 'password', snapshot: transition.snapshot };
}
if (transition.action === 'email') {
return { action: 'email', snapshot: transition.snapshot };
}
return {
action: 'recoverable',
result: transition.result,
};
}
if (snapshot.state === 'oauth_consent_page') {
throw new Error(`提交邮箱后页面直接进入 OAuth 授权页,未经过登录验证码页。URL: ${snapshot.url}`);
}
if (snapshot.state === 'add_phone_page') {
throw new Error(`提交邮箱后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`);
}
await sleep(250);
}
snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
if (snapshot.state === 'verification_page') {
if (normalizedSnapshot.state === 'verification_page') {
return {
action: 'done',
result: createStep6SuccessResult(snapshot, {
via: 'email_submit',
loginVerificationRequestedAt: emailSubmittedAt,
result: createStep6SuccessResult(normalizedSnapshot, {
via,
loginVerificationRequestedAt,
}),
};
}
if (snapshot.state === 'password_page') {
return { action: 'password', snapshot };
if (normalizedSnapshot.state === 'oauth_consent_page') {
return {
action: 'done',
result: createStep6OAuthConsentSuccessResult(normalizedSnapshot, {
via: oauthConsentVia,
}),
};
}
if (snapshot.state === 'login_timeout_error_page') {
if (normalizedSnapshot.state === 'login_timeout_error_page') {
const transition = await createStep6LoginTimeoutRecoveryTransition(
'login_timeout_error_page',
snapshot,
'提交邮箱后进入登录超时报错页。',
timeoutRecoveryReason,
normalizedSnapshot,
timeoutRecoveryMessage,
{
loginVerificationRequestedAt: emailSubmittedAt,
via: 'email_submit_timeout_recovered',
loginVerificationRequestedAt,
via: timeoutRecoveryVia,
}
);
if (transition.action === 'done') {
@@ -2696,213 +2704,116 @@ async function waitForStep6EmailSubmitTransition(emailSubmittedAt, timeout = 120
result: transition.result,
};
}
if (snapshot.state === 'oauth_consent_page') {
throw new Error(`提交邮箱后页面直接进入 OAuth 授权页,未经过登录验证码页。URL: ${snapshot.url}`);
if (normalizedSnapshot.state === 'password_page') {
if (allowPasswordAction || (final && allowFinalPasswordAction)) {
return { action: 'password', snapshot: normalizedSnapshot };
}
if (final && allowFinalSwitchAction && normalizedSnapshot.switchTrigger) {
return { action: 'switch', snapshot: normalizedSnapshot };
}
}
if (snapshot.state === 'add_phone_page') {
throw new Error(`提交邮箱后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`);
if (normalizedSnapshot.state === 'email_page' && (allowEmailAction || (final && allowFinalEmailAction))) {
return { action: 'email', snapshot: normalizedSnapshot };
}
if (normalizedSnapshot.state === 'add_phone_page') {
const message = getStep6OptionMessage(addPhoneMessage, normalizedSnapshot)
|| `登录提交后页面进入手机号页面。URL: ${normalizedSnapshot.url || location.href}`;
throw new Error(message);
}
return null;
}
async function waitForStep6PostSubmitTransition(options = {}) {
const {
timeout = 10000,
stalledReason = 'post_submit_stalled',
stalledMessage = '登录提交后未进入可识别的下一页。',
} = options;
const start = Date.now();
let snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
while (Date.now() - start < timeout) {
throwIfStopped();
snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
const transition = await resolveStep6PostSubmitSnapshot(snapshot, {
...options,
final: false,
});
if (transition) {
return transition;
}
await sleep(250);
}
snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
const transition = await resolveStep6PostSubmitSnapshot(snapshot, {
...options,
final: true,
});
if (transition) {
return transition;
}
return {
action: 'recoverable',
result: createStep6RecoverableResult('email_submit_stalled', snapshot, {
message: '提交邮箱后长时间未进入密码页或登录验证码页。',
result: createStep6RecoverableResult(stalledReason, snapshot, {
message: stalledMessage,
loginVerificationRequestedAt: options.loginVerificationRequestedAt || null,
}),
};
}
async function waitForStep6EmailSubmitTransition(emailSubmittedAt, timeout = 12000) {
return waitForStep6PostSubmitTransition({
timeout,
via: 'email_submit',
oauthConsentVia: 'email_submit_oauth_consent',
loginVerificationRequestedAt: emailSubmittedAt,
timeoutRecoveryMessage: '提交邮箱后进入登录超时报错页。',
timeoutRecoveryVia: 'email_submit_timeout_recovered',
allowPasswordAction: true,
stalledReason: 'email_submit_stalled',
stalledMessage: '提交邮箱后长时间未进入密码页或登录验证码页。',
addPhoneMessage: (snapshot) => `提交邮箱后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`,
});
}
async function waitForStep6PasswordSubmitTransition(passwordSubmittedAt, timeout = 10000) {
const start = Date.now();
let snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
while (Date.now() - start < timeout) {
throwIfStopped();
snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
if (snapshot.state === 'verification_page') {
return {
action: 'done',
result: createStep6SuccessResult(snapshot, {
via: 'password_submit',
loginVerificationRequestedAt: passwordSubmittedAt,
}),
};
}
if (snapshot.state === 'login_timeout_error_page') {
const transition = await createStep6LoginTimeoutRecoveryTransition(
'login_timeout_error_page',
snapshot,
'提交密码后进入登录超时报错页。',
{
loginVerificationRequestedAt: passwordSubmittedAt,
via: 'password_submit_timeout_recovered',
}
);
if (transition.action === 'done') {
return {
action: 'done',
result: transition.result,
};
}
if (transition.action === 'password') {
return { action: 'password', snapshot: transition.snapshot };
}
if (transition.action === 'email') {
return { action: 'email', snapshot: transition.snapshot };
}
return {
action: 'recoverable',
result: transition.result,
};
}
if (snapshot.state === 'oauth_consent_page') {
throw new Error(`提交密码后页面直接进入 OAuth 授权页,未经过登录验证码页。URL: ${snapshot.url}`);
}
if (snapshot.state === 'add_phone_page') {
throw new Error(`提交密码后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`);
}
await sleep(250);
}
snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
if (snapshot.state === 'verification_page') {
return {
action: 'done',
result: createStep6SuccessResult(snapshot, {
via: 'password_submit',
loginVerificationRequestedAt: passwordSubmittedAt,
}),
};
}
if (snapshot.state === 'login_timeout_error_page') {
const transition = await createStep6LoginTimeoutRecoveryTransition(
'login_timeout_error_page',
snapshot,
'提交密码后进入登录超时报错页。',
{
loginVerificationRequestedAt: passwordSubmittedAt,
via: 'password_submit_timeout_recovered',
}
);
if (transition.action === 'done') {
return {
action: 'done',
result: transition.result,
};
}
if (transition.action === 'password') {
return { action: 'password', snapshot: transition.snapshot };
}
if (transition.action === 'email') {
return { action: 'email', snapshot: transition.snapshot };
}
return {
action: 'recoverable',
result: transition.result,
};
}
if (snapshot.state === 'oauth_consent_page') {
throw new Error(`提交密码后页面直接进入 OAuth 授权页,未经过登录验证码页。URL: ${snapshot.url}`);
}
if (snapshot.state === 'add_phone_page') {
throw new Error(`提交密码后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`);
}
if (snapshot.state === 'password_page' && snapshot.switchTrigger) {
return { action: 'switch', snapshot };
}
return {
action: 'recoverable',
result: createStep6RecoverableResult('password_submit_stalled', snapshot, {
message: '提交密码后仍未进入登录验证码页。',
}),
};
return waitForStep6PostSubmitTransition({
timeout,
via: 'password_submit',
oauthConsentVia: 'password_submit_oauth_consent',
loginVerificationRequestedAt: passwordSubmittedAt,
timeoutRecoveryMessage: '提交密码后进入登录超时报错页。',
timeoutRecoveryVia: 'password_submit_timeout_recovered',
allowFinalSwitchAction: true,
stalledReason: 'password_submit_stalled',
stalledMessage: '提交密码后仍未进入登录验证码页。',
addPhoneMessage: (snapshot) => `提交密码后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`,
});
}
async function waitForStep6SwitchTransition(loginVerificationRequestedAt, timeout = 10000) {
const start = Date.now();
let snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
const transition = await waitForStep6PostSubmitTransition({
timeout,
via: 'switch_to_one_time_code_login',
oauthConsentVia: 'switch_to_one_time_code_oauth_consent',
loginVerificationRequestedAt,
timeoutRecoveryMessage: '切换到一次性验证码登录后进入登录超时报错页。',
timeoutRecoveryVia: 'switch_to_one_time_code_timeout_recovered',
stalledReason: 'one_time_code_switch_stalled',
stalledMessage: '点击一次性验证码登录后仍未进入登录验证码页。',
addPhoneMessage: (snapshot) => `切换到一次性验证码登录后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`,
});
while (Date.now() - start < timeout) {
throwIfStopped();
snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
if (snapshot.state === 'verification_page') {
return createStep6SuccessResult(snapshot, {
via: 'switch_to_one_time_code_login',
loginVerificationRequestedAt,
});
}
if (snapshot.state === 'login_timeout_error_page') {
const transition = await createStep6LoginTimeoutRecoveryTransition(
'login_timeout_error_page',
snapshot,
'切换到一次性验证码登录后进入登录超时报错页。',
{
loginVerificationRequestedAt,
via: 'switch_to_one_time_code_timeout_recovered',
}
);
if (transition.action === 'done') {
return transition.result;
}
if (transition.action === 'password' || transition.action === 'email') {
return transition;
}
return transition.result;
}
if (snapshot.state === 'oauth_consent_page') {
throw new Error(`切换到一次性验证码登录后页面直接进入 OAuth 授权页,未经过登录验证码页。URL: ${snapshot.url}`);
}
if (snapshot.state === 'add_phone_page') {
throw new Error(`切换到一次性验证码登录后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`);
}
await sleep(250);
}
snapshot = normalizeStep6Snapshot(inspectLoginAuthState());
if (snapshot.state === 'verification_page') {
return createStep6SuccessResult(snapshot, {
via: 'switch_to_one_time_code_login',
loginVerificationRequestedAt,
});
}
if (snapshot.state === 'login_timeout_error_page') {
const transition = await createStep6LoginTimeoutRecoveryTransition(
'login_timeout_error_page',
snapshot,
'切换到一次性验证码登录后进入登录超时报错页。',
{
loginVerificationRequestedAt,
via: 'switch_to_one_time_code_timeout_recovered',
}
);
if (transition.action === 'done') {
return transition.result;
}
if (transition.action === 'password' || transition.action === 'email') {
return transition;
}
if (transition.action === 'done' || transition.action === 'recoverable') {
return transition.result;
}
if (snapshot.state === 'oauth_consent_page') {
throw new Error(`切换到一次性验证码登录后页面直接进入 OAuth 授权页,未经过登录验证码页。URL: ${snapshot.url}`);
}
if (snapshot.state === 'add_phone_page') {
throw new Error(`切换到一次性验证码登录后页面直接进入手机号页面,未经过登录验证码页。URL: ${snapshot.url}`);
}
return createStep6RecoverableResult('one_time_code_switch_stalled', snapshot, {
message: '点击一次性验证码登录后仍未进入登录验证码页。',
});
return transition;
}
async function step6SwitchToOneTimeCodeLogin(payload, snapshot) {
@@ -2921,6 +2832,9 @@ async function step6SwitchToOneTimeCodeLogin(payload, snapshot) {
await sleep(1200);
const result = await waitForStep6SwitchTransition(loginVerificationRequestedAt);
if (result?.step6Outcome === 'success') {
if (result.skipLoginVerificationStep) {
return result;
}
return finalizeStep6VerificationReady({
logLabel: '步骤 7 收尾',
loginVerificationRequestedAt: result.loginVerificationRequestedAt || loginVerificationRequestedAt,
@@ -2964,6 +2878,9 @@ async function step6LoginFromPasswordPage(payload, snapshot) {
const transition = await waitForStep6PasswordSubmitTransition(passwordSubmittedAt);
if (transition.action === 'done') {
if (transition.result?.skipLoginVerificationStep) {
return transition.result;
}
return finalizeStep6VerificationReady({
logLabel: '步骤 7 收尾',
loginVerificationRequestedAt: transition.result.loginVerificationRequestedAt || passwordSubmittedAt,
@@ -3020,6 +2937,9 @@ async function step6LoginFromEmailPage(payload, snapshot) {
const transition = await waitForStep6EmailSubmitTransition(emailSubmittedAt);
if (transition.action === 'done') {
if (transition.result?.skipLoginVerificationStep) {
return transition.result;
}
return finalizeStep6VerificationReady({
logLabel: '步骤 7 收尾',
loginVerificationRequestedAt: transition.result.loginVerificationRequestedAt || emailSubmittedAt,
@@ -3057,6 +2977,13 @@ async function step6_login(payload) {
});
}
if (snapshot.state === 'oauth_consent_page') {
log('步骤 7:认证页已直接进入 OAuth 授权页,跳过登录验证码步骤。', 'ok');
return createStep6OAuthConsentSuccessResult(snapshot, {
via: 'already_on_oauth_consent_page',
});
}
if (snapshot.state === 'login_timeout_error_page') {
log('步骤 7:检测到登录超时报错页,先尝试恢复当前页面。', 'warn');
const transition = await createStep6LoginTimeoutRecoveryTransition(
@@ -3069,6 +2996,9 @@ async function step6_login(payload) {
}
);
if (transition.action === 'done') {
if (transition.result?.skipLoginVerificationStep) {
return transition.result;
}
return finalizeStep6VerificationReady({
logLabel: '步骤 7 收尾',
loginVerificationRequestedAt: transition.result.loginVerificationRequestedAt || null,
+1 -1
View File
@@ -1012,7 +1012,7 @@ async function step1_getOAuthLink(payload, options = {}) {
async function step9_vpsVerify(payload) {
const visibleStep = Number(payload?.visibleStep) || 10;
const confirmStep = visibleStep === 12 ? 11 : 9;
const confirmStep = visibleStep >= 13 ? 12 : 9;
await ensureOAuthManagementPage(payload?.vpsPassword, confirmStep);
// 优先从 payload 读取 localhostUrl;没有时再回退到全局状态