diff --git a/README.md b/README.md index e87ebfe..523fb4c 100644 --- a/README.md +++ b/README.md @@ -605,7 +605,7 @@ Cloudflare 模式下,插件不会再调用 Cloudflare API 创建路由。 这一步只负责等待注册完成后的页面状态稳定: - 固定等待 20 秒 -- 不再清理 `chatgpt.com / openai.com` 相关 cookies +- 默认不清理 `chatgpt.com / openai.com` 相关 cookies;侧栏开启第六步 `清 Cookies` 后才会在等待结束后执行清理 - 等待完成后直接进入后续 OAuth 登录链路 diff --git a/background.js b/background.js index 688b0d4..4e67c5c 100644 --- a/background.js +++ b/background.js @@ -239,7 +239,7 @@ const SUB2API_STEP1_RESPONSE_TIMEOUT_MS = 90000; const SUB2API_STEP9_RESPONSE_TIMEOUT_MS = 120000; const DEFAULT_SUB2API_URL = 'https://sub2api.hisence.fun/admin/accounts'; const DEFAULT_CODEX2API_URL = 'http://localhost:8080/admin/accounts'; -const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.leftcode.xyz'; +const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.qlhazycoder.top'; const DEFAULT_SUB2API_GROUP_NAME = 'codex'; const DEFAULT_SUB2API_PROXY_NAME = ''; const DEFAULT_SUB2API_ACCOUNT_PRIORITY = 1; @@ -646,6 +646,7 @@ const PERSISTED_SETTING_DEFAULTS = { autoRunDelayEnabled: false, autoRunDelayMinutes: 30, autoStepDelaySeconds: null, + step6CookieCleanupEnabled: false, phoneVerificationEnabled: false, freePhoneReuseEnabled: true, freePhoneReuseAutoEnabled: true, @@ -2304,11 +2305,15 @@ function normalizePersistentSettingValue(key, value) { ); case 'gopayHelperApiUrl': { + const legacyGpcHelperApiUrl = 'https://gpc.leftcode.xyz'; const defaultGpcHelperApiUrl = PERSISTED_SETTING_DEFAULTS.gopayHelperApiUrl - || (typeof DEFAULT_GPC_HELPER_API_URL !== 'undefined' ? DEFAULT_GPC_HELPER_API_URL : 'https://gpc.leftcode.xyz'); - return self.GoPayUtils?.normalizeGpcHelperBaseUrl + || (typeof DEFAULT_GPC_HELPER_API_URL !== 'undefined' ? DEFAULT_GPC_HELPER_API_URL : 'https://gpc.qlhazycoder.top'); + const normalizedGpcHelperApiUrl = self.GoPayUtils?.normalizeGpcHelperBaseUrl ? self.GoPayUtils.normalizeGpcHelperBaseUrl(value || defaultGpcHelperApiUrl) : String(value || defaultGpcHelperApiUrl).trim().replace(/\/+$/g, ''); + return normalizedGpcHelperApiUrl === legacyGpcHelperApiUrl + ? defaultGpcHelperApiUrl + : normalizedGpcHelperApiUrl; } case 'gopayHelperApiKey': case 'gopayHelperCardKey': @@ -2342,6 +2347,7 @@ function normalizePersistentSettingValue(key, value) { case 'oauthFlowTimeoutEnabled': case 'gopayHelperLocalSmsHelperEnabled': case 'autoRunDelayEnabled': + case 'step6CookieCleanupEnabled': case 'phoneVerificationEnabled': case 'freePhoneReuseEnabled': case 'freePhoneReuseAutoEnabled': @@ -10680,7 +10686,9 @@ const step5Executor = self.MultiPageBackgroundStep5?.createStep5Executor({ }); const step6Executor = self.MultiPageBackgroundStep6?.createStep6Executor({ addLog, + chrome, completeStepFromBackground, + getErrorMessage, registrationSuccessWaitMs: STEP6_REGISTRATION_SUCCESS_WAIT_MS, sleepWithStop, }); @@ -10843,7 +10851,7 @@ const stepExecutorsByKey = { 'fill-password': (state) => step3Executor.executeStep3(state), 'fetch-signup-code': (state) => step4Executor.executeStep4(state), 'fill-profile': (state) => step5Executor.executeStep5(state), - 'wait-registration-success': () => step6Executor.executeStep6(), + 'wait-registration-success': (state) => step6Executor.executeStep6(state), 'plus-checkout-create': (state) => plusCheckoutCreateExecutor.executePlusCheckoutCreate(state), 'plus-checkout-billing': (state) => plusCheckoutBillingExecutor.executePlusCheckoutBilling(state), 'gopay-subscription-confirm': (state) => goPayManualConfirmExecutor.executeGoPayManualConfirm(state), @@ -11724,8 +11732,8 @@ async function rerunStep7ForStep8Recovery(options = {}) { } } -async function executeStep6() { - return step6Executor.executeStep6(); +async function executeStep6(state = null) { + return step6Executor.executeStep6(state || await getState()); } // ============================================================ diff --git a/background/steps/create-plus-checkout.js b/background/steps/create-plus-checkout.js index f1ee9f5..c22cb30 100644 --- a/background/steps/create-plus-checkout.js +++ b/background/steps/create-plus-checkout.js @@ -7,7 +7,7 @@ const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal'; const PLUS_PAYMENT_METHOD_GOPAY = 'gopay'; const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper'; - const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.leftcode.xyz'; + const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.qlhazycoder.top'; function createPlusCheckoutCreateExecutor(deps = {}) { const { diff --git a/background/steps/fill-plus-checkout.js b/background/steps/fill-plus-checkout.js index 7cd00c0..d294ca6 100644 --- a/background/steps/fill-plus-checkout.js +++ b/background/steps/fill-plus-checkout.js @@ -10,7 +10,7 @@ const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal'; const PLUS_PAYMENT_METHOD_GOPAY = 'gopay'; const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper'; - const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.leftcode.xyz'; + const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.qlhazycoder.top'; const GPC_TASK_POLL_INTERVAL_MS = 3000; const PAYMENT_METHOD_CONFIGS = { [PLUS_PAYMENT_METHOD_PAYPAL]: { diff --git a/background/steps/wait-registration-success.js b/background/steps/wait-registration-success.js index 76ffe46..945bfd2 100644 --- a/background/steps/wait-registration-success.js +++ b/background/steps/wait-registration-success.js @@ -2,21 +2,152 @@ root.MultiPageBackgroundStep6 = factory(); })(typeof self !== 'undefined' ? self : globalThis, function createBackgroundStep6Module() { const DEFAULT_REGISTRATION_SUCCESS_WAIT_MS = 20000; + const STEP6_COOKIE_CLEAR_DOMAINS = [ + 'chatgpt.com', + 'chat.openai.com', + 'openai.com', + 'auth.openai.com', + 'auth0.openai.com', + 'accounts.openai.com', + ]; + const STEP6_COOKIE_CLEAR_ORIGINS = [ + 'https://chatgpt.com', + 'https://chat.openai.com', + 'https://auth.openai.com', + 'https://auth0.openai.com', + 'https://accounts.openai.com', + 'https://openai.com', + ]; + + function normalizeStep6CookieDomain(domain) { + return String(domain || '').trim().replace(/^\.+/, '').toLowerCase(); + } + + function shouldClearStep6Cookie(cookie) { + const domain = normalizeStep6CookieDomain(cookie?.domain); + if (!domain) return false; + return STEP6_COOKIE_CLEAR_DOMAINS.some((target) => ( + domain === target || domain.endsWith(`.${target}`) + )); + } + + function buildStep6CookieRemovalUrl(cookie) { + const host = normalizeStep6CookieDomain(cookie?.domain); + const rawPath = String(cookie?.path || '/'); + const path = rawPath.startsWith('/') ? rawPath : `/${rawPath}`; + return `https://${host}${path}`; + } + + async function collectStep6Cookies(chromeApi) { + if (!chromeApi.cookies?.getAll) { + return []; + } + + const stores = chromeApi.cookies.getAllCookieStores + ? await chromeApi.cookies.getAllCookieStores() + : [{ id: undefined }]; + const cookies = []; + const seen = new Set(); + + for (const store of stores) { + const storeId = store?.id; + const batch = await chromeApi.cookies.getAll(storeId ? { storeId } : {}); + for (const cookie of batch || []) { + if (!shouldClearStep6Cookie(cookie)) continue; + const key = [ + cookie.storeId || storeId || '', + cookie.domain || '', + cookie.path || '', + cookie.name || '', + cookie.partitionKey ? JSON.stringify(cookie.partitionKey) : '', + ].join('|'); + if (seen.has(key)) continue; + seen.add(key); + cookies.push(cookie); + } + } + + return cookies; + } + + async function removeStep6Cookie(chromeApi, cookie, getErrorMessage) { + const details = { + url: buildStep6CookieRemovalUrl(cookie), + name: cookie.name, + }; + if (cookie.storeId) { + details.storeId = cookie.storeId; + } + if (cookie.partitionKey) { + details.partitionKey = cookie.partitionKey; + } + + try { + const result = await chromeApi.cookies.remove(details); + return Boolean(result); + } catch (error) { + console.warn('[MultiPage:step6] remove cookie failed', { + domain: cookie?.domain, + name: cookie?.name, + message: getErrorMessage(error), + }); + return false; + } + } function createStep6Executor(deps = {}) { const { addLog = async () => {}, + chrome: chromeApi = globalThis.chrome, completeStepFromBackground, + getErrorMessage = (error) => error?.message || String(error || '未知错误'), registrationSuccessWaitMs = DEFAULT_REGISTRATION_SUCCESS_WAIT_MS, sleepWithStop = async (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, Number(ms) || 0))), } = deps; - async function executeStep6() { + async function clearCookiesIfEnabled(state = {}) { + if (!state?.step6CookieCleanupEnabled) { + return; + } + if (!chromeApi?.cookies?.getAll || !chromeApi.cookies?.remove) { + await addLog('步骤 6:当前浏览器不支持 cookies API,跳过第六步 Cookies 清理。', 'warn'); + return; + } + + try { + await addLog('步骤 6:已开启 Cookies 清理,正在清理 ChatGPT / OpenAI cookies...', 'info'); + const cookies = await collectStep6Cookies(chromeApi); + let removedCount = 0; + for (const cookie of cookies) { + if (await removeStep6Cookie(chromeApi, cookie, getErrorMessage)) { + removedCount += 1; + } + } + + if (chromeApi.browsingData?.removeCookies) { + try { + await chromeApi.browsingData.removeCookies({ + since: 0, + origins: STEP6_COOKIE_CLEAR_ORIGINS, + }); + } catch (error) { + await addLog(`步骤 6:browsingData 补扫 cookies 失败:${getErrorMessage(error)}`, 'warn'); + } + } + + await addLog(`步骤 6:已清理 ${removedCount} 个 ChatGPT / OpenAI cookies。`, 'ok'); + } catch (error) { + await addLog(`步骤 6:Cookies 清理失败,已跳过并继续后续流程:${getErrorMessage(error)}`, 'warn'); + } + } + + async function executeStep6(state = {}) { const waitMs = Math.max(0, Math.floor(Number(registrationSuccessWaitMs) || 0)); if (waitMs > 0) { await addLog(`步骤 6:等待 ${Math.round(waitMs / 1000)} 秒,确认注册成功并让页面稳定...`, 'info'); await sleepWithStop(waitMs); } + await clearCookiesIfEnabled(state); await addLog('步骤 6:注册成功等待完成,准备继续获取 OAuth 链接并登录。', 'ok'); await completeStepFromBackground(6); } diff --git a/gopay-utils.js b/gopay-utils.js index eac491b..0fe3e9b 100644 --- a/gopay-utils.js +++ b/gopay-utils.js @@ -4,7 +4,8 @@ const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal'; const PLUS_PAYMENT_METHOD_GOPAY = 'gopay'; const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper'; - const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.leftcode.xyz'; + const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.qlhazycoder.top'; + const LEGACY_GPC_HELPER_API_URL = 'https://gpc.leftcode.xyz'; function normalizePlusPaymentMethod(value = '') { const normalized = String(value || '').trim().toLowerCase(); @@ -66,6 +67,9 @@ normalized = normalized.replace(/\/api\/gp\/balance(?:\?.*)?$/i, ''); normalized = normalized.replace(/\/api\/card\/balance(?:\?.*)?$/i, ''); normalized = normalized.replace(/\/api\/card\/redeem-api-key(?:\?.*)?$/i, ''); + if (normalized === LEGACY_GPC_HELPER_API_URL) { + return DEFAULT_GPC_HELPER_API_URL; + } return normalized || DEFAULT_GPC_HELPER_API_URL; } diff --git a/sidepanel/sidepanel.css b/sidepanel/sidepanel.css index 2c4fc3f..7036555 100644 --- a/sidepanel/sidepanel.css +++ b/sidepanel/sidepanel.css @@ -1971,6 +1971,16 @@ header { .data-select:focus { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-soft); } [data-theme="dark"] .data-select { color-scheme: dark; } +.data-input[readonly] { + color: var(--text-secondary); + background: var(--bg-surface); + cursor: default; +} + +.gpc-helper-api-input { + font-family: 'JetBrains Mono', monospace; +} + .editable-list-picker { position: relative; flex: 1; @@ -2114,6 +2124,37 @@ header { justify-content: flex-end; } +.auto-delay-setting-pair { + flex-wrap: wrap; + row-gap: 8px; +} + +#row-auto-delay-settings .setting-group-primary { + flex: 0 0 auto; + min-width: 116px; +} + +#row-auto-delay-settings .setting-group-secondary { + margin-left: 0; + min-width: 0; +} + +.step6-cookie-cleanup-setting { + gap: 8px; +} + +.auto-run-delay-setting { + margin-left: auto !important; +} + +#row-auto-delay-settings .setting-caption { + min-width: auto; +} + +.setting-caption-left { + text-align: left; +} + .plus-payment-method-select { flex: 0 0 156px; min-width: 156px; diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html index e19cd84..0a5801c 100644 --- a/sidepanel/sidepanel.html +++ b/sidepanel/sidepanel.html @@ -264,7 +264,7 @@ GoPay GPC - 获取 API Key + 购买卡密 PayPal 订阅链路 @@ -285,8 +285,11 @@