fix: update API URLs and improve error handling for SUB2API configuration
This commit is contained in:
+14
-5
@@ -237,7 +237,7 @@ const STEP7_MAIL_POLLING_RECOVERY_MAX_ATTEMPTS = 8;
|
||||
const OAUTH_FLOW_TIMEOUT_MS = 5 * 60 * 1000;
|
||||
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_SUB2API_URL = '';
|
||||
const DEFAULT_CODEX2API_URL = 'http://localhost:8080/admin/accounts';
|
||||
const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.qlhazycoder.top';
|
||||
const DEFAULT_SUB2API_GROUP_NAME = 'codex';
|
||||
@@ -2305,15 +2305,23 @@ 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.qlhazycoder.top');
|
||||
const normalizedGpcHelperApiUrl = self.GoPayUtils?.normalizeGpcHelperBaseUrl
|
||||
? self.GoPayUtils.normalizeGpcHelperBaseUrl(value || defaultGpcHelperApiUrl)
|
||||
: String(value || defaultGpcHelperApiUrl).trim().replace(/\/+$/g, '');
|
||||
return normalizedGpcHelperApiUrl === legacyGpcHelperApiUrl
|
||||
? defaultGpcHelperApiUrl
|
||||
: normalizedGpcHelperApiUrl;
|
||||
if (!self.GoPayUtils?.normalizeGpcHelperBaseUrl) {
|
||||
try {
|
||||
const parsed = new URL(normalizedGpcHelperApiUrl);
|
||||
const hostname = parsed.hostname.toLowerCase();
|
||||
if (hostname !== 'gpc.qlhazycoder.top' && hostname !== 'localhost' && hostname !== '127.0.0.1') {
|
||||
return defaultGpcHelperApiUrl;
|
||||
}
|
||||
} catch {
|
||||
return defaultGpcHelperApiUrl;
|
||||
}
|
||||
}
|
||||
return normalizedGpcHelperApiUrl;
|
||||
}
|
||||
case 'gopayHelperApiKey':
|
||||
case 'gopayHelperCardKey':
|
||||
@@ -6777,6 +6785,7 @@ function normalizeSub2ApiUrl(rawUrl) {
|
||||
return navigationUtils.normalizeSub2ApiUrl(rawUrl);
|
||||
}
|
||||
const input = (rawUrl || '').trim() || DEFAULT_SUB2API_URL;
|
||||
if (!input) return '';
|
||||
const withProtocol = /^https?:\/\//i.test(input) ? input : `https://${input}`;
|
||||
const parsed = new URL(withProtocol);
|
||||
if (!parsed.pathname || parsed.pathname === '/') {
|
||||
|
||||
@@ -37,12 +37,10 @@
|
||||
const MAIL2925_COOKIE_DOMAINS = [
|
||||
'2925.com',
|
||||
'www.2925.com',
|
||||
'mail2.xiyouji.com',
|
||||
];
|
||||
const MAIL2925_COOKIE_ORIGINS = [
|
||||
'https://2925.com',
|
||||
'https://www.2925.com',
|
||||
'https://mail2.xiyouji.com',
|
||||
];
|
||||
const MAIL2925_LIMIT_ERROR_PREFIX = 'MAIL2925_LIMIT_REACHED::';
|
||||
const MAIL2925_THREAD_TERMINATED_ERROR_PREFIX = 'MAIL2925_THREAD_TERMINATED::';
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
function normalizeSub2ApiUrl(rawUrl) {
|
||||
const input = (rawUrl || '').trim() || DEFAULT_SUB2API_URL;
|
||||
if (!input) return '';
|
||||
const withProtocol = /^https?:\/\//i.test(input) ? input : `https://${input}`;
|
||||
const parsed = new URL(withProtocol);
|
||||
if (!parsed.pathname || parsed.pathname === '/') {
|
||||
|
||||
@@ -251,6 +251,9 @@
|
||||
const sub2apiUrl = normalizeSub2ApiUrl(state.sub2apiUrl);
|
||||
const groupName = (state.sub2apiGroupName || DEFAULT_SUB2API_GROUP_NAME).trim() || DEFAULT_SUB2API_GROUP_NAME;
|
||||
|
||||
if (!sub2apiUrl) {
|
||||
throw new Error('SUB2API URL is not configured. Please fill it in the side panel first.');
|
||||
}
|
||||
if (!state.sub2apiEmail) {
|
||||
throw new Error('尚未配置 SUB2API 登录邮箱,请先在侧边栏填写。');
|
||||
}
|
||||
|
||||
@@ -343,6 +343,9 @@
|
||||
}
|
||||
|
||||
const sub2apiUrl = normalizeSub2ApiUrl(state.sub2apiUrl);
|
||||
if (!sub2apiUrl) {
|
||||
throw new Error('SUB2API URL is not configured. Please fill it in the side panel first.');
|
||||
}
|
||||
const injectFiles = ['content/utils.js', 'content/sub2api-panel.js'];
|
||||
|
||||
await addStepLog(visibleStep, '正在打开 SUB2API 后台...');
|
||||
|
||||
+10
-3
@@ -5,7 +5,7 @@
|
||||
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
||||
const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper';
|
||||
const DEFAULT_GPC_HELPER_API_URL = 'https://gpc.qlhazycoder.top';
|
||||
const LEGACY_GPC_HELPER_API_URL = 'https://gpc.leftcode.xyz';
|
||||
const ALLOWED_GPC_HELPER_REMOTE_HOST = 'gpc.qlhazycoder.top';
|
||||
|
||||
function normalizePlusPaymentMethod(value = '') {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
@@ -67,10 +67,17 @@
|
||||
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) {
|
||||
|
||||
try {
|
||||
const parsed = new URL(normalized);
|
||||
const hostname = parsed.hostname.toLowerCase();
|
||||
if (hostname === ALLOWED_GPC_HELPER_REMOTE_HOST || hostname === 'localhost' || hostname === '127.0.0.1') {
|
||||
return normalized || DEFAULT_GPC_HELPER_API_URL;
|
||||
}
|
||||
return DEFAULT_GPC_HELPER_API_URL;
|
||||
} catch {
|
||||
return DEFAULT_GPC_HELPER_API_URL;
|
||||
}
|
||||
return normalized || DEFAULT_GPC_HELPER_API_URL;
|
||||
}
|
||||
|
||||
function buildGpcHelperApiUrl(apiUrl = '', path = '') {
|
||||
|
||||
+5
-3
@@ -6,7 +6,6 @@
|
||||
|
||||
root.HotmailUtils = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createHotmailUtils() {
|
||||
const HOTMAIL_MAIL_API_URL = 'https://apple.882263.xyz/api/mail-new';
|
||||
const HOTMAIL_SERVICE_MODE_REMOTE = 'remote';
|
||||
const HOTMAIL_SERVICE_MODE_LOCAL = 'local';
|
||||
|
||||
@@ -287,8 +286,11 @@
|
||||
return list.map((message) => normalizeHotmailMailApiMessage(message));
|
||||
}
|
||||
|
||||
function buildHotmailMailApiLatestUrl(options) {
|
||||
const apiUrl = String(options?.apiUrl || '').trim() || HOTMAIL_MAIL_API_URL;
|
||||
function buildHotmailMailApiLatestUrl(options = {}) {
|
||||
const apiUrl = String(options?.apiUrl || '').trim();
|
||||
if (!apiUrl) {
|
||||
throw new Error('Hotmail mail API URL is required.');
|
||||
}
|
||||
const url = new URL(apiUrl);
|
||||
url.searchParams.set('refresh_token', String(options?.refreshToken || ''));
|
||||
url.searchParams.set('client_id', String(options?.clientId || ''));
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
<div class="data-row" id="row-sub2api-url" style="display:none;">
|
||||
<span class="data-label">SUB2API</span>
|
||||
<input type="text" id="input-sub2api-url" class="data-input"
|
||||
placeholder="https://sub2api.hisence.fun/admin/accounts" />
|
||||
placeholder="https://your-sub2api-domain/admin/accounts" />
|
||||
</div>
|
||||
<div class="data-row" id="row-sub2api-email" style="display:none;">
|
||||
<span class="data-label">账号</span>
|
||||
|
||||
@@ -71,6 +71,20 @@ test('navigation utils support codex2api mode and url normalization', () => {
|
||||
assert.equal(utils.getPanelModeLabel('codex2api'), 'Codex2API');
|
||||
});
|
||||
|
||||
test('navigation utils leaves SUB2API url empty when no default is configured', () => {
|
||||
const source = fs.readFileSync('background/navigation-utils.js', 'utf8');
|
||||
const globalScope = {};
|
||||
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundNavigationUtils;`)(globalScope);
|
||||
const utils = api.createNavigationUtils({
|
||||
DEFAULT_CODEX2API_URL: 'http://localhost:8080/admin/accounts',
|
||||
DEFAULT_SUB2API_URL: '',
|
||||
normalizeLocalCpaStep9Mode: (value) => value,
|
||||
});
|
||||
|
||||
assert.equal(utils.normalizeSub2ApiUrl(''), '');
|
||||
});
|
||||
|
||||
test('navigation utils recognize the iCloud mail tab family on both supported hosts', () => {
|
||||
const source = fs.readFileSync('background/navigation-utils.js', 'utf8');
|
||||
const globalScope = {};
|
||||
|
||||
@@ -28,6 +28,7 @@ test('GoPay utils builds GPC queue task and balance URLs from helper endpoints',
|
||||
const api = loadGoPayUtils();
|
||||
assert.equal(api.DEFAULT_GPC_HELPER_API_URL, 'https://gpc.qlhazycoder.top');
|
||||
assert.equal(api.normalizeGpcHelperBaseUrl(''), 'https://gpc.qlhazycoder.top');
|
||||
assert.equal(api.normalizeGpcHelperBaseUrl('https://example.com/api/gp/tasks'), 'https://gpc.qlhazycoder.top');
|
||||
assert.equal(
|
||||
api.buildGpcHelperApiUrl('', '/api/checkout/start'),
|
||||
'https://gpc.qlhazycoder.top/api/checkout/start'
|
||||
|
||||
@@ -358,13 +358,14 @@ test('pickVerificationMessageWithTimeFallback can ignore afterTimestamp while ke
|
||||
|
||||
test('buildHotmailMailApiLatestUrl includes email, client id, refresh token, and mailbox', () => {
|
||||
const url = new URL(buildHotmailMailApiLatestUrl({
|
||||
apiUrl: 'https://example.com/api/mail-new',
|
||||
clientId: 'client-123',
|
||||
email: 'user@hotmail.com',
|
||||
refreshToken: 'refresh-token-xyz',
|
||||
mailbox: 'Junk',
|
||||
}));
|
||||
|
||||
assert.equal(url.origin + url.pathname, 'https://apple.882263.xyz/api/mail-new');
|
||||
assert.equal(url.origin + url.pathname, 'https://example.com/api/mail-new');
|
||||
assert.equal(url.searchParams.get('client_id'), 'client-123');
|
||||
assert.equal(url.searchParams.get('email'), 'user@hotmail.com');
|
||||
assert.equal(url.searchParams.get('refresh_token'), 'refresh-token-xyz');
|
||||
@@ -372,6 +373,13 @@ test('buildHotmailMailApiLatestUrl includes email, client id, refresh token, and
|
||||
assert.equal(url.searchParams.get('response_type'), 'json');
|
||||
});
|
||||
|
||||
test('buildHotmailMailApiLatestUrl requires an explicit api url', () => {
|
||||
assert.throws(
|
||||
() => buildHotmailMailApiLatestUrl({ email: 'user@hotmail.com' }),
|
||||
/Hotmail mail API URL is required/
|
||||
);
|
||||
});
|
||||
|
||||
test('buildHotmailMailApiLatestUrl supports custom api url and can omit response_type', () => {
|
||||
const url = new URL(buildHotmailMailApiLatestUrl({
|
||||
apiUrl: 'https://example.com/custom-mail-api',
|
||||
|
||||
+1
-1
@@ -549,7 +549,7 @@ Plus 模式通过 `plusModeEnabled` 开启,目标是在普通注册资料完
|
||||
Plus 模式可见步骤:
|
||||
|
||||
1. 第 1~5 步:沿用普通注册入口、邮箱、密码、注册验证码、资料填写链路。
|
||||
2. 第 6 步 `创建 Plus Checkout`:PayPal / GoPay 打开已登录 ChatGPT 页面,通过 `/api/auth/session` 读取 accessToken,再请求 `https://chatgpt.com/backend-api/payments/checkout` 创建 `chatgptplusplan` 的 checkout session。PayPal 使用 `DE / EUR` 与 `https://chatgpt.com/checkout/openai_ie/{checkout_session_id}`;GoPay 使用 `ID / IDR` 与 `https://chatgpt.com/checkout/openai_llc/{checkout_session_id}`;GPC helper 模式改为把 accessToken、手机号、国家区号、`otp_channel` 等提交到 `gopayHelperApiUrl` 的 `/api/gp/tasks`,并通过 `gopayHelperApiKey` 发送 `X-API-Key` 认证,创建后保存 `task_id`;当前默认 GPC API 地址为 `https://gpc.qlhazycoder.top`,旧的 `https://gpc.leftcode.xyz` 配置会兼容归一到新地址。
|
||||
2. 第 6 步 `创建 Plus Checkout`:PayPal / GoPay 打开已登录 ChatGPT 页面,通过 `/api/auth/session` 读取 accessToken,再请求 `https://chatgpt.com/backend-api/payments/checkout` 创建 `chatgptplusplan` 的 checkout session。PayPal 使用 `DE / EUR` 与 `https://chatgpt.com/checkout/openai_ie/{checkout_session_id}`;GoPay 使用 `ID / IDR` 与 `https://chatgpt.com/checkout/openai_llc/{checkout_session_id}`;GPC helper 模式改为把 accessToken、手机号、国家区号、`otp_channel` 等提交到 `gopayHelperApiUrl` 的 `/api/gp/tasks`,并通过 `gopayHelperApiKey` 发送 `X-API-Key` 认证,创建后保存 `task_id`;当前默认 GPC API 地址为 `https://gpc.qlhazycoder.top`。
|
||||
3. 第 7 步 `填写账单并提交订阅`:PayPal / GoPay 仍走 checkout 页面与 Stripe iframe 自动化;GPC helper 模式不再操作 checkout iframe,而是轮询 `/api/gp/tasks/{task_id}`,根据远端 `api_waiting_for` 依次向 `/otp` 和 `/pin` 提交验证码与 PIN。若侧栏启用本地 OTP helper,后台会轮询 `gopayHelperLocalSmsHelperUrl` 的 `/latest-otp?phone=...&consume=1` 接口,按当前 GPC 手机号读取并消费当前 OTP 通道的验证码;未开启本地 helper 时才弹出手动 OTP 输入框。仓库内置的 `scripts/gpc_sms_helper_macos.py` 是 macOS Messages/本地通知兼容读取实现,其他通道需要提供兼容的本地 `/latest-otp` 或 `/otp` 接口。
|
||||
4. 仅 PayPal / GoPay 会继续显示第 8 步:该步按当前支付方式显示为 `PayPal 登录与授权` 或 `GoPay 手机验证与授权`,底层 step key 仍为 `paypal-approve`。
|
||||
5. 第 9 步 `订阅回跳确认` 仅在 PayPal / GoPay 模式下等待授权后回跳到 ChatGPT / OpenAI 页面,页面加载完成后固定等待 1 秒。GPC helper 模式在第 7 步任务完成后会直接进入 Plus 可见第 10 步 OAuth 登录。
|
||||
|
||||
Reference in New Issue
Block a user