Files
FlowPilot/content/chatgpt.js
T
unknown 1286130023 feat: reuse tabs across multi-run — no more tab bloat
- tabRegistry preserved across resetState (like seenCodes/accounts)
- New reuseOrCreateTab() helper: navigates existing tab or creates new one
- All steps use reuseOrCreateTab: VPS panel, auth page, mail
- Mail tabs: only activate if alive, don't re-navigate (preserves session)
- Auth tab: reused between step 2→6→8, navigated to new URLs
- VPS tab: reused across runs, re-injected on navigation
2026-04-05 10:49:40 +08:00

212 lines
7.3 KiB
JavaScript

// 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
}