fix(auth): avoid blocking oauth callback wait on prompt

This commit is contained in:
hkfires
2026-03-20 11:48:30 +08:00
parent 2bd646ad70
commit cccb77b552
5 changed files with 108 additions and 23 deletions

View File

@@ -305,6 +305,9 @@ func (g *GeminiAuth) getTokenFromWeb(ctx context.Context, config *oauth2.Config,
defer manualPromptTimer.Stop() defer manualPromptTimer.Stop()
} }
var manualInputCh <-chan string
var manualInputErrCh <-chan error
waitForCallback: waitForCallback:
for { for {
select { select {
@@ -326,13 +329,25 @@ waitForCallback:
return nil, err return nil, err
default: default:
} }
inputCh := make(chan string, 1)
inputErrCh := make(chan error, 1)
go func() {
input, err := opts.Prompt("Paste the Gemini callback URL (or press Enter to keep waiting): ") input, err := opts.Prompt("Paste the Gemini callback URL (or press Enter to keep waiting): ")
if err != nil { if err != nil {
return nil, err inputErrCh <- err
return
} }
parsed, err := misc.ParseOAuthCallback(input) inputCh <- input
if err != nil { }()
return nil, err manualInputCh = inputCh
manualInputErrCh = inputErrCh
continue
case input := <-manualInputCh:
manualInputCh = nil
manualInputErrCh = nil
parsed, errParse := misc.ParseOAuthCallback(input)
if errParse != nil {
return nil, errParse
} }
if parsed == nil { if parsed == nil {
continue continue
@@ -345,6 +360,8 @@ waitForCallback:
} }
authCode = parsed.Code authCode = parsed.Code
break waitForCallback break waitForCallback
case errManual := <-manualInputErrCh:
return nil, errManual
case <-timeoutTimer.C: case <-timeoutTimer.C:
return nil, fmt.Errorf("oauth flow timed out") return nil, fmt.Errorf("oauth flow timed out")
} }

View File

@@ -98,6 +98,9 @@ func (AntigravityAuthenticator) Login(ctx context.Context, cfg *config.Config, o
defer manualPromptTimer.Stop() defer manualPromptTimer.Stop()
} }
var manualInputCh <-chan string
var manualInputErrCh <-chan error
waitForCallback: waitForCallback:
for { for {
select { select {
@@ -115,10 +118,22 @@ waitForCallback:
break waitForCallback break waitForCallback
default: default:
} }
inputCh := make(chan string, 1)
inputErrCh := make(chan error, 1)
go func() {
input, errPrompt := opts.Prompt("Paste the antigravity callback URL (or press Enter to keep waiting): ") input, errPrompt := opts.Prompt("Paste the antigravity callback URL (or press Enter to keep waiting): ")
if errPrompt != nil { if errPrompt != nil {
return nil, errPrompt inputErrCh <- errPrompt
return
} }
inputCh <- input
}()
manualInputCh = inputCh
manualInputErrCh = inputErrCh
continue
case input := <-manualInputCh:
manualInputCh = nil
manualInputErrCh = nil
parsed, errParse := misc.ParseOAuthCallback(input) parsed, errParse := misc.ParseOAuthCallback(input)
if errParse != nil { if errParse != nil {
return nil, errParse return nil, errParse
@@ -132,6 +147,8 @@ waitForCallback:
Error: parsed.Error, Error: parsed.Error,
} }
break waitForCallback break waitForCallback
case errManual := <-manualInputErrCh:
return nil, errManual
case <-timeoutTimer.C: case <-timeoutTimer.C:
return nil, fmt.Errorf("antigravity: authentication timed out") return nil, fmt.Errorf("antigravity: authentication timed out")
} }

View File

