diff --git a/background.js b/background.js index 987cbaf..a016efe 100644 --- a/background.js +++ b/background.js @@ -1350,7 +1350,6 @@ const PERSISTED_SETTING_DEFAULTS = { gopayHelperApiKeyStatus: '', autoRunSkipFailures: false, autoRunFallbackThreadIntervalMinutes: 0, - oauthFlowTimeoutEnabled: true, operationDelayEnabled: true, autoStepDelaySeconds: null, step6CookieCleanupEnabled: false, @@ -3329,7 +3328,6 @@ function normalizePersistentSettingValue(key, value) { case 'gopayHelperRemainingUses': return Math.max(0, Number(value) || 0); case 'autoRunSkipFailures': - case 'oauthFlowTimeoutEnabled': case 'gopayHelperLocalSmsHelperEnabled': case 'gopayHelperAutoModeEnabled': return Boolean(value); @@ -14441,15 +14439,46 @@ function normalizeOAuthFlowSourceUrl(value) { return normalized || null; } +function resolveOAuthTimeoutBudgetScope(state = {}) { + const activeFlowId = self.MultiPageFlowRegistry?.normalizeFlowId + ? self.MultiPageFlowRegistry.normalizeFlowId( + state?.activeFlowId || state?.flowId, + DEFAULT_ACTIVE_FLOW_ID + ) + : (String(state?.activeFlowId || state?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() + || DEFAULT_ACTIVE_FLOW_ID); + const capabilityState = typeof resolveCurrentFlowCapabilities === 'function' + ? resolveCurrentFlowCapabilities(state, { activeFlowId }) + : null; + const targetId = capabilityState?.effectiveTargetId || (self.MultiPageFlowRegistry?.normalizeTargetId + ? self.MultiPageFlowRegistry.normalizeTargetId( + activeFlowId, + state?.targetId, + self.MultiPageFlowRegistry.getDefaultTargetId?.(activeFlowId) + ) + : String(state?.targetId || '').trim().toLowerCase()); + const targetCapabilities = capabilityState?.targetCapabilities || (self.MultiPageFlowRegistry?.getTargetCapabilities + ? self.MultiPageFlowRegistry.getTargetCapabilities(activeFlowId, targetId) + : null); + return { + activeFlowId, + targetId, + enabled: activeFlowId === DEFAULT_ACTIVE_FLOW_ID && Boolean(targetCapabilities?.usesOauthTimeoutBudget), + }; +} + +function shouldUseOAuthTimeoutBudget(state = {}) { + return resolveOAuthTimeoutBudgetScope(state).enabled; +} + async function startOAuthFlowTimeoutWindow(options = {}) { const step = Number(options.step) || 7; const state = options.state || await getState(); - if (state?.oauthFlowTimeoutEnabled === false) { + if (!shouldUseOAuthTimeoutBudget(state)) { await setState({ oauthFlowDeadlineAt: null, oauthFlowDeadlineSourceUrl: null, }); - await addLog(`步骤 ${step}:已拿到新的 OAuth 登录地址,授权后链总超时已关闭,仅保留各步骤本地等待超时。`, 'info'); return null; } @@ -14466,7 +14495,7 @@ async function getOAuthFlowRemainingMs(options = {}) { const step = Number(options.step) || 7; const actionLabel = String(options.actionLabel || '后续授权流程').trim() || '后续授权流程'; const state = options.state || await getState(); - if (state?.oauthFlowTimeoutEnabled === false) { + if (!shouldUseOAuthTimeoutBudget(state)) { return null; } diff --git a/background/message-router.js b/background/message-router.js index 8a9adbe..1fadb68 100644 --- a/background/message-router.js +++ b/background/message-router.js @@ -1423,16 +1423,10 @@ || (nextPlusModeEnabled && plusPaymentChanged) || (nextPlusModeEnabled && plusAccountAccessStrategyChanged) || phoneSignupReloginAfterBindEmailChanged; - const oauthFlowTimeoutDisabled = Object.prototype.hasOwnProperty.call(updates, 'oauthFlowTimeoutEnabled') - && updates.oauthFlowTimeoutEnabled === false; const canonicalSettingsUpdates = await setPersistentSettings(updates); const stateUpdates = { ...canonicalSettingsUpdates, ...sessionUpdates, - ...(oauthFlowTimeoutDisabled ? { - oauthFlowDeadlineAt: null, - oauthFlowDeadlineSourceUrl: null, - } : {}), }; if (Object.prototype.hasOwnProperty.call(canonicalSettingsUpdates, 'activeFlowId') && !Object.prototype.hasOwnProperty.call(stateUpdates, 'flowId')) { diff --git a/core/flow-kernel/flow-capabilities.js b/core/flow-kernel/flow-capabilities.js index 03969ed..ac3dfd3 100644 --- a/core/flow-kernel/flow-capabilities.js +++ b/core/flow-kernel/flow-capabilities.js @@ -33,7 +33,6 @@ contributionAdapterIds: [], supportedTargetIds: [], supportsLuckmail: false, - supportsOauthTimeoutBudget: false, canSwitchFlow: true, stepDefinitionMode: 'default', targetSelectorLabel: '来源', @@ -59,6 +58,7 @@ const DEFAULT_TARGET_CAPABILITIES = Object.freeze({ supportsPhoneSignup: true, requiresPhoneSignupWarning: false, + usesOauthTimeoutBudget: false, supportedPlusAccountAccessStrategies: Object.freeze([PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH]), }); diff --git a/core/flow-kernel/flow-registry.js b/core/flow-kernel/flow-registry.js index 4ad595f..ad3341b 100644 --- a/core/flow-kernel/flow-registry.js +++ b/core/flow-kernel/flow-registry.js @@ -18,7 +18,6 @@ contributionAdapterIds: [], supportedTargetIds: [], supportsLuckmail: false, - supportsOauthTimeoutBudget: false, canSwitchFlow: true, stepDefinitionMode: 'default', targetSelectorLabel: '\u6765\u6e90', diff --git a/docs/多注册流程侧边栏能力矩阵.md b/docs/多注册流程侧边栏能力矩阵.md index 82d5011..51e1c41 100644 --- a/docs/多注册流程侧边栏能力矩阵.md +++ b/docs/多注册流程侧边栏能力矩阵.md @@ -49,7 +49,6 @@ flowCapabilities.openai = { supportsContributionMode: true, supportsPlatformBinding: ['cpa', 'sub2api', 'codex2api'], supportsLuckmail: true, - supportsOauthTimeoutBudget: true, stepDefinitionMode: 'openai-dynamic', }; @@ -61,7 +60,6 @@ flowCapabilities.siteA = { supportsContributionMode: false, supportsPlatformBinding: ['siteA-panel'], supportsLuckmail: false, - supportsOauthTimeoutBudget: false, stepDefinitionMode: 'siteA', }; ``` @@ -82,6 +80,7 @@ panelCapabilities = { cpa: { supportsPhoneSignup: true, requiresPhoneSignupWarning: true, + usesOauthTimeoutBudget: true, }, sub2api: { supportsPhoneSignup: true, diff --git a/flows/grok/index.js b/flows/grok/index.js index 90a4ff3..ed2aba1 100644 --- a/flows/grok/index.js +++ b/flows/grok/index.js @@ -30,7 +30,6 @@ contributionAdapterIds: [], supportedTargetIds: ['webchat2api'], supportsLuckmail: false, - supportsOauthTimeoutBudget: false, canSwitchFlow: true, stepDefinitionMode: 'grok', targetSelectorLabel: '来源', diff --git a/flows/kiro/index.js b/flows/kiro/index.js index b46e59b..f5a79a8 100644 --- a/flows/kiro/index.js +++ b/flows/kiro/index.js @@ -34,7 +34,6 @@ "kiro-rs" ], "supportsLuckmail": false, - "supportsOauthTimeoutBudget": false, "canSwitchFlow": true, "stepDefinitionMode": "kiro", "targetSelectorLabel": "来源" diff --git a/flows/openai/index.js b/flows/openai/index.js index 3e99221..70476f3 100644 --- a/flows/openai/index.js +++ b/flows/openai/index.js @@ -38,7 +38,6 @@ "codex2api" ], "supportsLuckmail": true, - "supportsOauthTimeoutBudget": true, "canSwitchFlow": true, "stepDefinitionMode": "openai-dynamic", "targetSelectorLabel": "来源" @@ -427,7 +426,6 @@ "id": "openai-oauth", "label": "OAuth", "rowIds": [ - "row-oauth-flow-timeout", "row-oauth-display", "row-oauth-callback" ] @@ -444,6 +442,7 @@ "cpa": { "supportsPhoneSignup": true, "requiresPhoneSignupWarning": true, + "usesOauthTimeoutBudget": true, "supportedPlusAccountAccessStrategies": [ "oauth", "cpa_codex_session" diff --git a/sidepanel/sidepanel.css b/sidepanel/sidepanel.css index c6cb51d..ae20c10 100644 --- a/sidepanel/sidepanel.css +++ b/sidepanel/sidepanel.css @@ -2231,17 +2231,6 @@ header { text-align: center; } -.oauth-flow-timeout-setting { - gap: 8px; - min-width: 0; -} - -.oauth-flow-timeout-caption { - min-width: 0 !important; - overflow: hidden; - text-overflow: ellipsis; -} - .setting-caption-left { text-align: left; } diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html index bc5ebc9..401a97f 100644 --- a/sidepanel/sidepanel.html +++ b/sidepanel/sidepanel.html @@ -728,22 +728,6 @@ -
- 授权总超时 -
-
- - 关闭后只取消 Step 7 后链总预算 -
-
-
执行范围
diff --git a/sidepanel/sidepanel.js b/sidepanel/sidepanel.js index 6dce808..6db8e70 100644 --- a/sidepanel/sidepanel.js +++ b/sidepanel/sidepanel.js @@ -429,7 +429,6 @@ const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures' const inputAutoSkipFailuresThreadIntervalMinutes = document.getElementById('input-auto-skip-failures-thread-interval-minutes'); const inputStep6CookieCleanupEnabled = document.getElementById('input-step6-cookie-cleanup-enabled'); const inputAutoStepDelaySeconds = document.getElementById('input-auto-step-delay-seconds'); -const inputOAuthFlowTimeoutEnabled = document.getElementById('input-oauth-flow-timeout-enabled'); const rowStepExecutionRange = document.getElementById('row-step-execution-range'); const inputStepExecutionRangeEnabled = document.getElementById('input-step-execution-range-enabled'); const inputStepExecutionRangeFrom = document.getElementById('input-step-execution-range-from'); @@ -5119,9 +5118,6 @@ function collectSettingsPayload() { ? buildStepExecutionRangeByFlowPayload(latestState?.stepExecutionRangeByFlow) : (latestState?.stepExecutionRangeByFlow || {}), autoStepDelaySeconds: normalizeAutoStepDelaySeconds(inputAutoStepDelaySeconds.value), - oauthFlowTimeoutEnabled: typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled - ? Boolean(inputOAuthFlowTimeoutEnabled.checked) - : true, phoneVerificationEnabled: effectivePhoneVerificationEnabled, signupMethod: effectiveSignupMethod, phoneSignupReloginAfterBindEmailEnabled: typeof inputPhoneSignupReloginAfterBindEmail !== 'undefined' && inputPhoneSignupReloginAfterBindEmail @@ -11374,11 +11370,6 @@ function applySettingsState(state) { inputStep6CookieCleanupEnabled.checked = Boolean(state?.step6CookieCleanupEnabled); } inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(state?.autoStepDelaySeconds); - if (typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled) { - inputOAuthFlowTimeoutEnabled.checked = state?.oauthFlowTimeoutEnabled !== undefined - ? Boolean(state.oauthFlowTimeoutEnabled) - : true; - } if (inputVerificationResendCount) { const restoredVerificationResendCount = state?.verificationResendCount !== undefined ? state.verificationResendCount @@ -17849,9 +17840,6 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { if (message.payload.autoStepDelaySeconds !== undefined) { inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(message.payload.autoStepDelaySeconds); } - if (message.payload.oauthFlowTimeoutEnabled !== undefined && typeof inputOAuthFlowTimeoutEnabled !== 'undefined' && inputOAuthFlowTimeoutEnabled) { - inputOAuthFlowTimeoutEnabled.checked = Boolean(message.payload.oauthFlowTimeoutEnabled); - } if ( ( message.payload.verificationResendCount !== undefined diff --git a/tests/background-auth-chain-guard.test.js b/tests/background-auth-chain-guard.test.js index 5af333e..adf0f95 100644 --- a/tests/background-auth-chain-guard.test.js +++ b/tests/background-auth-chain-guard.test.js @@ -48,6 +48,33 @@ function extractFunction(name) { return source.slice(start, end); } +const OAUTH_TIMEOUT_BUDGET_TEST_REGISTRY = ` +const DEFAULT_ACTIVE_FLOW_ID = 'openai'; +const self = { + MultiPageFlowRegistry: { + normalizeFlowId(value, fallback = 'openai') { + const normalized = String(value || '').trim().toLowerCase(); + return ['openai', 'kiro', 'grok'].includes(normalized) ? normalized : fallback; + }, + normalizeTargetId(flowId, value, fallback = 'cpa') { + const normalized = String(value || '').trim().toLowerCase(); + if (flowId === 'openai' && ['cpa', 'sub2api', 'codex2api'].includes(normalized)) return normalized; + if (flowId === 'kiro') return 'kiro-rs'; + if (flowId === 'grok') return 'webchat2api'; + return fallback; + }, + getDefaultTargetId(flowId) { + return flowId === 'openai' ? 'cpa' : ''; + }, + getTargetCapabilities(flowId, targetId) { + return flowId === 'openai' && targetId === 'cpa' + ? { usesOauthTimeoutBudget: true } + : { usesOauthTimeoutBudget: false }; + }, + }, +}; +`; + test('background auth chain set does not include Plus session import nodes', () => { const authChainStart = source.indexOf('const AUTH_CHAIN_NODE_IDS = new Set(['); const authChainEnd = source.indexOf(']);', authChainStart); @@ -431,6 +458,9 @@ test('oauth timeout budget ignores stale deadlines from an old oauth url', async const api = new Function(` const LOG_PREFIX = '[test]'; const OAUTH_FLOW_TIMEOUT_MS = 5 * 60 * 1000; +${OAUTH_TIMEOUT_BUDGET_TEST_REGISTRY} +${extractFunction('resolveOAuthTimeoutBudgetScope')} +${extractFunction('shouldUseOAuthTimeoutBudget')} ${extractFunction('normalizeOAuthFlowDeadlineAt')} ${extractFunction('normalizeOAuthFlowSourceUrl')} ${extractFunction('getOAuthFlowRemainingMs')} @@ -444,6 +474,8 @@ return { step: 8, actionLabel: '登录验证码流程', state: { + activeFlowId: 'openai', + targetId: 'cpa', oauthUrl: 'https://oauth.example/current', oauthFlowDeadlineAt: Date.now() + 1200, oauthFlowDeadlineSourceUrl: 'https://oauth.example/old', @@ -457,7 +489,10 @@ test('oauth timeout budget clamps local timeout when enabled by default', async const api = new Function(` const LOG_PREFIX = '[test]'; const OAUTH_FLOW_TIMEOUT_MS = 5 * 60 * 1000; +${OAUTH_TIMEOUT_BUDGET_TEST_REGISTRY} ${extractFunction('buildOAuthFlowTimeoutError')} +${extractFunction('resolveOAuthTimeoutBudgetScope')} +${extractFunction('shouldUseOAuthTimeoutBudget')} ${extractFunction('normalizeOAuthFlowDeadlineAt')} ${extractFunction('normalizeOAuthFlowSourceUrl')} ${extractFunction('getOAuthFlowRemainingMs')} @@ -471,6 +506,8 @@ return { step: 8, actionLabel: '登录验证码流程', state: { + activeFlowId: 'openai', + targetId: 'cpa', oauthUrl: 'https://oauth.example/current', oauthFlowDeadlineAt: Date.now() + 1200, oauthFlowDeadlineSourceUrl: 'https://oauth.example/current', @@ -481,11 +518,14 @@ return { assert(timeoutMs >= 1000); }); -test('oauth timeout budget disabled mode ignores active deadlines', async () => { +test('oauth timeout budget ignores active deadlines outside openai cpa target', async () => { const api = new Function(` const LOG_PREFIX = '[test]'; const OAUTH_FLOW_TIMEOUT_MS = 5 * 60 * 1000; +${OAUTH_TIMEOUT_BUDGET_TEST_REGISTRY} ${extractFunction('buildOAuthFlowTimeoutError')} +${extractFunction('resolveOAuthTimeoutBudgetScope')} +${extractFunction('shouldUseOAuthTimeoutBudget')} ${extractFunction('normalizeOAuthFlowDeadlineAt')} ${extractFunction('normalizeOAuthFlowSourceUrl')} ${extractFunction('getOAuthFlowRemainingMs')} @@ -499,7 +539,8 @@ return { step: 9, actionLabel: 'OAuth localhost 回调', state: { - oauthFlowTimeoutEnabled: false, + activeFlowId: 'openai', + targetId: 'sub2api', oauthUrl: 'https://oauth.example/current', oauthFlowDeadlineAt: Date.now() - 1000, oauthFlowDeadlineSourceUrl: 'https://oauth.example/current', @@ -509,16 +550,18 @@ return { assert.equal(timeoutMs, 15000); }); -test('startOAuthFlowTimeoutWindow clears stale deadline when timeout is disabled', async () => { +test('startOAuthFlowTimeoutWindow clears stale deadline outside openai cpa target', async () => { const events = { stateUpdates: [], logs: [], }; - const api = new Function('events', ` +const api = new Function('events', ` const OAUTH_FLOW_TIMEOUT_MS = 5 * 60 * 1000; +${OAUTH_TIMEOUT_BUDGET_TEST_REGISTRY} async function getState() { return { - oauthFlowTimeoutEnabled: false, + activeFlowId: 'openai', + targetId: 'sub2api', oauthFlowDeadlineAt: Date.now() - 1000, oauthFlowDeadlineSourceUrl: 'https://oauth.example/old', }; @@ -529,6 +572,8 @@ async function setState(update) { async function addLog(message, level) { events.logs.push({ message, level }); } +${extractFunction('resolveOAuthTimeoutBudgetScope')} +${extractFunction('shouldUseOAuthTimeoutBudget')} ${extractFunction('normalizeOAuthFlowSourceUrl')} ${extractFunction('startOAuthFlowTimeoutWindow')} return { @@ -546,7 +591,7 @@ return { oauthFlowDeadlineAt: null, oauthFlowDeadlineSourceUrl: null, }]); - assert.match(events.logs[0].message, /授权后链总超时已关闭/); + assert.deepStrictEqual(events.logs, []); }); test('oauth localhost timeout recovery resumes from bound-email relogin tail when present', async () => { diff --git a/tests/background-cloudflare-temp-email-settings.test.js b/tests/background-cloudflare-temp-email-settings.test.js index e1ba682..12cb135 100644 --- a/tests/background-cloudflare-temp-email-settings.test.js +++ b/tests/background-cloudflare-temp-email-settings.test.js @@ -156,12 +156,11 @@ return { }); }); -test('oauth flow timeout setting is persisted and normalized as boolean', () => { +test('cloudflare temp email settings payload ignores removed UI-only flags', () => { const api = new Function(` const DEFAULT_VERIFICATION_RESEND_COUNT = 4; const PERSISTED_SETTING_DEFAULTS = { panelMode: 'cpa', - oauthFlowTimeoutEnabled: true, autoStepDelaySeconds: null, verificationResendCount: DEFAULT_VERIFICATION_RESEND_COUNT, mailProvider: '163', @@ -222,15 +221,10 @@ return { }; `)(); - assert.equal(api.normalizePersistentSettingValue('oauthFlowTimeoutEnabled', 0), false); - assert.equal(api.normalizePersistentSettingValue('oauthFlowTimeoutEnabled', 1), true); - assert.deepEqual(api.buildPersistentSettingsPayload({ - oauthFlowTimeoutEnabled: false, - }), { - oauthFlowTimeoutEnabled: false, - }); + removedUiOnlyFlag: false, + }), {}); const defaults = api.buildPersistentSettingsPayload({}, { fillDefaults: true }); - assert.equal(defaults.oauthFlowTimeoutEnabled, true); + assert.equal(Object.prototype.hasOwnProperty.call(defaults, 'removedUiOnlyFlag'), false); }); diff --git a/tests/flow-capabilities-module.test.js b/tests/flow-capabilities-module.test.js index b2192a1..ba15192 100644 --- a/tests/flow-capabilities-module.test.js +++ b/tests/flow-capabilities-module.test.js @@ -27,6 +27,7 @@ test('flow capability registry keeps OpenAI phone signup available only when run assert.equal(enabledState.canUsePhoneSignup, true); assert.equal(enabledState.effectiveSignupMethod, 'phone'); assert.equal(enabledState.shouldWarnCpaPhoneSignup, true); + assert.equal(enabledState.targetCapabilities.usesOauthTimeoutBudget, true); assert.deepEqual(enabledState.effectiveSignupMethods, ['email', 'phone']); const plusLockedState = registry.resolveSidepanelCapabilities({ @@ -43,6 +44,7 @@ test('flow capability registry keeps OpenAI phone signup available only when run assert.equal(plusLockedState.canUsePhoneSignup, false); assert.equal(plusLockedState.effectiveSignupMethod, 'email'); assert.equal(plusLockedState.shouldWarnCpaPhoneSignup, false); + assert.equal(plusLockedState.targetCapabilities.usesOauthTimeoutBudget, false); assert.deepEqual(plusLockedState.effectiveSignupMethods, ['email']); }); diff --git a/tests/flow-registry-settings-schema.test.js b/tests/flow-registry-settings-schema.test.js index 21fae27..3857092 100644 --- a/tests/flow-registry-settings-schema.test.js +++ b/tests/flow-registry-settings-schema.test.js @@ -29,6 +29,14 @@ test('flow registry exposes canonical flow and target metadata', () => { flowRegistry.getFlowDefinition('openai')?.targets?.cpa?.defaultState, { vpsUrl: '', vpsPassword: '', localCpaStep9Mode: 'submit' } ); + assert.equal( + flowRegistry.getTargetCapabilities('openai', 'cpa')?.usesOauthTimeoutBudget, + true + ); + assert.equal( + flowRegistry.getTargetCapabilities('openai', 'sub2api')?.usesOauthTimeoutBudget, + undefined + ); assert.deepEqual( flowRegistry.getFlowDefinition('kiro')?.targets?.['kiro-rs']?.defaultState, { baseUrl: '', apiKey: '' } diff --git a/tests/sidepanel-contribution-mode.test.js b/tests/sidepanel-contribution-mode.test.js index 85a95e0..6949471 100644 --- a/tests/sidepanel-contribution-mode.test.js +++ b/tests/sidepanel-contribution-mode.test.js @@ -248,7 +248,6 @@ const inputTempEmailUseRandomSubdomain = { checked: true }; const inputAutoSkipFailures = { checked: false }; const inputAutoSkipFailuresThreadIntervalMinutes = { value: '5' }; const inputAutoStepDelaySeconds = { value: '10' }; -const inputOAuthFlowTimeoutEnabled = { checked: true }; const inputVerificationResendCount = { value: '6' }; const DEFAULT_VERIFICATION_RESEND_COUNT = 4; const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms'; diff --git a/tests/sidepanel-icloud-provider.test.js b/tests/sidepanel-icloud-provider.test.js index bd5c5fb..4526d32 100644 --- a/tests/sidepanel-icloud-provider.test.js +++ b/tests/sidepanel-icloud-provider.test.js @@ -133,7 +133,6 @@ const inputTempEmailUseRandomSubdomain = { checked: false }; const inputAutoSkipFailures = { checked: false }; const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' }; const inputAutoStepDelaySeconds = { value: '' }; -const inputOAuthFlowTimeoutEnabled = { checked: true }; const inputVerificationResendCount = { value: '4' }; const DEFAULT_VERIFICATION_RESEND_COUNT = 4; const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms'; @@ -406,7 +405,6 @@ const inputLuckmailDomain = { value: '' }; const inputAutoSkipFailures = { checked: false }; const inputAutoSkipFailuresThreadIntervalMinutes = { value: '' }; const inputAutoStepDelaySeconds = { value: '' }; -const inputOAuthFlowTimeoutEnabled = { checked: true }; const inputVerificationResendCount = { value: '' }; const inputPhoneVerificationEnabled = { checked: false }; const selectPhoneSmsProvider = { value: 'hero-sms' }; diff --git a/tests/sidepanel-mail2925-base-email.test.js b/tests/sidepanel-mail2925-base-email.test.js index e10cb2b..3b737f6 100644 --- a/tests/sidepanel-mail2925-base-email.test.js +++ b/tests/sidepanel-mail2925-base-email.test.js @@ -204,7 +204,6 @@ const inputTempEmailUseRandomSubdomain = { checked: false }; const inputAutoSkipFailures = { checked: false }; const inputAutoSkipFailuresThreadIntervalMinutes = { value: '0' }; const inputAutoStepDelaySeconds = { value: '' }; -const inputOAuthFlowTimeoutEnabled = { checked: true }; const inputVerificationResendCount = { value: '4' }; const DEFAULT_VERIFICATION_RESEND_COUNT = 4; const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms'; diff --git a/tests/sidepanel-operation-delay.test.js b/tests/sidepanel-operation-delay.test.js index f63a95d..4b9c9bf 100644 --- a/tests/sidepanel-operation-delay.test.js +++ b/tests/sidepanel-operation-delay.test.js @@ -48,7 +48,6 @@ test('sidepanel splits shared auto-run controls from openai oauth controls', () const step6CookieIndex = html.indexOf('id="row-step6-cookie-settings"'); const sharedAutoRunIndex = html.indexOf('id="row-shared-auto-run"'); const threadIntervalIndex = html.indexOf('id="row-auto-run-thread-interval"'); - const oauthTimeoutIndex = html.indexOf('id="row-oauth-flow-timeout"'); const stepRangeIndex = html.indexOf('id="row-step-execution-range"'); const oauthDisplayIndex = html.indexOf('id="row-oauth-display"'); const oauthCallbackIndex = html.indexOf('id="row-oauth-callback"'); @@ -57,15 +56,15 @@ test('sidepanel splits shared auto-run controls from openai oauth controls', () assert.notEqual(step6CookieIndex, -1); assert.notEqual(sharedAutoRunIndex, -1); assert.notEqual(threadIntervalIndex, -1); - assert.notEqual(oauthTimeoutIndex, -1); + assert.doesNotMatch(html, /id="row-oauth-flow-timeout"/); + assert.doesNotMatch(html, /id="input-oauth-flow-timeout-enabled"/); assert.notEqual(stepRangeIndex, -1); assert.notEqual(oauthDisplayIndex, -1); assert.notEqual(oauthCallbackIndex, -1); assert.notEqual(settingsActionsIndex, -1); assert.ok(sharedAutoRunIndex > step6CookieIndex, 'shared auto-run should render below the openai step6 cookie row'); assert.ok(threadIntervalIndex > sharedAutoRunIndex, 'thread interval should be part of the shared auto-run block'); - assert.ok(threadIntervalIndex < oauthTimeoutIndex, 'thread interval should stay outside openai oauth controls'); - assert.ok(stepRangeIndex > oauthTimeoutIndex, 'step execution range should render below oauth timeout'); + assert.ok(stepRangeIndex > threadIntervalIndex, 'step execution range should render below shared thread interval'); assert.ok(stepRangeIndex < oauthDisplayIndex, 'step execution range should stay above oauth runtime display'); assert.ok(oauthCallbackIndex > oauthDisplayIndex, 'openai callback row should follow the oauth display'); assert.ok(settingsActionsIndex > oauthCallbackIndex, 'save settings action should live outside the callback row'); diff --git a/项目完整链路说明.md b/项目完整链路说明.md index f457ee6..80078dd 100644 --- a/项目完整链路说明.md +++ b/项目完整链路说明.md @@ -281,7 +281,7 @@ - Kiro 目标配置:`flows.kiro.targetId` 与 `flows.kiro.targets["kiro-rs"] = { baseUrl, apiKey }` - 自动运行默认配置 - 操作间延迟兼容字段 `operationDelayEnabled`:当前会被严格归一为启用;sidepanel 不再暴露真正关闭入口,但内容脚本仍通过 `chrome.storage.local` 监听该字段完成兼容同步 -- OAuth 授权后链总超时开关 `oauthFlowTimeoutEnabled`:默认开启;关闭后会立即清空已存在的 OAuth 总预算 deadline,仅保留各步骤本地等待超时 +- OAuth 授权后链总超时:不再作为侧栏配置项持久化,只由 `openai + cpa` target capability 自动启用;其他来源与 flow 不启动 OAuth 总预算,仅保留各步骤本地等待超时 - flow 级执行范围配置 `stepExecutionRangeByFlow`:按 flowId 保存,例如 `openai: { enabled: true, fromStep: 3, toStep: 6 }`;侧栏中的 `codex` 会归一到内部默认 flowId `openai`。这是通用配置结构,但当前只给 codex/openai flow 暴露 UI。 - 账号运行历史 `accountRunHistory`(以统一账号标识为主键;邮箱账号保留邮箱主键,手机号注册保留手机号主键;同一轮中后续绑定的邮箱或手机号会写入同一条记录的副身份字段,保存最近一次状态:成功/失败/停止) - 账号运行历史本地同步 helper 地址 diff --git a/项目文件结构说明.md b/项目文件结构说明.md index 8c8669e..3e90ee6 100644 --- a/项目文件结构说明.md +++ b/项目文件结构说明.md @@ -21,7 +21,7 @@ - `.gitignore`:定义仓库忽略规则,当前忽略 `docs/md/`、`.github/`、`_metadata/`、`.vscode/` 等目录。 - `LICENSE`:项目许可证文件。 - `README.md`:面向使用者的精简说明文档,主要介绍项目用途、功能范围、快速开始与文档入口;不再承载过多技术实现细节。 -- `background.js`:扩展后台 Service Worker 入口壳,负责模块装配、初始化、全局常量、少量保留的领域函数与运行入口;当前已按 `activeFlowId` 装配 flow-aware 的步骤定义、执行注册表、自动运行与状态同步,`openai` flow 继续承接 `oauthFlowTimeoutEnabled` 与 `stepExecutionRangeByFlow`,`kiro` flow 走独立的“注册页 1-6 步 -> 桌面授权 7-8 步 -> `kiro.rs` 上传 9 步”链路,`grok` flow 走独立的“注册页 1-4 步 -> SSO Cookie 提取 5 步 -> `webchat2api` 上传 6 步”链路。 +- `background.js`:扩展后台 Service Worker 入口壳,负责模块装配、初始化、全局常量、少量保留的领域函数与运行入口;当前已按 `activeFlowId` 装配 flow-aware 的步骤定义、执行注册表、自动运行与状态同步,OAuth 后链 5 分钟总预算只由 `openai + cpa` target capability 自动启用,其他来源与 flow 不启用该预算;`openai` flow 继续承接 `stepExecutionRangeByFlow`,`kiro` flow 走独立的“注册页 1-6 步 -> 桌面授权 7-8 步 -> `kiro.rs` 上传 9 步”链路,`grok` flow 走独立的“注册页 1-4 步 -> SSO Cookie 提取 5 步 -> `webchat2api` 上传 6 步”链路。 - `cloudmail-utils.js`:Cloud Mail / SkyMail 相关的纯工具函数,负责 API 地址、域名、鉴权头、邮件列表响应与邮件正文归一化。 - `cloudflare-temp-email-utils.js`:Cloudflare Temp Email 相关的纯工具函数,负责 URL、域名、邮件内容与 MIME 数据归一化。 - `gopay-utils.js`:GoPay / GPC Plus 支付相关纯工具函数,负责支付方式归一化、GoPay 手机号/OTP/PIN 归一化、GPC API 地址归一化、API Key 请求头、任务创建/查询/OTP/PIN/停止 URL 与余额响应解析。 @@ -68,7 +68,7 @@ - `background/mail-2925-session.js`:2925 会话模块,负责 2925 账号池持久化、当前账号切换、cookie 清理登出、自动登录、命中“子邮箱已达上限邮箱”后的 24 小时禁用与自动切号。 - `background/mail-rule-registry.js`:flow-aware 邮件规则注册表,负责按 `activeFlowId` 选择验证码规则构造器,并统一输出注册/登录验证码轮询 payload。 - `background/flow-mail-polling.js`:flow-aware 邮件轮询调度层,负责读取共享邮箱配置、调用当前 flow 的 mail rules、分派 Hotmail / LuckMail / Cloudflare Temp Email / Cloud Mail / YYDS Mail API provider、准备 iCloud / 2925 / 网页邮箱会话,并统一通过邮箱内容脚本轮询验证码。 -- `background/message-router.js`:后台消息路由层,负责处理 `chrome.runtime.onMessage` 进入的所有业务消息;`LOG / STEP_COMPLETE / STEP_ERROR` 会把消息里的真实 `step` 继续传给结构化日志,跳过登录验证码这类派生日志也按当前步骤 key 写入;当前额外接入 PayPal 账号池的新增与切换、2925 账号池的新增、导入、切换、登录、禁用与删除消息,以及 IP 代理的同步、切换、Change 与出口检测消息;手动改邮箱、手动取邮箱等入口也统一经这里落到 `setEmailState`,同步维护注册邮箱运行态;当侧栏关闭 `oauthFlowTimeoutEnabled` 时,会立即清空已存在的 OAuth 总预算 deadline;手动 `EXECUTE_NODE` 会先按 `stepExecutionRangeByFlow` 校验当前节点是否允许执行。 +- `background/message-router.js`:后台消息路由层,负责处理 `chrome.runtime.onMessage` 进入的所有业务消息;`LOG / STEP_COMPLETE / STEP_ERROR` 会把消息里的真实 `step` 继续传给结构化日志,跳过登录验证码这类派生日志也按当前步骤 key 写入;当前额外接入 PayPal 账号池的新增与切换、2925 账号池的新增、导入、切换、登录、禁用与删除消息,以及 IP 代理的同步、切换、Change 与出口检测消息;手动改邮箱、手动取邮箱等入口也统一经这里落到 `setEmailState`,同步维护注册邮箱运行态;手动 `EXECUTE_NODE` 会先按 `stepExecutionRangeByFlow` 校验当前节点是否允许执行。 - `background/registration-email-state.js`:注册邮箱运行态共享模块,负责维护 `registrationEmailState = { current, previous, source, updatedAt }`,并提供“当前邮箱清空时保留上一比较基线”“Duck 生成前解析比较基线”“Step 8 `add-email` 写入邮箱时按需保留手机号身份”的统一工具。 - `core/flow-kernel/runtime-state.js`:运行态视图与 patch 构造模块,负责把会话字段归一到 `runtimeState / sharedState / serviceState / flowState` 结构,并维护 flow-aware 的 session patch、节点状态默认值与兼容视图输出。 - `background/navigation-utils.js`:导航与 URL 判断工具层,负责 callback、入口页、CPA / SUB2API / Codex2API 地址归一化、来源标签页家族判断与步骤跳转相关判断。 @@ -84,7 +84,7 @@ ## `background/steps/` - `flows/openai/background/steps/wait-registration-success.js`:步骤 6 实现,负责注册资料提交后等待 20 秒,让注册成功状态和页面跳转稳定;默认不清理 cookies,只有侧栏第六步 `清 Cookies` 开关开启时才会在等待结束后清理 ChatGPT / OpenAI 相关 cookies。 -- `flows/openai/background/steps/confirm-oauth.js`:步骤 9 实现,负责 OAuth 同意页按钮定位、点击、localhost 回调监听与回调完成;等待 callback 期间会动态检查 OAuth 总预算开关,关闭后仅保留本地回调等待超时。 +- `flows/openai/background/steps/confirm-oauth.js`:步骤 9 实现,负责 OAuth 同意页按钮定位、点击、localhost 回调监听与回调完成;等待 callback 期间会动态检查 OAuth 总预算,只有 `openai + cpa` 来源启用 5 分钟后链预算,其他来源和 flow 仅保留本地回调等待超时。 - `flows/openai/background/steps/create-plus-checkout.js`:Plus 模式第 6 步实现,负责在已登录 ChatGPT 页面创建 PayPal / GoPay checkout session,或在 GPC 模式下读取 accessToken 并通过 `https://gpc.qlhazycoder.top/api/gp/tasks` 创建队列任务,记录 checkout / GPC task 运行态。 - `flows/openai/background/steps/fetch-login-code.js`:步骤 8 实现,负责按真实认证页状态分发登录后续流程:邮箱验证码页走邮箱轮询、验证码回填与回退控制;真实 `phone-verification` 页才复用 OpenAI 专属手机号验证码流程;手机号注册登录后若进入 `add-email`,会先按共享邮箱状态持久化规则生成/解析邮箱并提交绑定,在不丢失当前手机号身份的前提下再进入邮箱验证码轮询;邮箱分支对非 2925 provider 会固定当前验证码页显示邮箱作为本次 Step 8 的目标邮箱,当 provider 为 2925 时,会在轮询前先确保当前 2925 账号已自动登录;命中 `email_in_use` 时会仅清空当前邮箱并保留上一轮比较基线,再在当前 Step 8 内重开 `add-email` 获取新邮箱,`max_check_attempts` 也只重启当前步骤恢复链。 - `flows/openai/background/steps/fetch-signup-code.js`:步骤 4 实现,负责注册验证码阶段的页面准备与验证码流程入口;邮箱注册继续走邮箱验证码,手机号注册改走短信验证码;当 provider 为 2925 时,会在邮箱轮询前先确保当前 2925 账号已自动登录。 @@ -217,7 +217,7 @@ receive 模式把账号池开关一起隐藏;当前在 `邮箱生成` 区域新增 `自定义邮箱池` 选项和多行邮箱池输入框,并在 `邮箱服务 = 自定义邮箱` 时 额外显示 `自定义号池` 文本框;当邮箱服务为 iCloud 时,额外提供目标邮箱类型与转发邮箱 provider 配置,用于选择直接从 iCloud 收件箱收 码或从 QQ / 网易 / Gmail 转发目标邮箱收码;当邮箱服务或邮箱生成器为 Cloud Mail 时,额外显示 API 地址、管理员账号、接收邮箱和生成域名配置行;当邮箱服务为 YYDS Mail 时,额外显示 API Key 与 Base URL 配置行,并隐藏普通邮箱生成/转发邮箱相关配置;来源下拉框当前支持 `CPA / SUB2API / Codex2API`,其中 Codex2API 额外提供后台地址和管理密 - 钥配置行;设置卡片新增 `IP代理` 开关与代理配置折叠区,支持 711Proxy 账号密码模式、代理状态卡与出口检测按钮;接码卡内把注册方式、接码配置、接码订单运行态与“注册手机号”身份运行态分层展示,“注册手机号”位于订单运行状态下方,不嵌入当前分配/验证码网格;设置卡片新增 `Plus 模式` 开关,并在 `Plus 支付` 之上新增 `账号接入策略` 下拉;该下拉只显示 `OAuth / 使用会话 JSON 导入` 两种接入方式,会话导入目标由当前来源自动决定,不支持的来源会直接禁用并显示“当前来源仅支持 OAuth”;PayPal 账号下拉框继续使用公共表单弹窗添加账号;GPC Plus 配置额外提供只读 API 地址、API Key、专用手机号、OTP 渠道、本地 OTP helper 开关、helper URL 与 PIN,并提供 `购买卡密` 与 `转换 API Key` 入口;Hotmail / 2925 两个账号池当前都使用统一的头部“添加账号/取消添加”按钮和共享表单容器;设置卡片还新增“授权总超时”开关,用于控制 Step 7 后链 5 分钟总预算;注册邮箱下方新增 `执行范围` 行,目前只在 codex/openai flow 显示,用于配置允许执行的起止步骤。 + 钥配置行;设置卡片新增 `IP代理` 开关与代理配置折叠区,支持 711Proxy 账号密码模式、代理状态卡与出口检测按钮;接码卡内把注册方式、接码配置、接码订单运行态与“注册手机号”身份运行态分层展示,“注册手机号”位于订单运行状态下方,不嵌入当前分配/验证码网格;设置卡片新增 `Plus 模式` 开关,并在 `Plus 支付` 之上新增 `账号接入策略` 下拉;该下拉只显示 `OAuth / 使用会话 JSON 导入` 两种接入方式,会话导入目标由当前来源自动决定,不支持的来源会直接禁用并显示“当前来源仅支持 OAuth”;PayPal 账号下拉框继续使用公共表单弹窗添加账号;GPC Plus 配置额外提供只读 API 地址、API Key、专用手机号、OTP 渠道、本地 OTP helper 开关、helper URL 与 PIN,并提供 `购买卡密` 与 `转换 API Key` 入口;Hotmail / 2925 两个账号池当前都使用统一的头部“添加账号/取消添加”按钮和共享表单容器;注册邮箱下方新增 `执行范围` 行,目前只在 codex/openai flow 显示,用于配置允许执行的起止步骤。 - `sidepanel/paypal-manager.js`:侧边栏 PayPal 账号管理器,负责 Plus 模式下的账号下拉框渲染、添加账号弹窗、保存账号与切换当前账号。 - `sidepanel/sidepanel.js`:侧边栏主入口脚本,负责 UI 状态同步、动态步骤渲染、按钮交互、共享验证码自动重发次数配置与广播接收,并装 配 Hotmail / 2925 / iCloud / LuckMail / 贡献模式 / 账号记录面板 / 贡献内容更新服务;当前贡献模式的“开始贡献”会直接复用主自动流程启 @@ -231,7 +231,7 @@ 会在 sidepanel 初始化时拉取并恢复到本地保存的国家/API 设置,接码开关关闭时会直接隐藏相关配置;账号记录快照同步改为默认自动模式,只 要本地 helper 可用就会自动落盘;新来源 Codex2API 在这里仅补充来源配置接线、表单显隐和 Step 10 按钮文案,不承接协议业务逻辑; Hotmail / 2925 的新增表单显隐统一接到 `sidepanel/account-pool-ui.js` 这一层共享 helper;IP 代理配置保存、服务配置快照、开关应用和运行态回显由这里接入消息路由,具体解析/状态渲染下沉到 `sidepanel/ip-proxy-panel.js`;侧边栏初始化与点击“自动”前会刷新一次贡献站 - 公开内容摘要,并按本地关闭版本决定是否展示轻提示,同时在首次初始化后按现有规则决定是否弹出新手引导提示;当前会保存、回显并热更新 `oauthFlowTimeoutEnabled` 设置;日志渲染只读取结构化 `entry.step` 生成步骤标签,不再正则解析日志正文;注册手机号输入框只同步运行态身份,不写入持久配置。 + 公开内容摘要,并按本地关闭版本决定是否展示轻提示,同时在首次初始化后按现有规则决定是否弹出新手引导提示;日志渲染只读取结构化 `entry.step` 生成步骤标签,不再正则解析日志正文;注册手机号输入框只同步运行态身份,不写入持久配置。 - `sidepanel/update-service.js`:侧边栏更新检查服务,负责 GitHub Releases 查询、`Ultra` / 历史 `Pro` / legacy `v` 版本族排序、缓存读取与版本展示。 - 补充:`sidepanel/sidepanel.html` 与 `sidepanel/sidepanel.js` 当前已改为 flow-aware 侧边栏主界面;顶部提供 `flow/target` 双层选择,`openai` flow 继续把 `panelMode` 归一为 integration target,`kiro` flow 则使用独立 `targetId` 与 `kiro.rs URL / API Key` 专属字段,并只显示 Kiro 运行状态与共享邮箱/IP 代理配置。