fix: resolve HeroSMS Plus dev sync conflicts
This commit is contained in:
@@ -40,17 +40,14 @@
|
||||
return /缺少|未配置|请输入|无效|错误|失败|401|认证失败|未授权|unauthorized|invalid/i.test(message);
|
||||
}
|
||||
|
||||
function getVisibleStep(state, fallback = 7) {
|
||||
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
|
||||
return visibleStep > 0 ? visibleStep : fallback;
|
||||
}
|
||||
|
||||
async function executeStep7(state) {
|
||||
const visibleStep = getVisibleStep(state, 7);
|
||||
if (!state.email) {
|
||||
throw new Error('缺少邮箱地址,请先完成步骤 3。');
|
||||
}
|
||||
|
||||
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
|
||||
const completionStep = visibleStep > 0 ? visibleStep : 7;
|
||||
|
||||
let attempt = 0;
|
||||
let lastError = null;
|
||||
|
||||
@@ -60,22 +57,22 @@
|
||||
try {
|
||||
const currentState = attempt === 1 ? state : await getState();
|
||||
const password = currentState.password || currentState.customPassword || '';
|
||||
const oauthUrl = await refreshOAuthUrlBeforeStep6(currentState, { visibleStep });
|
||||
const oauthUrl = await refreshOAuthUrlBeforeStep6(currentState);
|
||||
if (typeof startOAuthFlowTimeoutWindow === 'function') {
|
||||
await startOAuthFlowTimeoutWindow({ step: visibleStep, oauthUrl });
|
||||
await startOAuthFlowTimeoutWindow({ step: 7, oauthUrl });
|
||||
}
|
||||
const loginTimeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(180000, {
|
||||
step: visibleStep,
|
||||
step: 7,
|
||||
actionLabel: 'OAuth 登录并进入验证码页',
|
||||
oauthUrl,
|
||||
})
|
||||
: 180000;
|
||||
|
||||
if (attempt === 1) {
|
||||
await addLog(`步骤 ${visibleStep}:正在打开最新 OAuth 链接并登录...`);
|
||||
await addLog('步骤 7:正在打开最新 OAuth 链接并登录...');
|
||||
} else {
|
||||
await addLog(`步骤 ${visibleStep}:上一轮失败后,正在进行第 ${attempt} 次尝试(最多 ${STEP6_MAX_ATTEMPTS} 次)...`, 'warn');
|
||||
await addLog(`步骤 7:上一轮失败后,正在进行第 ${attempt} 次尝试(最多 ${STEP6_MAX_ATTEMPTS} 次)...`, 'warn');
|
||||
}
|
||||
|
||||
await reuseOrCreateTab('signup-page', oauthUrl);
|
||||
@@ -89,14 +86,13 @@
|
||||
payload: {
|
||||
email: currentState.email,
|
||||
password,
|
||||
visibleStep,
|
||||
},
|
||||
},
|
||||
{
|
||||
timeoutMs: loginTimeoutMs,
|
||||
responseTimeoutMs: loginTimeoutMs,
|
||||
retryDelayMs: 700,
|
||||
logMessage: `步骤 ${visibleStep}:认证页正在切换,等待页面重新就绪后继续登录...`,
|
||||
logMessage: '步骤 7:认证页正在切换,等待页面重新就绪后继续登录...',
|
||||
}
|
||||
);
|
||||
|
||||
@@ -108,13 +104,14 @@
|
||||
const completionPayload = {
|
||||
loginVerificationRequestedAt: result.loginVerificationRequestedAt || null,
|
||||
};
|
||||
if (result.skipLoginVerificationStep) {
|
||||
completionPayload.skipLoginVerificationStep = true;
|
||||
if (Object.prototype.hasOwnProperty.call(result || {}, 'skipLoginVerificationStep')) {
|
||||
completionPayload.skipLoginVerificationStep = Boolean(result.skipLoginVerificationStep);
|
||||
}
|
||||
if (result.directOAuthConsentPage) {
|
||||
completionPayload.directOAuthConsentPage = true;
|
||||
if (Object.prototype.hasOwnProperty.call(result || {}, 'directOAuthConsentPage')) {
|
||||
completionPayload.directOAuthConsentPage = Boolean(result.directOAuthConsentPage);
|
||||
}
|
||||
await completeStepFromBackground(visibleStep, completionPayload);
|
||||
|
||||
await completeStepFromBackground(completionStep, completionPayload);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -132,7 +129,7 @@
|
||||
}
|
||||
if (isManagementSecretConfigError(err)) {
|
||||
await addLog(
|
||||
`步骤 ${visibleStep}:检测到来源后台管理密钥缺失或错误,不再重试,当前流程停止。原因:${getErrorMessage(err)}`,
|
||||
`步骤 7:检测到来源后台管理密钥缺失或错误,不再重试,当前流程停止。原因:${getErrorMessage(err)}`,
|
||||
'error'
|
||||
);
|
||||
throw err;
|
||||
@@ -142,11 +139,11 @@
|
||||
break;
|
||||
}
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:第 ${attempt} 次尝试失败,原因:${getErrorMessage(err)};准备重试...`, 'warn');
|
||||
await addLog(`步骤 7:第 ${attempt} 次尝试失败,原因:${getErrorMessage(err)};准备重试...`, 'warn');
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`步骤 ${visibleStep}:判断失败后已重试 ${STEP6_MAX_ATTEMPTS - 1} 次,仍未成功。最后原因:${getErrorMessage(lastError)}`);
|
||||
throw new Error(`步骤 7:判断失败后已重试 ${STEP6_MAX_ATTEMPTS - 1} 次,仍未成功。最后原因:${getErrorMessage(lastError)}`);
|
||||
}
|
||||
|
||||
return { executeStep7 };
|
||||
|
||||
@@ -26,31 +26,23 @@
|
||||
return String(value || '').trim();
|
||||
}
|
||||
|
||||
function getVisibleStep(state, fallback = 10) {
|
||||
function resolvePlatformVerifyStep(state = {}) {
|
||||
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
|
||||
return visibleStep > 0 ? visibleStep : fallback;
|
||||
return visibleStep >= 10 ? visibleStep : 10;
|
||||
}
|
||||
|
||||
function getConfirmStepForVisibleStep(visibleStep) {
|
||||
return visibleStep >= 13 ? 12 : 9;
|
||||
}
|
||||
|
||||
function getAuthLoginStepForVisibleStep(visibleStep) {
|
||||
return visibleStep >= 13 ? 10 : 7;
|
||||
}
|
||||
|
||||
function parseLocalhostCallback(rawUrl, visibleStep = 10, confirmStep = 9) {
|
||||
function parseLocalhostCallback(rawUrl) {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = new URL(rawUrl);
|
||||
} catch {
|
||||
throw new Error(`步骤 ${visibleStep} 捕获到的 localhost OAuth 回调地址格式无效,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 10 捕获到的 localhost OAuth 回调地址格式无效,请重新执行步骤 9。');
|
||||
}
|
||||
|
||||
const code = normalizeString(parsed.searchParams.get('code'));
|
||||
const state = normalizeString(parsed.searchParams.get('state'));
|
||||
if (!code || !state) {
|
||||
throw new Error(`步骤 ${visibleStep} 捕获到的 localhost OAuth 回调地址缺少 code 或 state,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 10 捕获到的 localhost OAuth 回调地址缺少 code 或 state,请重新执行步骤 9。');
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -72,6 +64,77 @@
|
||||
return details || `Codex2API 请求失败(HTTP ${responseStatus})。`;
|
||||
}
|
||||
|
||||
function deriveCpaManagementOrigin(vpsUrl) {
|
||||
const normalizedUrl = normalizeString(vpsUrl);
|
||||
if (!normalizedUrl) {
|
||||
throw new Error('尚未填写 CPA 地址,请先在侧边栏输入。');
|
||||
}
|
||||
let parsed;
|
||||
try {
|
||||
parsed = new URL(normalizedUrl);
|
||||
} catch {
|
||||
throw new Error('CPA 地址格式无效,请先在侧边栏检查。');
|
||||
}
|
||||
return parsed.origin;
|
||||
}
|
||||
|
||||
function getCpaApiErrorMessage(payload, responseStatus = 500) {
|
||||
const details = [
|
||||
payload?.error,
|
||||
payload?.message,
|
||||
payload?.detail,
|
||||
payload?.reason,
|
||||
]
|
||||
.map((value) => normalizeString(value))
|
||||
.find(Boolean);
|
||||
return details || `CPA 管理接口请求失败(HTTP ${responseStatus})。`;
|
||||
}
|
||||
|
||||
async function fetchCpaManagementJson(origin, path, options = {}) {
|
||||
const controller = new AbortController();
|
||||
const timeoutMs = Math.max(1000, Math.floor(Number(options.timeoutMs) || 20000));
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
const managementKey = normalizeString(options.managementKey);
|
||||
const headers = {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
if (managementKey) {
|
||||
headers.Authorization = `Bearer ${managementKey}`;
|
||||
headers['X-Management-Key'] = managementKey;
|
||||
}
|
||||
|
||||
const response = await fetch(`${origin}${path}`, {
|
||||
method: options.method || 'POST',
|
||||
headers,
|
||||
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
let payload = {};
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch {
|
||||
payload = {};
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(getCpaApiErrorMessage(payload, response.status));
|
||||
}
|
||||
|
||||
return payload;
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') {
|
||||
throw new Error('CPA 管理接口请求超时,请稍后重试。');
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchCodex2ApiJson(origin, path, options = {}) {
|
||||
const controller = new AbortController();
|
||||
const timeoutMs = Math.max(1000, Math.floor(Number(options.timeoutMs) || 30000));
|
||||
@@ -122,95 +185,88 @@
|
||||
}
|
||||
|
||||
async function executeCpaStep10(state) {
|
||||
const visibleStep = getVisibleStep(state, 10);
|
||||
const confirmStep = getConfirmStepForVisibleStep(visibleStep);
|
||||
const platformVerifyStep = resolvePlatformVerifyStep(state);
|
||||
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
|
||||
throw new Error(`步骤 ${confirmStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
|
||||
}
|
||||
if (!state.localhostUrl) {
|
||||
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmStep}。`);
|
||||
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
|
||||
}
|
||||
if (!state.vpsUrl) {
|
||||
throw new Error('尚未填写 CPA 地址,请先在侧边栏输入。');
|
||||
}
|
||||
|
||||
if (shouldBypassStep9ForLocalCpa(state)) {
|
||||
await addLog(`步骤 ${visibleStep}:检测到本地 CPA,且当前策略为“跳过第10步”,本轮不再重复提交回调地址。`, 'info');
|
||||
await completeStepFromBackground(visibleStep, {
|
||||
await addLog('步骤 10:检测到本地 CPA,且当前策略为“跳过第10步”,本轮不再重复提交回调地址。', 'info');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
localhostUrl: state.localhostUrl,
|
||||
verifiedStatus: 'local-auto',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在打开 CPA 面板...`);
|
||||
|
||||
const injectFiles = ['content/activation-utils.js', 'content/utils.js', 'content/vps-panel.js'];
|
||||
let tabId = await getTabId('vps-panel');
|
||||
const alive = tabId && await isTabAlive('vps-panel');
|
||||
|
||||
if (!alive) {
|
||||
tabId = await reuseOrCreateTab('vps-panel', state.vpsUrl, {
|
||||
inject: injectFiles,
|
||||
reloadIfSameUrl: true,
|
||||
});
|
||||
} else {
|
||||
await closeConflictingTabsForSource('vps-panel', state.vpsUrl, { excludeTabIds: [tabId] });
|
||||
await chrome.tabs.update(tabId, { active: true });
|
||||
await rememberSourceLastUrl('vps-panel', state.vpsUrl);
|
||||
const callback = parseLocalhostCallback(state.localhostUrl);
|
||||
const expectedState = normalizeString(state.cpaOAuthState);
|
||||
if (expectedState && expectedState !== callback.state) {
|
||||
throw new Error('CPA 回调 state 与当前授权会话不匹配,请重新执行步骤 7。');
|
||||
}
|
||||
const managementKey = normalizeString(state.vpsPassword);
|
||||
if (!managementKey) {
|
||||
throw new Error('尚未配置 CPA 管理密钥,请先在侧边栏填写。');
|
||||
}
|
||||
|
||||
await ensureContentScriptReadyOnTab('vps-panel', tabId, {
|
||||
inject: injectFiles,
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: `步骤 ${visibleStep}:CPA 面板仍在加载,正在重试连接...`,
|
||||
});
|
||||
await addLog('步骤 10:正在通过 CPA 管理接口提交回调地址...');
|
||||
try {
|
||||
const origin = normalizeString(state.cpaManagementOrigin) || deriveCpaManagementOrigin(state.vpsUrl);
|
||||
const result = await fetchCpaManagementJson(origin, '/v0/management/oauth-callback', {
|
||||
method: 'POST',
|
||||
managementKey,
|
||||
body: {
|
||||
provider: 'codex',
|
||||
redirect_url: callback.url,
|
||||
},
|
||||
});
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在填写回调地址...`);
|
||||
const result = await sendToContentScriptResilient('vps-panel', {
|
||||
type: 'EXECUTE_STEP',
|
||||
step: visibleStep,
|
||||
source: 'background',
|
||||
payload: { localhostUrl: state.localhostUrl, vpsPassword: state.vpsPassword, visibleStep },
|
||||
}, {
|
||||
timeoutMs: 125000,
|
||||
responseTimeoutMs: 125000,
|
||||
retryDelayMs: 700,
|
||||
logMessage: `步骤 ${visibleStep}:CPA 面板通信未就绪,正在等待页面恢复...`,
|
||||
});
|
||||
|
||||
if (result?.error) {
|
||||
throw new Error(result.error);
|
||||
const verifiedStatus = normalizeString(result?.message)
|
||||
|| normalizeString(result?.status_message)
|
||||
|| 'CPA 已通过接口提交回调';
|
||||
await addLog(`步骤 10:${verifiedStatus}`, 'ok');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
localhostUrl: callback.url,
|
||||
verifiedStatus,
|
||||
});
|
||||
} catch (error) {
|
||||
const reason = normalizeString(error?.message) || 'unknown error';
|
||||
await addLog(`步骤 10:CPA 接口提交失败:${reason}`, 'error');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function executeCodex2ApiStep10(state) {
|
||||
const visibleStep = getVisibleStep(state, 10);
|
||||
const confirmStep = getConfirmStepForVisibleStep(visibleStep);
|
||||
const platformVerifyStep = resolvePlatformVerifyStep(state);
|
||||
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
|
||||
throw new Error(`步骤 ${confirmStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
|
||||
}
|
||||
if (!state.localhostUrl) {
|
||||
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmStep}。`);
|
||||
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
|
||||
}
|
||||
if (!state.codex2apiSessionId) {
|
||||
throw new Error(`缺少 Codex2API 会话信息,请重新执行步骤 ${getAuthLoginStepForVisibleStep(visibleStep)}。`);
|
||||
throw new Error('缺少 Codex2API 会话信息,请重新执行步骤 7。');
|
||||
}
|
||||
if (!normalizeString(state.codex2apiAdminKey)) {
|
||||
throw new Error('尚未配置 Codex2API 管理密钥,请先在侧边栏填写。');
|
||||
}
|
||||
|
||||
const callback = parseLocalhostCallback(state.localhostUrl, visibleStep, confirmStep);
|
||||
const callback = parseLocalhostCallback(state.localhostUrl);
|
||||
const expectedState = normalizeString(state.codex2apiOAuthState);
|
||||
if (expectedState && expectedState !== callback.state) {
|
||||
throw new Error(`Codex2API 回调 state 与当前授权会话不匹配,请重新执行步骤 ${getAuthLoginStepForVisibleStep(visibleStep)}。`);
|
||||
throw new Error('Codex2API 回调 state 与当前授权会话不匹配,请重新执行步骤 7。');
|
||||
}
|
||||
|
||||
const codex2apiUrl = normalizeCodex2ApiUrl(state.codex2apiUrl);
|
||||
const origin = new URL(codex2apiUrl).origin;
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在向 Codex2API 提交回调并创建账号...`);
|
||||
await addLog('步骤 10:正在向 Codex2API 提交回调并创建账号...');
|
||||
const result = await fetchCodex2ApiJson(origin, '/api/admin/oauth/exchange-code', {
|
||||
adminKey: state.codex2apiAdminKey,
|
||||
method: 'POST',
|
||||
@@ -222,21 +278,19 @@
|
||||
});
|
||||
|
||||
const verifiedStatus = normalizeString(result?.message) || 'Codex2API OAuth 账号添加成功';
|
||||
await addLog(`步骤 ${visibleStep}:${verifiedStatus}`, 'ok');
|
||||
await completeStepFromBackground(visibleStep, {
|
||||
await addLog(`步骤 10:${verifiedStatus}`, 'ok');
|
||||
await completeStepFromBackground(platformVerifyStep, {
|
||||
localhostUrl: callback.url,
|
||||
verifiedStatus,
|
||||
});
|
||||
}
|
||||
|
||||
async function executeSub2ApiStep10(state) {
|
||||
const visibleStep = getVisibleStep(state, 10);
|
||||
const confirmStep = getConfirmStepForVisibleStep(visibleStep);
|
||||
if (state.localhostUrl && !isLocalhostOAuthCallbackUrl(state.localhostUrl)) {
|
||||
throw new Error(`步骤 ${confirmStep} 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 ${confirmStep}。`);
|
||||
throw new Error('步骤 9 捕获到的 localhost OAuth 回调地址无效,请重新执行步骤 9。');
|
||||
}
|
||||
if (!state.localhostUrl) {
|
||||
throw new Error(`缺少 localhost 回调地址,请先完成步骤 ${confirmStep}。`);
|
||||
throw new Error('缺少 localhost 回调地址,请先完成步骤 9。');
|
||||
}
|
||||
if (!state.sub2apiSessionId) {
|
||||
throw new Error('缺少 SUB2API 会话信息,请重新执行步骤 1。');
|
||||
@@ -251,7 +305,7 @@
|
||||
const sub2apiUrl = normalizeSub2ApiUrl(state.sub2apiUrl);
|
||||
const injectFiles = ['content/utils.js', 'content/sub2api-panel.js'];
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在打开 SUB2API 后台...`);
|
||||
await addLog('步骤 10:正在打开 SUB2API 后台...');
|
||||
|
||||
let tabId = await getTabId('sub2api-panel');
|
||||
const alive = tabId && await isTabAlive('sub2api-panel');
|
||||
@@ -273,13 +327,12 @@
|
||||
injectSource: 'sub2api-panel',
|
||||
});
|
||||
|
||||
await addLog(`步骤 ${visibleStep}:正在向 SUB2API 提交回调并创建账号...`);
|
||||
await addLog('步骤 10:正在向 SUB2API 提交回调并创建账号...');
|
||||
const result = await sendToContentScript('sub2api-panel', {
|
||||
type: 'EXECUTE_STEP',
|
||||
step: visibleStep,
|
||||
step: 10,
|
||||
source: 'background',
|
||||
payload: {
|
||||
visibleStep,
|
||||
localhostUrl: state.localhostUrl,
|
||||
sub2apiUrl,
|
||||
sub2apiEmail: state.sub2apiEmail,
|
||||
|
||||
Reference in New Issue
Block a user