feat: add step definitions module and integrate with sidepanel
- Introduced a new module for step definitions in `data/step-definitions.js` to manage shared step metadata. - Updated `sidepanel.html` to dynamically render steps based on the new step definitions module. - Refactored `sidepanel.js` to utilize the step definitions for rendering and managing step statuses. - Enhanced tests to validate the step definitions module and its integration with the sidepanel. - Cleaned up existing tests to ensure they align with the new structure and functionality.
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
(function attachBackgroundNavigationUtils(root, factory) {
|
||||
root.MultiPageBackgroundNavigationUtils = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundNavigationUtilsModule() {
|
||||
function createNavigationUtils(deps = {}) {
|
||||
const {
|
||||
DEFAULT_SUB2API_URL,
|
||||
normalizeCpaCallbackMode,
|
||||
normalizeLocalCpaStep9Mode,
|
||||
} = deps;
|
||||
|
||||
function parseUrlSafely(rawUrl) {
|
||||
if (!rawUrl) return null;
|
||||
try {
|
||||
return new URL(rawUrl);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeSub2ApiUrl(rawUrl) {
|
||||
const input = (rawUrl || '').trim() || DEFAULT_SUB2API_URL;
|
||||
const withProtocol = /^https?:\/\//i.test(input) ? input : `https://${input}`;
|
||||
const parsed = new URL(withProtocol);
|
||||
if (!parsed.pathname || parsed.pathname === '/') {
|
||||
parsed.pathname = '/admin/accounts';
|
||||
}
|
||||
parsed.hash = '';
|
||||
return parsed.toString();
|
||||
}
|
||||
|
||||
function getPanelMode(state = {}) {
|
||||
return state.panelMode === 'sub2api' ? 'sub2api' : 'cpa';
|
||||
}
|
||||
|
||||
function getPanelModeLabel(modeOrState) {
|
||||
const mode = typeof modeOrState === 'string' ? modeOrState : getPanelMode(modeOrState);
|
||||
return mode === 'sub2api' ? 'SUB2API' : 'CPA';
|
||||
}
|
||||
|
||||
function isSignupPageHost(hostname = '') {
|
||||
return ['auth0.openai.com', 'auth.openai.com', 'accounts.openai.com'].includes(hostname);
|
||||
}
|
||||
|
||||
function isSignupEntryHost(hostname = '') {
|
||||
return ['chatgpt.com', 'chat.openai.com'].includes(hostname);
|
||||
}
|
||||
|
||||
function isSignupPasswordPageUrl(rawUrl) {
|
||||
const parsed = parseUrlSafely(rawUrl);
|
||||
if (!parsed) return false;
|
||||
return isSignupPageHost(parsed.hostname)
|
||||
&& /\/create-account\/password(?:[/?#]|$)/i.test(parsed.pathname || '');
|
||||
}
|
||||
|
||||
function is163MailHost(hostname = '') {
|
||||
return hostname === 'mail.163.com'
|
||||
|| hostname.endsWith('.mail.163.com')
|
||||
|| hostname === 'webmail.vip.163.com';
|
||||
}
|
||||
|
||||
function isLocalhostOAuthCallbackUrl(rawUrl) {
|
||||
const parsed = parseUrlSafely(rawUrl);
|
||||
if (!parsed) return false;
|
||||
if (!['http:', 'https:'].includes(parsed.protocol)) return false;
|
||||
if (!['localhost', '127.0.0.1'].includes(parsed.hostname)) return false;
|
||||
if (!['/auth/callback', '/codex/callback'].includes(parsed.pathname)) return false;
|
||||
|
||||
const code = (parsed.searchParams.get('code') || '').trim();
|
||||
const state = (parsed.searchParams.get('state') || '').trim();
|
||||
return Boolean(code && state);
|
||||
}
|
||||
|
||||
function isLocalCpaUrl(rawUrl) {
|
||||
const parsed = parseUrlSafely(rawUrl);
|
||||
if (!parsed) return false;
|
||||
if (!['http:', 'https:'].includes(parsed.protocol)) return false;
|
||||
return ['localhost', '127.0.0.1'].includes(parsed.hostname);
|
||||
}
|
||||
|
||||
function shouldBypassStep9ForLocalCpa(state) {
|
||||
return normalizeLocalCpaStep9Mode(state?.localCpaStep9Mode) === 'bypass'
|
||||
&& Boolean(state?.localhostUrl)
|
||||
&& isLocalCpaUrl(state?.vpsUrl);
|
||||
}
|
||||
|
||||
function shouldSkipLoginVerificationForCpaCallback(state) {
|
||||
return getPanelMode(state) === 'cpa'
|
||||
&& normalizeCpaCallbackMode(state?.cpaCallbackMode) === 'step6';
|
||||
}
|
||||
|
||||
function matchesSourceUrlFamily(source, candidateUrl, referenceUrl) {
|
||||
const candidate = parseUrlSafely(candidateUrl);
|
||||
if (!candidate) return false;
|
||||
|
||||
const reference = parseUrlSafely(referenceUrl);
|
||||
|
||||
switch (source) {
|
||||
case 'signup-page':
|
||||
return isSignupPageHost(candidate.hostname) || isSignupEntryHost(candidate.hostname);
|
||||
case 'duck-mail':
|
||||
return candidate.hostname === 'duckduckgo.com' && candidate.pathname.startsWith('/email/');
|
||||
case 'qq-mail':
|
||||
return candidate.hostname === 'mail.qq.com' || candidate.hostname === 'wx.mail.qq.com';
|
||||
case 'mail-163':
|
||||
return is163MailHost(candidate.hostname);
|
||||
case 'gmail-mail':
|
||||
return candidate.hostname === 'mail.google.com';
|
||||
case 'inbucket-mail':
|
||||
return Boolean(reference)
|
||||
&& candidate.origin === reference.origin
|
||||
&& candidate.pathname.startsWith('/m/');
|
||||
case 'mail-2925':
|
||||
return candidate.hostname === '2925.com' || candidate.hostname === 'www.2925.com';
|
||||
case 'vps-panel':
|
||||
return Boolean(reference)
|
||||
&& candidate.origin === reference.origin
|
||||
&& candidate.pathname === reference.pathname;
|
||||
case 'sub2api-panel':
|
||||
return Boolean(reference)
|
||||
&& candidate.origin === reference.origin
|
||||
&& (
|
||||
candidate.pathname.startsWith('/admin/accounts')
|
||||
|| candidate.pathname.startsWith('/login')
|
||||
|| candidate.pathname === '/'
|
||||
);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getStep8CallbackUrlFromNavigation(details, signupTabId) {
|
||||
if (!Number.isInteger(signupTabId) || !details) return '';
|
||||
if (details.tabId !== signupTabId) return '';
|
||||
if (details.frameId !== 0) return '';
|
||||
return isLocalhostOAuthCallbackUrl(details.url) ? details.url : '';
|
||||
}
|
||||
|
||||
function getStep8CallbackUrlFromTabUpdate(tabId, changeInfo, tab, signupTabId) {
|
||||
if (!Number.isInteger(signupTabId) || tabId !== signupTabId) return '';
|
||||
const candidates = [changeInfo?.url, tab?.url];
|
||||
for (const candidate of candidates) {
|
||||
if (isLocalhostOAuthCallbackUrl(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
return {
|
||||
getPanelMode,
|
||||
getPanelModeLabel,
|
||||
getStep8CallbackUrlFromNavigation,
|
||||
getStep8CallbackUrlFromTabUpdate,
|
||||
is163MailHost,
|
||||
isLocalCpaUrl,
|
||||
isLocalhostOAuthCallbackUrl,
|
||||
isSignupEntryHost,
|
||||
isSignupPageHost,
|
||||
isSignupPasswordPageUrl,
|
||||
matchesSourceUrlFamily,
|
||||
normalizeSub2ApiUrl,
|
||||
parseUrlSafely,
|
||||
shouldBypassStep9ForLocalCpa,
|
||||
shouldSkipLoginVerificationForCpaCallback,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createNavigationUtils,
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user