@@ -124,6 +124,9 @@ func (a *ClaudeAuthenticator) Login(ctx context.Context, cfg *config.Config, opt
defer manualPromptTimer.Stop() defer manualPromptTimer.Stop()
} }
var manualInputCh <-chan string
var manualInputErrCh <-chan error
waitForCallback: waitForCallback:
for { for {
select { select {
@@ -149,10 +152,22 @@ waitForCallback:
return nil, err return nil, err
default: default:
} }
inputCh := make(chan string, 1)
inputErrCh := make(chan error, 1)
go func() {
input, errPrompt := opts.Prompt("Paste the Claude callback URL (or press Enter to keep waiting): ") input, errPrompt := opts.Prompt("Paste the Claude callback URL (or press Enter to keep waiting): ")
if errPrompt != nil { if errPrompt != nil {
return nil, errPrompt inputErrCh <- errPrompt
return
} }
inputCh <- input
}()
manualInputCh = inputCh
manualInputErrCh = inputErrCh
continue
case input := <-manualInputCh:
manualInputCh = nil
manualInputErrCh = nil
parsed, errParse := misc.ParseOAuthCallback(input) parsed, errParse := misc.ParseOAuthCallback(input)
if errParse != nil { if errParse != nil {
return nil, errParse return nil, errParse
@@ -167,6 +182,8 @@ waitForCallback:
Error: parsed.Error, Error: parsed.Error,
} }
break waitForCallback break waitForCallback
case errManual := <-manualInputErrCh:
return nil, errManual
} }
} }

View File

@@ -127,6 +127,9 @@ func (a *CodexAuthenticator) Login(ctx context.Context, cfg *config.Config, opts
defer manualPromptTimer.Stop() defer manualPromptTimer.Stop()
} }
var manualInputCh <-chan string
var manualInputErrCh <-chan error
waitForCallback: waitForCallback:
for { for {
select { select {
@@ -152,10 +155,22 @@ waitForCallback:
return nil, err return nil, err
default: default:
} }
inputCh := make(chan string, 1)
inputErrCh := make(chan error, 1)
go func() {
input, errPrompt := opts.Prompt("Paste the Codex callback URL (or press Enter to keep waiting): ") input, errPrompt := opts.Prompt("Paste the Codex callback URL (or press Enter to keep waiting): ")
if errPrompt != nil { if errPrompt != nil {
return nil, errPrompt inputErrCh <- errPrompt
return
} }
inputCh <- input
}()
manualInputCh = inputCh
manualInputErrCh = inputErrCh
continue
case input := <-manualInputCh:
manualInputCh = nil
manualInputErrCh = nil
parsed, errParse := misc.ParseOAuthCallback(input) parsed, errParse := misc.ParseOAuthCallback(input)
if errParse != nil { if errParse != nil {
return nil, errParse return nil, errParse
@@ -170,6 +185,8 @@ waitForCallback:
Error: parsed.Error, Error: parsed.Error,
} }
break waitForCallback break waitForCallback
case errManual := <-manualInputErrCh:
return nil, errManual
} }
} }

View File

@@ -109,6 +109,9 @@ func (a *IFlowAuthenticator) Login(ctx context.Context, cfg *config.Config, opts
defer manualPromptTimer.Stop() defer manualPromptTimer.Stop()
} }
var manualInputCh <-chan string
var manualInputErrCh <-chan error
waitForCallback: waitForCallback:
for { for {
select { select {
@@ -128,10 +131,22 @@ waitForCallback:
return nil, fmt.Errorf("iflow auth: callback wait failed: %w", err) return nil, fmt.Errorf("iflow auth: callback wait failed: %w", err)
default: default:
} }
inputCh := make(chan string, 1)
inputErrCh := make(chan error, 1)
go func() {
input, errPrompt := opts.Prompt("Paste the iFlow callback URL (or press Enter to keep waiting): ") input, errPrompt := opts.Prompt("Paste the iFlow callback URL (or press Enter to keep waiting): ")
if errPrompt != nil { if errPrompt != nil {
return nil, errPrompt inputErrCh <- errPrompt
return
} }
inputCh <- input
}()
manualInputCh = inputCh
manualInputErrCh = inputErrCh
continue
case input := <-manualInputCh:
manualInputCh = nil
manualInputErrCh = nil
parsed, errParse := misc.ParseOAuthCallback(input) parsed, errParse := misc.ParseOAuthCallback(input)
if errParse != nil { if errParse != nil {
return nil, errParse return nil, errParse
@@ -145,6 +160,8 @@ waitForCallback:
Error: parsed.Error, Error: parsed.Error,
} }
break waitForCallback break waitForCallback
case errManual := <-manualInputErrCh:
return nil, errManual
} }
} }
if result.Error != "" { if result.Error != "" {