| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 |
- (function attachBackgroundVerificationFlow(root, factory) {
- root.MultiPageBackgroundVerificationFlow = factory();
- })(typeof self !== 'undefined' ? self : globalThis, function createBackgroundVerificationFlowModule() {
- function createVerificationFlowHelpers(deps = {}) {
- const {
- A4SKY_PROVIDER,
- addLog,
- chrome,
- CLOUDFLARE_TEMP_EMAIL_PROVIDER,
- completeStepFromBackground,
- confirmCustomVerificationStepBypassRequest,
- getHotmailVerificationPollConfig,
- getHotmailVerificationRequestTimestamp,
- getState,
- getTabId,
- HOTMAIL_PROVIDER,
- isStopError,
- LUCKMAIL_PROVIDER,
- MAIL_2925_VERIFICATION_INTERVAL_MS,
- MAIL_2925_VERIFICATION_MAX_ATTEMPTS,
- pollCloudflareTempEmailVerificationCode,
- pollHotmailVerificationCode,
- pollLuckmailVerificationCode,
- sendToContentScript,
- sendToMailContentScriptResilient,
- setState,
- sleepWithStop,
- throwIfStopped,
- VERIFICATION_POLL_MAX_ROUNDS,
- } = deps;
- const A4SKY_MANUAL_LOGIN_RESPONSE_TIMEOUT_MS = 20 * 60 * 1000;
- function getVerificationCodeStateKey(step) {
- return step === 4 ? 'lastSignupCode' : 'lastLoginCode';
- }
- function getVerificationCodeLabel(step) {
- return step === 4 ? '注册' : '登录';
- }
- function getVerificationResendStateKey() {
- return 'verificationResendCount';
- }
- function normalizeVerificationResendCount(value, fallback = 0) {
- const numeric = Number(value);
- if (!Number.isFinite(numeric)) {
- return Math.max(0, Math.floor(Number(fallback) || 0));
- }
- return Math.min(20, Math.max(0, Math.floor(numeric)));
- }
- function getLegacyVerificationResendCountDefault(step, options = {}) {
- const requestFreshCodeFirst = Boolean(options.requestFreshCodeFirst);
- const legacyMaxRounds = Math.max(1, Math.floor(Number(VERIFICATION_POLL_MAX_ROUNDS) || 1));
- if (step === 4 && requestFreshCodeFirst) {
- return legacyMaxRounds;
- }
- return Math.max(0, legacyMaxRounds - 1);
- }
- function getConfiguredVerificationResendCount(step, state, options = {}) {
- const stateKey = getVerificationResendStateKey(step);
- const configuredValue = state?.[stateKey] !== undefined
- ? state[stateKey]
- : (state?.signupVerificationResendCount ?? state?.loginVerificationResendCount);
- return normalizeVerificationResendCount(
- configuredValue,
- getLegacyVerificationResendCountDefault(step, options)
- );
- }
- function resolveMaxResendRequests(pollOverrides = {}) {
- if (pollOverrides.maxResendRequests !== undefined) {
- return normalizeVerificationResendCount(pollOverrides.maxResendRequests, 0);
- }
- const legacyMaxRounds = Number(pollOverrides.maxRounds);
- if (Number.isFinite(legacyMaxRounds)) {
- return Math.max(0, Math.floor(legacyMaxRounds) - 1);
- }
- return Math.max(0, Math.floor(Number(VERIFICATION_POLL_MAX_ROUNDS) || 1) - 1);
- }
- async function confirmCustomVerificationStepBypass(step) {
- const verificationLabel = getVerificationCodeLabel(step);
- await addLog(`步骤 ${step}:当前为自定义邮箱模式,请手动在页面中输入${verificationLabel}验证码并进入下一页面。`, 'warn');
- let response = null;
- try {
- response = await confirmCustomVerificationStepBypassRequest(step);
- } catch {
- throw new Error(`步骤 ${step}:无法打开确认弹窗,请先保持侧边栏打开后重试。`);
- }
- if (response?.error) {
- throw new Error(response.error);
- }
- if (!response?.confirmed) {
- throw new Error(`步骤 ${step}:已取消手动${verificationLabel}验证码确认。`);
- }
- await setState({
- lastEmailTimestamp: null,
- signupVerificationRequestedAt: null,
- loginVerificationRequestedAt: null,
- });
- await deps.setStepStatus(step, 'skipped');
- await addLog(`步骤 ${step}:已确认手动完成${verificationLabel}验证码输入,当前步骤已跳过。`, 'warn');
- }
- function getVerificationPollPayload(step, state, overrides = {}) {
- const is2925Provider = state?.mailProvider === '2925';
- if (step === 4) {
- return {
- filterAfterTimestamp: getHotmailVerificationRequestTimestamp(4, state),
- senderFilters: ['openai', 'noreply', 'verify', 'auth', 'duckduckgo', 'forward'],
- subjectFilters: ['verify', 'verification', 'code', '验证码', 'confirm'],
- targetEmail: state.email,
- maxAttempts: is2925Provider ? MAIL_2925_VERIFICATION_MAX_ATTEMPTS : 5,
- intervalMs: is2925Provider ? MAIL_2925_VERIFICATION_INTERVAL_MS : 3000,
- ...overrides,
- };
- }
- return {
- filterAfterTimestamp: getHotmailVerificationRequestTimestamp(8, state),
- senderFilters: ['openai', 'noreply', 'verify', 'auth', 'chatgpt', 'duckduckgo', 'forward'],
- subjectFilters: ['verify', 'verification', 'code', '验证码', 'confirm', 'login'],
- targetEmail: state.email,
- maxAttempts: is2925Provider ? MAIL_2925_VERIFICATION_MAX_ATTEMPTS : 5,
- intervalMs: is2925Provider ? MAIL_2925_VERIFICATION_INTERVAL_MS : 3000,
- ...overrides,
- };
- }
- async function getRemainingTimeBudgetMs(step, options = {}, actionLabel = '') {
- const resolver = typeof options.getRemainingTimeMs === 'function'
- ? options.getRemainingTimeMs
- : null;
- if (!resolver) {
- return null;
- }
- const value = await resolver({ step, actionLabel });
- const numeric = Number(value);
- if (!Number.isFinite(numeric)) {
- return null;
- }
- return Math.max(0, Math.floor(numeric));
- }
- async function getResponseTimeoutMsForStep(step, options = {}, fallbackMs = 30000, actionLabel = '') {
- const remainingMs = await getRemainingTimeBudgetMs(step, options, actionLabel);
- if (remainingMs === null) {
- return Math.max(1000, Number(fallbackMs) || 1000);
- }
- return Math.max(1000, Math.min(Math.max(1000, Number(fallbackMs) || 1000), remainingMs));
- }
- async function applyMailPollingTimeBudget(step, payload, options = {}, actionLabel = '') {
- const nextPayload = { ...payload };
- const intervalMs = Math.max(1, Number(nextPayload.intervalMs) || 3000);
- const baseMaxAttempts = Math.max(1, Number(nextPayload.maxAttempts) || 1);
- const remainingMs = await getRemainingTimeBudgetMs(step, options, actionLabel);
- if (remainingMs !== null) {
- nextPayload.maxAttempts = Math.max(
- 1,
- Math.min(baseMaxAttempts, Math.floor(Math.max(0, remainingMs - 1000) / intervalMs) + 1)
- );
- }
- const defaultResponseTimeoutMs = Math.max(45000, nextPayload.maxAttempts * intervalMs + 25000);
- const responseTimeoutMs = remainingMs === null
- ? defaultResponseTimeoutMs
- : Math.max(1000, Math.min(defaultResponseTimeoutMs, remainingMs));
- return {
- payload: nextPayload,
- responseTimeoutMs,
- timeoutMs: responseTimeoutMs,
- };
- }
- function getMailContentScriptTimeoutOptions(mail, timedPoll = {}) {
- if (mail?.provider === A4SKY_PROVIDER) {
- const extendedTimeoutMs = Math.max(
- Number(timedPoll.responseTimeoutMs) || 0,
- A4SKY_MANUAL_LOGIN_RESPONSE_TIMEOUT_MS
- );
- return {
- timeoutMs: extendedTimeoutMs,
- responseTimeoutMs: extendedTimeoutMs,
- };
- }
- return {
- timeoutMs: timedPoll.timeoutMs,
- responseTimeoutMs: timedPoll.responseTimeoutMs,
- };
- }
- async function requestVerificationCodeResend(step, options = {}) {
- throwIfStopped();
- const signupTabId = await getTabId('signup-page');
- if (!signupTabId) {
- throw new Error('认证页面标签页已关闭,无法重新请求验证码。');
- }
- throwIfStopped();
- await chrome.tabs.update(signupTabId, { active: true });
- throwIfStopped();
- const result = await sendToContentScript('signup-page', {
- type: 'RESEND_VERIFICATION_CODE',
- step,
- source: 'background',
- payload: {},
- }, {
- responseTimeoutMs: await getResponseTimeoutMsForStep(
- step,
- options,
- 30000,
- `重新发送${getVerificationCodeLabel(step)}验证码`
- ),
- });
- if (result && result.error) {
- throw new Error(result.error);
- }
- await addLog(`步骤 ${step}:已请求新的${getVerificationCodeLabel(step)}验证码。`, 'warn');
- const requestedAt = Date.now();
- if (step === 4) {
- await setState({ signupVerificationRequestedAt: requestedAt });
- }
- if (step === 8) {
- await setState({ loginVerificationRequestedAt: requestedAt });
- }
- const currentState = await getState();
- if (currentState.mailProvider === '2925') {
- const mailTabId = await getTabId('mail-2925');
- if (mailTabId) {
- await chrome.tabs.update(mailTabId, { active: true });
- await addLog(`步骤 ${step}:已切换到 2925 邮箱标签页等待新邮件。`, 'info');
- }
- }
- return requestedAt;
- }
- async function pollFreshVerificationCodeWithResendInterval(step, state, mail, pollOverrides = {}) {
- const stateKey = getVerificationCodeStateKey(step);
- const rejectedCodes = new Set();
- if (state[stateKey]) {
- rejectedCodes.add(state[stateKey]);
- }
- for (const code of (pollOverrides.excludeCodes || [])) {
- if (code) rejectedCodes.add(code);
- }
- const {
- maxRounds: _ignoredMaxRounds,
- maxResendRequests: _ignoredMaxResendRequests,
- resendIntervalMs: _ignoredResendIntervalMs,
- lastResendAt: _ignoredLastResendAt,
- onResendRequestedAt: _ignoredOnResendRequestedAt,
- ...payloadOverrides
- } = pollOverrides;
- const onResendRequestedAt = typeof pollOverrides.onResendRequestedAt === 'function'
- ? pollOverrides.onResendRequestedAt
- : null;
- let lastError = null;
- let filterAfterTimestamp = payloadOverrides.filterAfterTimestamp ?? getVerificationPollPayload(step, state).filterAfterTimestamp;
- const maxResendRequests = resolveMaxResendRequests(pollOverrides);
- const totalRounds = maxResendRequests + 1;
- const maxRounds = totalRounds;
- const resendIntervalMs = Math.max(0, Number(pollOverrides.resendIntervalMs) || 0);
- let lastResendAt = Number(pollOverrides.lastResendAt) || 0;
- let usedResendRequests = 0;
- for (let round = 1; round <= totalRounds; round++) {
- throwIfStopped();
- if (round > 1) {
- lastResendAt = await requestVerificationCodeResend(step, pollOverrides);
- usedResendRequests += 1;
- if (onResendRequestedAt) {
- const nextFilterAfterTimestamp = await onResendRequestedAt(lastResendAt);
- if (nextFilterAfterTimestamp !== undefined) {
- filterAfterTimestamp = nextFilterAfterTimestamp;
- }
- }
- }
- while (true) {
- throwIfStopped();
- const payload = getVerificationPollPayload(step, state, {
- ...payloadOverrides,
- filterAfterTimestamp,
- excludeCodes: [...rejectedCodes],
- });
- if (lastResendAt > 0) {
- const remainingBeforeResendMs = Math.max(0, resendIntervalMs - (Date.now() - lastResendAt));
- const baseMaxAttempts = Math.max(1, Number(payload.maxAttempts) || 5);
- const intervalMs = Math.max(1, Number(payload.intervalMs) || 3000);
- payload.maxAttempts = Math.max(1, Math.min(baseMaxAttempts, Math.floor(remainingBeforeResendMs / intervalMs) + 1));
- }
- try {
- const timedPoll = await applyMailPollingTimeBudget(
- step,
- payload,
- pollOverrides,
- `轮询${getVerificationCodeLabel(step)}验证码邮箱`
- );
- const result = await sendToMailContentScriptResilient(
- mail,
- {
- type: 'POLL_EMAIL',
- step,
- source: 'background',
- payload: timedPoll.payload,
- },
- {
- ...getMailContentScriptTimeoutOptions(mail, timedPoll),
- maxRecoveryAttempts: 2,
- }
- );
- if (result && result.error) {
- throw new Error(result.error);
- }
- if (!result || !result.code) {
- throw new Error(`步骤 ${step}:邮箱轮询结束,但未获取到验证码。`);
- }
- if (rejectedCodes.has(result.code)) {
- throw new Error(`步骤 ${step}:再次收到了相同的${getVerificationCodeLabel(step)}验证码:${result.code}`);
- }
- return {
- ...result,
- lastResendAt,
- remainingResendRequests: Math.max(0, maxResendRequests - usedResendRequests),
- };
- } catch (err) {
- if (isStopError(err)) {
- throw err;
- }
- lastError = err;
- await addLog(`步骤 ${step}:${err.message}`, 'warn');
- }
- const remainingBeforeResendMs = lastResendAt > 0
- ? Math.max(0, resendIntervalMs - (Date.now() - lastResendAt))
- : 0;
- if (remainingBeforeResendMs > 0) {
- await addLog(
- `步骤 ${step}:距离下次重新发送验证码还差 ${Math.ceil(remainingBeforeResendMs / 1000)} 秒,继续刷新邮箱(第 ${round}/${maxRounds} 轮)...`,
- 'info'
- );
- continue;
- }
- if (round < maxRounds) {
- await addLog(`步骤 ${step}:已到 25 秒重发间隔,准备重新发送验证码(第 ${round + 1}/${maxRounds} 轮)...`, 'warn');
- }
- break;
- }
- }
- throw lastError || new Error(`步骤 ${step}:无法获取新的${getVerificationCodeLabel(step)}验证码。`);
- }
- async function pollFreshVerificationCode(step, state, mail, pollOverrides = {}) {
- const {
- onResendRequestedAt,
- maxRounds: _ignoredMaxRounds,
- maxResendRequests: _ignoredMaxResendRequests,
- ...cleanPollOverrides
- } = pollOverrides;
- if (mail.provider === HOTMAIL_PROVIDER) {
- const hotmailPollConfig = getHotmailVerificationPollConfig(step);
- const timedPoll = await applyMailPollingTimeBudget(step, {
- ...getVerificationPollPayload(step, state),
- ...hotmailPollConfig,
- ...cleanPollOverrides,
- }, cleanPollOverrides, `轮询${getVerificationCodeLabel(step)}验证码邮箱`);
- return pollHotmailVerificationCode(step, state, timedPoll.payload);
- }
- if (mail.provider === LUCKMAIL_PROVIDER) {
- const timedPoll = await applyMailPollingTimeBudget(step, {
- ...getVerificationPollPayload(step, state),
- ...cleanPollOverrides,
- }, cleanPollOverrides, `轮询${getVerificationCodeLabel(step)}验证码邮箱`);
- return pollLuckmailVerificationCode(step, state, timedPoll.payload);
- }
- if (mail.provider === CLOUDFLARE_TEMP_EMAIL_PROVIDER) {
- const timedPoll = await applyMailPollingTimeBudget(step, {
- ...getVerificationPollPayload(step, state),
- ...cleanPollOverrides,
- }, cleanPollOverrides, `轮询${getVerificationCodeLabel(step)}验证码邮箱`);
- return pollCloudflareTempEmailVerificationCode(step, state, timedPoll.payload);
- }
- if (Number(pollOverrides.resendIntervalMs) > 0) {
- return pollFreshVerificationCodeWithResendInterval(step, state, mail, pollOverrides);
- }
- const stateKey = getVerificationCodeStateKey(step);
- const rejectedCodes = new Set();
- if (state[stateKey]) {
- rejectedCodes.add(state[stateKey]);
- }
- for (const code of (pollOverrides.excludeCodes || [])) {
- if (code) rejectedCodes.add(code);
- }
- let lastError = null;
- let filterAfterTimestamp = cleanPollOverrides.filterAfterTimestamp ?? getVerificationPollPayload(step, state).filterAfterTimestamp;
- const maxResendRequests = resolveMaxResendRequests(pollOverrides);
- const maxRounds = maxResendRequests + 1;
- let usedResendRequests = 0;
- for (let round = 1; round <= maxRounds; round++) {
- throwIfStopped();
- if (round > 1) {
- const requestedAt = await requestVerificationCodeResend(step, pollOverrides);
- usedResendRequests += 1;
- if (typeof onResendRequestedAt === 'function') {
- const nextFilterAfterTimestamp = await onResendRequestedAt(requestedAt);
- if (nextFilterAfterTimestamp !== undefined) {
- filterAfterTimestamp = nextFilterAfterTimestamp;
- }
- }
- }
- const payload = getVerificationPollPayload(step, state, {
- ...cleanPollOverrides,
- filterAfterTimestamp,
- excludeCodes: [...rejectedCodes],
- });
- try {
- const timedPoll = await applyMailPollingTimeBudget(
- step,
- payload,
- pollOverrides,
- `轮询${getVerificationCodeLabel(step)}验证码邮箱`
- );
- const result = await sendToMailContentScriptResilient(
- mail,
- {
- type: 'POLL_EMAIL',
- step,
- source: 'background',
- payload: timedPoll.payload,
- },
- {
- ...getMailContentScriptTimeoutOptions(mail, timedPoll),
- maxRecoveryAttempts: 2,
- }
- );
- if (result && result.error) {
- throw new Error(result.error);
- }
- if (!result || !result.code) {
- throw new Error(`步骤 ${step}:邮箱轮询结束,但未获取到验证码。`);
- }
- if (rejectedCodes.has(result.code)) {
- throw new Error(`步骤 ${step}:再次收到了相同的${getVerificationCodeLabel(step)}验证码:${result.code}`);
- }
- return {
- ...result,
- remainingResendRequests: Math.max(0, maxResendRequests - usedResendRequests),
- };
- } catch (err) {
- if (isStopError(err)) {
- throw err;
- }
- lastError = err;
- await addLog(`步骤 ${step}:${err.message}`, 'warn');
- if (round < maxRounds) {
- await addLog(`步骤 ${step}:将重新发送验证码后重试(${round + 1}/${maxRounds})...`, 'warn');
- }
- }
- }
- throw lastError || new Error(`步骤 ${step}:无法获取新的${getVerificationCodeLabel(step)}验证码。`);
- }
- async function submitVerificationCode(step, code, options = {}) {
- const signupTabId = await getTabId('signup-page');
- if (!signupTabId) {
- throw new Error('认证页面标签页已关闭,无法填写验证码。');
- }
- await chrome.tabs.update(signupTabId, { active: true });
- const result = await sendToContentScript('signup-page', {
- type: 'FILL_CODE',
- step,
- source: 'background',
- payload: { code },
- }, {
- responseTimeoutMs: await getResponseTimeoutMsForStep(
- step,
- options,
- step === 7 ? 45000 : 30000,
- `填写${getVerificationCodeLabel(step)}验证码`
- ),
- });
- if (result && result.error) {
- throw new Error(result.error);
- }
- return result || {};
- }
- async function resolveVerificationStep(step, state, mail, options = {}) {
- const stateKey = getVerificationCodeStateKey(step);
- const rejectedCodes = new Set();
- const hotmailPollConfig = mail.provider === HOTMAIL_PROVIDER
- ? getHotmailVerificationPollConfig(step)
- : null;
- const beforeSubmit = typeof options.beforeSubmit === 'function'
- ? options.beforeSubmit
- : null;
- const ignorePersistedLastCode = Boolean(hotmailPollConfig?.ignorePersistedLastCode);
- if (state[stateKey] && !ignorePersistedLastCode) {
- rejectedCodes.add(state[stateKey]);
- }
- let nextFilterAfterTimestamp = options.filterAfterTimestamp ?? null;
- const requestFreshCodeFirst = options.requestFreshCodeFirst !== undefined
- ? Boolean(options.requestFreshCodeFirst)
- : (hotmailPollConfig?.requestFreshCodeFirst ?? false);
- let remainingAutomaticResendCount = options.maxResendRequests !== undefined
- ? normalizeVerificationResendCount(
- options.maxResendRequests,
- getLegacyVerificationResendCountDefault(step, { requestFreshCodeFirst })
- )
- : getConfiguredVerificationResendCount(step, state, { requestFreshCodeFirst });
- const maxSubmitAttempts = 3;
- const resendIntervalMs = Math.max(0, Number(options.resendIntervalMs) || 0);
- let lastResendAt = Number(options.lastResendAt) || 0;
- const updateFilterAfterTimestampForVerificationStep = async (_requestedAt) => {
- return nextFilterAfterTimestamp;
- };
- if (requestFreshCodeFirst) {
- if (remainingAutomaticResendCount <= 0) {
- await addLog(`步骤 ${step}:当前自动重新发送验证码次数为 0,将直接使用当前时间窗口轮询邮箱。`, 'info');
- } else {
- try {
- lastResendAt = await requestVerificationCodeResend(step, options);
- remainingAutomaticResendCount -= 1;
- await updateFilterAfterTimestampForVerificationStep(lastResendAt);
- await addLog(`步骤 ${step}:已先请求一封新的${getVerificationCodeLabel(step)}验证码,再开始轮询邮箱。`, 'warn');
- } catch (err) {
- if (isStopError(err)) {
- throw err;
- }
- await addLog(`步骤 ${step}:首次重新获取验证码失败:${err.message},将继续使用当前时间窗口轮询。`, 'warn');
- }
- }
- }
- if (mail.provider === HOTMAIL_PROVIDER) {
- const initialDelayMs = Number(options.initialDelayMs ?? hotmailPollConfig.initialDelayMs) || 0;
- if (initialDelayMs > 0) {
- const remainingMs = await getRemainingTimeBudgetMs(
- step,
- options,
- `等待${getVerificationCodeLabel(step)}验证码邮件到达`
- );
- const delayMs = remainingMs === null
- ? initialDelayMs
- : Math.min(initialDelayMs, Math.max(0, remainingMs));
- await addLog(`步骤 ${step}:等待 ${Math.round(initialDelayMs / 1000)} 秒,让 Hotmail 验证码邮件先到达...`, 'info');
- await sleepWithStop(delayMs);
- }
- }
- for (let attempt = 1; attempt <= maxSubmitAttempts; attempt++) {
- const pollOptions = {
- excludeCodes: [...rejectedCodes],
- getRemainingTimeMs: options.getRemainingTimeMs,
- maxResendRequests: remainingAutomaticResendCount,
- resendIntervalMs,
- lastResendAt,
- onResendRequestedAt: updateFilterAfterTimestampForVerificationStep,
- };
- if (nextFilterAfterTimestamp !== null && nextFilterAfterTimestamp !== undefined) {
- pollOptions.filterAfterTimestamp = nextFilterAfterTimestamp;
- }
- const result = await pollFreshVerificationCode(step, state, mail, pollOptions);
- lastResendAt = Number(result?.lastResendAt) || lastResendAt;
- remainingAutomaticResendCount = normalizeVerificationResendCount(
- result?.remainingResendRequests,
- remainingAutomaticResendCount
- );
- throwIfStopped();
- await addLog(`步骤 ${step}:已获取${getVerificationCodeLabel(step)}验证码:${result.code}`);
- if (beforeSubmit) {
- await beforeSubmit(result, {
- attempt,
- rejectedCodes: new Set(rejectedCodes),
- filterAfterTimestamp: nextFilterAfterTimestamp ?? undefined,
- lastResendAt,
- });
- }
- throwIfStopped();
- const submitResult = await submitVerificationCode(step, result.code, options);
- if (submitResult.invalidCode) {
- rejectedCodes.add(result.code);
- await addLog(`步骤 ${step}:验证码被页面拒绝:${submitResult.errorText || result.code}`, 'warn');
- if (attempt >= maxSubmitAttempts) {
- throw new Error(`步骤 ${step}:验证码连续失败,已达到 ${maxSubmitAttempts} 次重试上限。`);
- }
- const remainingBeforeResendMs = resendIntervalMs > 0 && lastResendAt > 0
- ? Math.max(0, resendIntervalMs - (Date.now() - lastResendAt))
- : 0;
- if (remainingBeforeResendMs > 0) {
- await addLog(
- `步骤 ${step}:提交失败后距离下次重新发送验证码还差 ${Math.ceil(remainingBeforeResendMs / 1000)} 秒,先继续刷新邮箱(${attempt + 1}/${maxSubmitAttempts})...`,
- 'warn'
- );
- continue;
- }
- if (remainingAutomaticResendCount <= 0) {
- await addLog(`步骤 ${step}:已达到自动重新发送验证码次数上限,将直接使用当前时间窗口继续重试。`, 'warn');
- continue;
- }
- lastResendAt = await requestVerificationCodeResend(step, options);
- remainingAutomaticResendCount -= 1;
- await updateFilterAfterTimestampForVerificationStep(lastResendAt);
- await addLog(`步骤 ${step}:提交失败后已请求新验证码(${attempt + 1}/${maxSubmitAttempts})...`, 'warn');
- continue;
- }
- if (submitResult.addPhonePage) {
- const urlPart = submitResult.url ? ` URL: ${submitResult.url}` : '';
- throw new Error(`步骤 ${step}:验证码提交后页面进入手机号页面,当前流程无法继续自动授权。${urlPart}`.trim());
- }
- await setState({
- lastEmailTimestamp: result.emailTimestamp,
- [stateKey]: result.code,
- });
- await completeStepFromBackground(step, {
- emailTimestamp: result.emailTimestamp,
- code: result.code,
- });
- return;
- }
- }
- return {
- confirmCustomVerificationStepBypass,
- getVerificationCodeLabel,
- getVerificationCodeStateKey,
- getVerificationPollPayload,
- pollFreshVerificationCode,
- pollFreshVerificationCodeWithResendInterval,
- requestVerificationCodeResend,
- resolveVerificationStep,
- submitVerificationCode,
- };
- }
- return {
- createVerificationFlowHelpers,
- };
- });
|