@@ -14,6 +14,7 @@ import (
1414 "os/signal"
1515 "strconv"
1616 "strings"
17+ "sync"
1718 "syscall"
1819 "time"
1920
@@ -28,18 +29,18 @@ import (
2829)
2930
3031var (
31- serverURL string
32- clientID string
33- clientSecret string
34- redirectURI string
35- callbackPort int
36- scope string
37- tokenFile string
38- tokenStoreMode string
39- tokenStore credstore.Store [credstore.Token ]
40- configInitialized bool
41- retryClient * retry.Client
42- configWarnings []string
32+ serverURL string
33+ clientID string
34+ clientSecret string
35+ redirectURI string
36+ callbackPort int
37+ scope string
38+ tokenFile string
39+ tokenStoreMode string
40+ tokenStore credstore.Store [credstore.Token ]
41+ configOnce sync. Once
42+ retryClient * retry.Client
43+ configWarnings []string
4344
4445 flagServerURL * string
4546 flagClientID * string
@@ -55,6 +56,7 @@ const (
5556 tokenExchangeTimeout = 10 * time .Second
5657 tokenVerificationTimeout = 10 * time .Second
5758 refreshTokenTimeout = 10 * time .Second
59+ maxResponseSize = 1 << 20 // 1 MB
5860)
5961
6062func init () {
@@ -96,16 +98,21 @@ func init() {
9698
9799// initConfig parses flags and initializes all configuration.
98100func initConfig () {
99- if configInitialized {
100- return
101- }
102- configInitialized = true
101+ configOnce .Do (doInitConfig )
102+ }
103103
104+ func doInitConfig () {
104105 flag .Parse ()
105106
106107 serverURL = getConfig (* flagServerURL , "SERVER_URL" , "http://localhost:8080" )
107108 clientID = getConfig (* flagClientID , "CLIENT_ID" , "" )
108109 clientSecret = getConfig (* flagClientSecret , "CLIENT_SECRET" , "" )
110+ if * flagClientSecret != "" {
111+ configWarnings = append (configWarnings ,
112+ "Client secret passed via command-line flag. " +
113+ "This may be visible in process listings. " +
114+ "Consider using CLIENT_SECRET env var or .env file instead." )
115+ }
109116 scope = getConfig (* flagScope , "SCOPE" , "read write" )
110117 tokenFile = getConfig (* flagTokenFile , "TOKEN_FILE" , ".authgate-tokens.json" )
111118
@@ -341,7 +348,7 @@ func exchangeCode(ctx context.Context, code, codeVerifier string) (*tui.TokenSto
341348 }
342349 defer resp .Body .Close ()
343350
344- body , err := io .ReadAll (resp .Body )
351+ body , err := io .ReadAll (io . LimitReader ( resp .Body , maxResponseSize ) )
345352 if err != nil {
346353 return nil , fmt .Errorf ("failed to read response: %w" , err )
347354 }
@@ -405,7 +412,7 @@ func refreshAccessToken(ctx context.Context, refreshToken string) (*tui.TokenSto
405412 }
406413 defer resp .Body .Close ()
407414
408- body , err := io .ReadAll (resp .Body )
415+ body , err := io .ReadAll (io . LimitReader ( resp .Body , maxResponseSize ) )
409416 if err != nil {
410417 return nil , fmt .Errorf ("failed to read response: %w" , err )
411418 }
@@ -472,7 +479,7 @@ func verifyToken(ctx context.Context, accessToken string) (string, error) {
472479 }
473480 defer resp .Body .Close ()
474481
475- body , err := io .ReadAll (resp .Body )
482+ body , err := io .ReadAll (io . LimitReader ( resp .Body , maxResponseSize ) )
476483 if err != nil {
477484 return "" , fmt .Errorf ("failed to read response: %w" , err )
478485 }
@@ -531,7 +538,7 @@ func makeAPICallWithAutoRefresh(ctx context.Context, storage *tui.TokenStorage)
531538 defer resp .Body .Close ()
532539 }
533540
534- body , err := io .ReadAll (resp .Body )
541+ body , err := io .ReadAll (io . LimitReader ( resp .Body , maxResponseSize ) )
535542 if err != nil {
536543 return fmt .Errorf ("failed to read response: %w" , err )
537544 }
0 commit comments