chore: pre-release cleanup
- Remove dead chatgpt.js (unused — all auth flows go through signup-page.js) - Remove chatgpt.com from manifest content_scripts - Fix resetState() to preserve vpsUrl and mailProvider on manual reset - Add 30s timeout to all tabs.onUpdated listeners (prevent hanging) - Fix misleading "All runs finished" log when loop breaks early - Remove stale TODO comment in signup-page.js - Add disabled styles for .btn-primary and .run-count-input - Remove unused `indicator` variable in sidepanel.js - Fix trailing comma in manifest.json
This commit is contained in:
@@ -1,211 +0,0 @@
|
||||
// content/chatgpt.js — Content script for ChatGPT (steps 6, 7-receive, 8)
|
||||
// Injected on: chatgpt.com
|
||||
|
||||
console.log('[MultiPage:chatgpt] Content script loaded on', location.href);
|
||||
|
||||
// Listen for commands from Background
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
if (message.type === 'EXECUTE_STEP' || message.type === 'FILL_CODE') {
|
||||
handleCommand(message).then(() => {
|
||||
sendResponse({ ok: true });
|
||||
}).catch(err => {
|
||||
reportError(message.step, err.message);
|
||||
sendResponse({ error: err.message });
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleCommand(message) {
|
||||
switch (message.type) {
|
||||
case 'EXECUTE_STEP':
|
||||
switch (message.step) {
|
||||
case 6: return await step6_loginChatGPT();
|
||||
case 8: return await step8_navigateOAuth();
|
||||
default: throw new Error(`chatgpt.js does not handle step ${message.step}`);
|
||||
}
|
||||
case 'FILL_CODE':
|
||||
return await step7_fillLoginCode(message.payload);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Step 6: Login ChatGPT
|
||||
// ============================================================
|
||||
|
||||
async function step6_loginChatGPT() {
|
||||
log('Step 6: Looking for login button on ChatGPT...');
|
||||
|
||||
// Get state for email and password
|
||||
const state = await chrome.runtime.sendMessage({ type: 'GET_STATE' });
|
||||
const email = state.email;
|
||||
const password = state.password;
|
||||
|
||||
if (!email) throw new Error('No email found in state. Complete earlier steps first.');
|
||||
|
||||
// Find login button on ChatGPT homepage
|
||||
let loginBtn = null;
|
||||
try {
|
||||
loginBtn = await waitForElementByText(
|
||||
'a, button, [role="button"], [role="link"]',
|
||||
/log\s*in|sign\s*in|登录/i,
|
||||
10000
|
||||
);
|
||||
} catch {
|
||||
try {
|
||||
loginBtn = await waitForElement(
|
||||
'[data-testid="login-button"], a[href*="auth"], a[href*="login"]',
|
||||
5000
|
||||
);
|
||||
} catch {
|
||||
throw new Error('Could not find Login button on ChatGPT. URL: ' + location.href);
|
||||
}
|
||||
}
|
||||
|
||||
simulateClick(loginBtn);
|
||||
log('Step 6: Clicked Login button, waiting for auth page...');
|
||||
await sleep(3000);
|
||||
|
||||
// We may be redirected to an auth page (auth0.openai.com etc.)
|
||||
// Or the login form may appear on the same page
|
||||
// Try to find email input
|
||||
let emailInput = null;
|
||||
try {
|
||||
emailInput = await waitForElement(
|
||||
'input[type="email"], input[name="email"], input[name="username"], input[id*="email"], input[placeholder*="email" i]',
|
||||
15000
|
||||
);
|
||||
} catch {
|
||||
throw new Error('Could not find email input on login page. URL: ' + location.href);
|
||||
}
|
||||
|
||||
fillInput(emailInput, email);
|
||||
log(`Step 6: Filled email: ${email}`);
|
||||
|
||||
// Submit email
|
||||
await sleep(500);
|
||||
const submitBtn1 = document.querySelector('button[type="submit"]')
|
||||
|| await waitForElementByText('button', /continue|next|submit|继续/i, 5000).catch(() => null);
|
||||
if (submitBtn1) {
|
||||
simulateClick(submitBtn1);
|
||||
log('Step 6: Submitted email');
|
||||
}
|
||||
|
||||
await sleep(2000);
|
||||
|
||||
// Check: password field or OTP?
|
||||
const passwordInput = document.querySelector('input[type="password"]');
|
||||
if (passwordInput) {
|
||||
log('Step 6: Password field found, filling password...');
|
||||
fillInput(passwordInput, password);
|
||||
|
||||
await sleep(500);
|
||||
const submitBtn2 = document.querySelector('button[type="submit"]')
|
||||
|| await waitForElementByText('button', /continue|log\s*in|submit|sign\s*in|登录/i, 5000).catch(() => null);
|
||||
if (submitBtn2) {
|
||||
simulateClick(submitBtn2);
|
||||
log('Step 6: Submitted password');
|
||||
}
|
||||
|
||||
await sleep(3000);
|
||||
|
||||
// Check if we need OTP after password
|
||||
const codeInput = document.querySelector(
|
||||
'input[name="code"], input[maxlength="6"], input[inputmode="numeric"], input[type="text"][maxlength="6"]'
|
||||
);
|
||||
if (codeInput) {
|
||||
log('Step 6: OTP code input found after password. Waiting for step 7...');
|
||||
reportComplete(6, { needsOTP: true });
|
||||
} else {
|
||||
// Check if we're actually logged in (redirected to chatgpt.com main page)
|
||||
log('Step 6: Login appears successful (no OTP needed)');
|
||||
reportComplete(6, { needsOTP: false });
|
||||
}
|
||||
} else {
|
||||
// No password field — check for OTP input or "check your email" message
|
||||
const codeInput = document.querySelector(
|
||||
'input[name="code"], input[maxlength="6"], input[inputmode="numeric"]'
|
||||
);
|
||||
if (codeInput) {
|
||||
log('Step 6: OTP flow detected (no password). Waiting for step 7...');
|
||||
reportComplete(6, { needsOTP: true });
|
||||
} else {
|
||||
// Maybe the page is still loading or transitioning
|
||||
log('Step 6: No password or OTP field found. May need email verification. Waiting for step 7...');
|
||||
reportComplete(6, { needsOTP: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Step 7 (receiving end): Fill Login Verification Code
|
||||
// ============================================================
|
||||
|
||||
async function step7_fillLoginCode(payload) {
|
||||
const { code } = payload;
|
||||
if (!code) throw new Error('No verification code provided.');
|
||||
|
||||
log(`Step 7: Filling login verification code: ${code}`);
|
||||
|
||||
// Find code input — single input or multiple single-digit inputs
|
||||
let codeInput = null;
|
||||
try {
|
||||
codeInput = await waitForElement(
|
||||
'input[name="code"], input[name="otp"], input[maxlength="6"], input[type="text"][inputmode="numeric"], input[aria-label*="code" i], input[placeholder*="code" i]',
|
||||
10000
|
||||
);
|
||||
} catch {
|
||||
// Check for multiple single-digit inputs
|
||||
const singleInputs = document.querySelectorAll('input[maxlength="1"]');
|
||||
if (singleInputs.length >= 6) {
|
||||
log('Step 7: Found single-digit code inputs, filling individually...');
|
||||
for (let i = 0; i < 6 && i < singleInputs.length; i++) {
|
||||
fillInput(singleInputs[i], code[i]);
|
||||
await sleep(100);
|
||||
}
|
||||
await sleep(1000);
|
||||
|
||||
// Auto-submit may happen; if not, try clicking submit
|
||||
const submitBtn = document.querySelector('button[type="submit"]')
|
||||
|| await waitForElementByText('button', /continue|verify|submit|confirm/i, 3000).catch(() => null);
|
||||
if (submitBtn) simulateClick(submitBtn);
|
||||
|
||||
await sleep(3000);
|
||||
reportComplete(7);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error('Could not find verification code input on ChatGPT login. URL: ' + location.href);
|
||||
}
|
||||
|
||||
fillInput(codeInput, code);
|
||||
|
||||
await sleep(500);
|
||||
const submitBtn = document.querySelector('button[type="submit"]')
|
||||
|| await waitForElementByText('button', /continue|verify|submit|confirm|确认/i, 5000).catch(() => null);
|
||||
if (submitBtn) {
|
||||
simulateClick(submitBtn);
|
||||
log('Step 7: Login verification code submitted');
|
||||
}
|
||||
|
||||
await sleep(3000);
|
||||
reportComplete(7);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Step 8: Navigate to OAuth URL
|
||||
// ============================================================
|
||||
|
||||
async function step8_navigateOAuth() {
|
||||
const state = await chrome.runtime.sendMessage({ type: 'GET_STATE' });
|
||||
const oauthUrl = state.oauthUrl;
|
||||
if (!oauthUrl) throw new Error('No OAuth URL found. Complete step 1 first.');
|
||||
|
||||
log(`Step 8: Navigating to OAuth URL: ${oauthUrl.slice(0, 80)}...`);
|
||||
log('Step 8: Waiting for localhost redirect (captured by background)...');
|
||||
|
||||
// Navigate — the webNavigation listener in background will capture localhost redirect
|
||||
window.location.href = oauthUrl;
|
||||
|
||||
// Don't reportComplete here — background handles it via webNavigation
|
||||
}
|
||||
@@ -40,7 +40,6 @@ async function handleCommand(message) {
|
||||
async function step2_clickRegister() {
|
||||
log('Step 2: Looking for Register/Sign up button...');
|
||||
|
||||
// TODO: Adjust selectors based on actual OpenAI auth page
|
||||
let registerBtn = null;
|
||||
try {
|
||||
registerBtn = await waitForElementByText(
|
||||
|
||||
+11
-7
@@ -1,5 +1,5 @@
|
||||
// content/vps-panel.js — Content script for VPS panel (steps 1, 9)
|
||||
// Injected on: http://154.26.182.181:8317/*
|
||||
// Injected on: VPS panel (user-configured URL)
|
||||
//
|
||||
// Actual DOM structure (after login click):
|
||||
// <div class="card">
|
||||
@@ -41,7 +41,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
async function handleStep(step, payload) {
|
||||
switch (step) {
|
||||
case 1: return await step1_getOAuthLink();
|
||||
case 9: return await step9_vpsVerify();
|
||||
case 9: return await step9_vpsVerify(payload);
|
||||
default:
|
||||
throw new Error(`vps-panel.js does not handle step ${step}`);
|
||||
}
|
||||
@@ -105,14 +105,18 @@ async function step1_getOAuthLink() {
|
||||
// Step 9: VPS Verify — paste localhost URL and submit
|
||||
// ============================================================
|
||||
|
||||
async function step9_vpsVerify() {
|
||||
log('Step 9: Getting localhost URL from storage...');
|
||||
|
||||
const state = await chrome.runtime.sendMessage({ type: 'GET_STATE' });
|
||||
const localhostUrl = state.localhostUrl;
|
||||
async function step9_vpsVerify(payload) {
|
||||
// Get localhostUrl from payload (passed directly by background) or fallback to state
|
||||
let localhostUrl = payload?.localhostUrl;
|
||||
if (!localhostUrl) {
|
||||
log('Step 9: localhostUrl not in payload, fetching from state...');
|
||||
const state = await chrome.runtime.sendMessage({ type: 'GET_STATE' });
|
||||
localhostUrl = state.localhostUrl;
|
||||
}
|
||||
if (!localhostUrl) {
|
||||
throw new Error('No localhost URL found. Complete step 8 first.');
|
||||
}
|
||||
log(`Step 9: Got localhostUrl: ${localhostUrl.slice(0, 60)}...`);
|
||||
|
||||
log('Step 9: Looking for callback URL input...');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user