103 lines
2.4 KiB
Go
103 lines
2.4 KiB
Go
package browser
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os/exec"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
func launchChrome() (string, *exec.Cmd, error) {
|
|
var chromePath string
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
chromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
case "linux":
|
|
chromePath = "google-chrome"
|
|
case "windows":
|
|
chromePath = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
|
|
default:
|
|
return "", nil, fmt.Errorf("unsupported OS: %s", runtime.GOOS)
|
|
}
|
|
|
|
// Kill any existing Chrome debug instances first
|
|
exec.Command("pkill", "-f", "remote-debugging-port=9222").Run()
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
cmd := exec.Command(chromePath,
|
|
"--remote-debugging-port=9222",
|
|
"--no-first-run",
|
|
"--no-default-browser-check",
|
|
"--user-data-dir=/tmp/chrome-debug-profile",
|
|
|
|
// Anti-detection flags
|
|
"--disable-blink-features=AutomationControlled",
|
|
"--disable-infobars",
|
|
"--disable-dev-shm-usage",
|
|
"--disable-browser-side-navigation",
|
|
"--disable-gpu",
|
|
"--no-sandbox",
|
|
"--disable-setuid-sandbox",
|
|
|
|
// Hide automation indicators
|
|
"--disable-extensions",
|
|
"--disable-plugins-discovery",
|
|
"--disable-bundled-ppapi-flash",
|
|
|
|
// Reduce fingerprinting
|
|
"--disable-background-networking",
|
|
"--disable-sync",
|
|
"--disable-translate",
|
|
"--metrics-recording-only",
|
|
"--safebrowsing-disable-auto-update",
|
|
"--disable-client-side-phishing-detection",
|
|
"--disable-default-apps",
|
|
"--disable-hang-monitor",
|
|
"--disable-popup-blocking",
|
|
"--disable-prompt-on-repost",
|
|
|
|
// Window size to look like a real browser
|
|
"--window-size=1920,1080",
|
|
"--start-maximized",
|
|
)
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
return "", nil, fmt.Errorf("failed to start Chrome: %w", err)
|
|
}
|
|
|
|
// Poll the debug endpoint to get the WebSocket URL
|
|
var wsURL string
|
|
for range 50 {
|
|
time.Sleep(200 * time.Millisecond)
|
|
resp, err := http.Get("http://127.0.0.1:9222/json/version")
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
var result struct {
|
|
WebSocketDebuggerURL string `json:"webSocketDebuggerUrl"`
|
|
}
|
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
resp.Body.Close()
|
|
continue
|
|
}
|
|
resp.Body.Close()
|
|
|
|
if result.WebSocketDebuggerURL != "" {
|
|
wsURL = result.WebSocketDebuggerURL
|
|
break
|
|
}
|
|
}
|
|
|
|
if wsURL == "" {
|
|
cmd.Process.Kill()
|
|
return "", nil, fmt.Errorf("timeout waiting for Chrome WebSocket URL")
|
|
}
|
|
|
|
// Wait for Chrome to be fully ready to accept connections
|
|
time.Sleep(1 * time.Second)
|
|
|
|
return wsURL, cmd, nil
|
|
}
|