Fix Cloudflare headless detection: use non-headless with hidden window
All checks were successful
Release / build (push) Successful in 1m37s
All checks were successful
Release / build (push) Successful in 1m37s
Cloudflare detects headless Chrome and loops the JS challenge forever. Switch to non-headless mode with an off-screen window. Also save Cloudflare cookies (cf_clearance, __cf_bm) after Chrome fallback so subsequent plain HTTP requests can reuse them. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,9 @@ import (
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -34,13 +37,21 @@ type ParsedUsage struct {
|
||||
type UpdateCallback func(ParsedUsage)
|
||||
|
||||
// doRequest performs an authenticated HTTP GET to the Claude API.
|
||||
// Includes any saved Cloudflare cookies from previous Chrome fallbacks.
|
||||
func doRequest(url, sessionKey string) ([]byte, int, error) {
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
req.Header.Set("Cookie", "sessionKey="+sessionKey)
|
||||
|
||||
cookie := "sessionKey=" + sessionKey
|
||||
// Append Cloudflare cookies if available (saved by Chrome fallback)
|
||||
if cfCookies := loadCFCookies(); cfCookies != "" {
|
||||
cookie += "; " + cfCookies
|
||||
}
|
||||
|
||||
req.Header.Set("Cookie", cookie)
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Referer", "https://claude.ai/")
|
||||
@@ -58,6 +69,24 @@ func doRequest(url, sessionKey string) ([]byte, int, error) {
|
||||
return body, resp.StatusCode, nil
|
||||
}
|
||||
|
||||
// loadCFCookies reads saved Cloudflare cookies from the cf-cookies file.
|
||||
func loadCFCookies() string {
|
||||
data, err := os.ReadFile(filepath.Join(config.ConfigDir(), "cf-cookies"))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
// File has one cookie per line (name=value), join with "; "
|
||||
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
|
||||
var valid []string
|
||||
for _, l := range lines {
|
||||
l = strings.TrimSpace(l)
|
||||
if l != "" {
|
||||
valid = append(valid, l)
|
||||
}
|
||||
}
|
||||
return strings.Join(valid, "; ")
|
||||
}
|
||||
|
||||
// fetchWithFallback tries a plain HTTP request first, then falls back to
|
||||
// headless Chrome (which can solve Cloudflare JS challenges) on 403.
|
||||
func fetchWithFallback(url, sessionKey string) ([]byte, error) {
|
||||
|
||||
Reference in New Issue
Block a user