feat: Implement browserless Codex API authentication with PoW solving and a new mail service, and update gitignore to exclude get_code.go.

This commit is contained in:
2026-02-04 09:43:22 +08:00
parent 381cbd41fa
commit 61712cf4fb
3 changed files with 106 additions and 3 deletions

View File

@@ -482,6 +482,10 @@ func (c *CodexAPIAuth) ObtainAuthorizationCode() (string, error) {
c.logStep(StepInputPassword, "验证密码...")
if pageType == "password" || strings.Contains(string(body), "password") {
// 在密码验证前记录最新邮件ID (基于 get_code.go 的增强逻辑)
latestEmailID := mail.GetLatestEmailID(c.email)
c.logStep(StepInputPassword, "记录当前最新邮件ID: %d", latestEmailID)
// 5. 验证密码
if !c.callSentinelReq("authorize_continue__auto") {
return "", fmt.Errorf("Sentinel 请求失败")
@@ -519,9 +523,9 @@ func (c *CodexAPIAuth) ObtainAuthorizationCode() (string, error) {
if nextPageType == "email_otp_verification" {
c.logStep(StepInputPassword, "账号需要邮箱验证,正在获取验证码...")
// 等待获取验证码 (最多60秒)
// 邮件标题格式: "Your ChatGPT code is 016547"
otpCode, err := mail.GetVerificationCode(c.email, 60*time.Second)
// 使用邮件ID过滤获取新的OTP验证码 (最多30秒)
// 基于 get_code.go 的增强逻辑使用邮件ID过滤避免获取到旧邮件的验证码
otpCode, err := mail.GetEmailOTPAfterID(c.email, latestEmailID, 30*time.Second)
if err != nil {
c.logError(StepInputPassword, "获取验证码失败: %v", err)
return "", fmt.Errorf("获取验证码失败: %v", err)
@@ -558,6 +562,20 @@ func (c *CodexAPIAuth) ObtainAuthorizationCode() (string, error) {
// 重新解析响应,检查下一步
json.Unmarshal(body, &data)
}
// 基于 get_code.go 的增强逻辑:检查是否有 continue_url
// 如果有,直接跟随重定向获取授权码,跳过工作区选择
if cu, ok := data["continue_url"].(string); ok && cu != "" && !strings.Contains(cu, "email-verification") {
if strings.Contains(cu, "consent") {
// 访问 consent 页面
c.logStep(StepSelectWorkspace, "处理 consent 页面...")
c.doRequest("GET", cu, nil, headers)
} else {
// 直接跟随重定向获取授权码
c.logStep(StepWaitCallback, "跟随 continue_url 重定向...")
return c.followRedirectsForCode(cu, headers)
}
}
} else {
c.logStep(StepInputPassword, "跳过密码验证步骤 (服务器未要求)")
}
@@ -656,6 +674,35 @@ func (c *CodexAPIAuth) ExchangeCodeForTokens(code, codeVerifier string) (*CodexT
return &tokens, nil
}
// followRedirectsForCode 跟随重定向获取授权码
// 基于 get_code.go 的实现,用于复用重定向逻辑
func (c *CodexAPIAuth) followRedirectsForCode(continueURL string, headers map[string]string) (string, error) {
c.logStep(StepWaitCallback, "跟随重定向获取授权码...")
for i := 0; i < 10; i++ {
resp, _, err := c.doRequest("GET", continueURL, nil, headers)
if err != nil {
break
}
if resp.StatusCode >= 300 && resp.StatusCode < 400 {
location := resp.Header.Get("Location")
if strings.Contains(location, "localhost:1455") {
code := ExtractCodeFromCallbackURL(location)
if code != "" {
c.logStep(StepComplete, "授权成功,获取到授权码")
return code, nil
}
}
continueURL = location
} else {
break
}
}
c.logError(StepWaitCallback, "未能获取授权码")
return "", fmt.Errorf("未能获取授权码")
}
// min 返回较小值
func min(a, b int) int {
if a < b {