feat: Implement S2A, Rod, and Chromedp based authentication for external services, and introduce new frontend pages and backend APIs for monitoring, configuration, upload, and team processes.
This commit is contained in:
@@ -6,12 +6,30 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"codex-pool/internal/proxyutil"
|
||||
|
||||
"github.com/chromedp/cdproto/fetch"
|
||||
"github.com/chromedp/cdproto/network"
|
||||
"github.com/chromedp/chromedp"
|
||||
)
|
||||
|
||||
// CompleteWithChromedp 使用 chromedp 完成 S2A OAuth 授权
|
||||
func CompleteWithChromedp(authURL, email, password, teamID string, headless bool, proxy string) (string, error) {
|
||||
var proxyServer string
|
||||
var proxyUser string
|
||||
var proxyPass string
|
||||
if proxy != "" {
|
||||
info, err := proxyutil.Parse(proxy)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("代理格式错误: %v", err)
|
||||
}
|
||||
if info.Server != nil {
|
||||
proxyServer = info.Server.String()
|
||||
}
|
||||
proxyUser = info.Username
|
||||
proxyPass = info.Password
|
||||
}
|
||||
|
||||
opts := append(chromedp.DefaultExecAllocatorOptions[:],
|
||||
chromedp.Flag("headless", headless),
|
||||
chromedp.Flag("disable-gpu", true),
|
||||
@@ -21,8 +39,8 @@ func CompleteWithChromedp(authURL, email, password, teamID string, headless bool
|
||||
chromedp.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"),
|
||||
)
|
||||
|
||||
if proxy != "" {
|
||||
opts = append(opts, chromedp.ProxyServer(proxy))
|
||||
if proxyServer != "" {
|
||||
opts = append(opts, chromedp.ProxyServer(proxyServer))
|
||||
}
|
||||
|
||||
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
|
||||
@@ -37,8 +55,36 @@ func CompleteWithChromedp(authURL, email, password, teamID string, headless bool
|
||||
var callbackURL string
|
||||
|
||||
chromedp.ListenTarget(ctx, func(ev interface{}) {
|
||||
if req, ok := ev.(*network.EventRequestWillBeSent); ok {
|
||||
url := req.Request.URL
|
||||
switch ev := ev.(type) {
|
||||
case *fetch.EventRequestPaused:
|
||||
// Fetch domain pauses requests; we must continue them to avoid stalling navigation.
|
||||
reqID := ev.RequestID
|
||||
go func() { _ = fetch.ContinueRequest(reqID).Do(ctx) }()
|
||||
|
||||
case *fetch.EventAuthRequired:
|
||||
reqID := ev.RequestID
|
||||
source := fetch.AuthChallengeSourceServer
|
||||
if ev.AuthChallenge != nil {
|
||||
source = ev.AuthChallenge.Source
|
||||
}
|
||||
|
||||
go func() {
|
||||
resp := &fetch.AuthChallengeResponse{Response: fetch.AuthChallengeResponseResponseDefault}
|
||||
if source == fetch.AuthChallengeSourceProxy {
|
||||
if proxyUser != "" {
|
||||
resp.Response = fetch.AuthChallengeResponseResponseProvideCredentials
|
||||
resp.Username = proxyUser
|
||||
resp.Password = proxyPass
|
||||
} else {
|
||||
// Fail fast if the proxy requires auth but user didn't provide credentials.
|
||||
resp.Response = fetch.AuthChallengeResponseResponseCancelAuth
|
||||
}
|
||||
}
|
||||
_ = fetch.ContinueWithAuth(reqID, resp).Do(ctx)
|
||||
}()
|
||||
|
||||
case *network.EventRequestWillBeSent:
|
||||
url := ev.Request.URL
|
||||
if strings.Contains(url, "localhost") && strings.Contains(url, "code=") {
|
||||
callbackURL = url
|
||||
}
|
||||
@@ -46,6 +92,8 @@ func CompleteWithChromedp(authURL, email, password, teamID string, headless bool
|
||||
})
|
||||
|
||||
err := chromedp.Run(ctx,
|
||||
// Handle proxy auth (407) in headless mode.
|
||||
fetch.Enable().WithHandleAuthRequests(true),
|
||||
network.Enable(),
|
||||
chromedp.Navigate(authURL),
|
||||
chromedp.WaitReady("body"),
|
||||
|
||||
Reference in New Issue
Block a user