@@ -11,7 +11,20 @@ import (
1111 "net/http"
1212)
1313
14+ // Request returns the API client for a command run. Without a static token it
15+ // signs in through OAuth, opening the browser when needed.
1416func Request () client.ClientWithResponsesInterface {
17+ return newClient (true )
18+ }
19+
20+ // CompletionRequest returns an API client for shell completion: it uses the
21+ // static token or an already stored OAuth sign-in, and never starts an
22+ // interactive login.
23+ func CompletionRequest () client.ClientWithResponsesInterface {
24+ return newClient (false )
25+ }
26+
27+ func newClient (interactive bool ) client.ClientWithResponsesInterface {
1528 apiURL := viper .GetString ("api_url" )
1629 if apiURL == "" {
1730 apiURL = "https://developers.hostinger.com"
@@ -21,14 +34,22 @@ func Request() client.ClientWithResponsesInterface {
2134 client .WithRequestEditorFn (addUserAgent ),
2235 }
2336
24- if staticToken := viper .GetString ("api_token" ); staticToken != "" {
37+ var doer client.HttpRequestDoer = & http.Client {}
38+ if viper .GetBool ("verbose" ) {
39+ doer = & verboseDoer {base : doer }
40+ }
41+
42+ if interactive && viper .GetBool ("dry_run" ) {
43+ // Print the request instead of sending it; no credentials are needed.
44+ opts = append (opts , client .WithHTTPClient (& dryRunDoer {}))
45+ } else if staticToken := viper .GetString ("api_token" ); staticToken != "" {
2546 // Static token wins: use it unchanged. OAuth and 401 re-auth are skipped
2647 // because there is no refresh source for a user-managed token.
2748 bearer , err := securityprovider .NewSecurityProviderBearerToken (staticToken )
2849 if err != nil {
2950 panic (err )
3051 }
31- opts = append (opts , client .WithRequestEditorFn (bearer .Intercept ))
52+ opts = append (opts , client .WithRequestEditorFn (bearer .Intercept ), client . WithHTTPClient ( doer ) )
3253 } else {
3354 // No static token: obtain the bearer via the OAuth service, and retry
3455 // once on a 401 after forcing a fresh token.
@@ -37,8 +58,8 @@ func Request() client.ClientWithResponsesInterface {
3758 log .Fatal (err )
3859 }
3960 opts = append (opts ,
40- client .WithRequestEditorFn (oauthBearer (oauth )),
41- client .WithHTTPClient (& oauthRetryDoer {oauth : oauth , base : & http. Client {} }),
61+ client .WithRequestEditorFn (oauthBearer (oauth , interactive )),
62+ client .WithHTTPClient (& oauthRetryDoer {oauth : oauth , base : doer , interactive : interactive }),
4263 )
4364 }
4465
@@ -51,10 +72,15 @@ func Request() client.ClientWithResponsesInterface {
5172}
5273
5374// oauthBearer resolves a token (cached -> refresh -> interactive login) and
54- // attaches it as the Authorization header before each request is sent.
55- func oauthBearer (oauth * OAuthService ) client.RequestEditorFn {
75+ // attaches it as the Authorization header before each request is sent. When
76+ // interactive is false the login step is skipped.
77+ func oauthBearer (oauth * OAuthService , interactive bool ) client.RequestEditorFn {
5678 return func (ctx context.Context , req * http.Request ) error {
57- token , err := oauth .Token (ctx )
79+ resolve := oauth .Token
80+ if ! interactive {
81+ resolve = oauth .TokenNoLogin
82+ }
83+ token , err := resolve (ctx )
5884 if err != nil {
5985 return err
6086 }
@@ -65,15 +91,17 @@ func oauthBearer(oauth *OAuthService) client.RequestEditorFn {
6591
6692// oauthRetryDoer performs API requests and, on a 401, forces a fresh token via
6793// Reauthenticate and retries the request exactly once (spec §8). A second 401
68- // is returned to the caller unchanged — it never loops.
94+ // is returned to the caller unchanged — it never loops. Non-interactive
95+ // clients return the first 401 as is.
6996type oauthRetryDoer struct {
70- oauth * OAuthService
71- base client.HttpRequestDoer
97+ oauth * OAuthService
98+ base client.HttpRequestDoer
99+ interactive bool
72100}
73101
74102func (d * oauthRetryDoer ) Do (req * http.Request ) (* http.Response , error ) {
75103 resp , err := d .base .Do (req )
76- if err != nil || resp .StatusCode != http .StatusUnauthorized {
104+ if err != nil || resp .StatusCode != http .StatusUnauthorized || ! d . interactive {
77105 return resp , err
78106 }
79107
0 commit comments