diff --git a/command/get.go b/command/get.go index 09a92dbe..76873188 100644 --- a/command/get.go +++ b/command/get.go @@ -110,22 +110,20 @@ func (g GetCommand) printUsage() error { func (g GetCommand) Execute(ctx context.Context) error { if HasTokenExpired(g.Config.Tokens) { - if g.Login { - login := LoginCommand{ - Config: g.Config, - OIDCDomain: g.OIDCDomain, - ClientID: g.ClientID, - MachineOutput: ShouldUseMachineOutput(g.Flags) || g.URLOnly, - NoBrowser: g.NoBrowser, - } - - if err := login.Execute(ctx); err != nil { - return err - } - } else { + if !g.Login { return ErrTokensExpiredOrAbsent } - return nil + + loginCommand := LoginCommand{ + OIDCDomain: g.OIDCDomain, + ClientID: g.ClientID, + MachineOutput: ShouldUseMachineOutput(g.Flags) || g.URLOnly, + NoBrowser: g.NoBrowser, + } + + if err := loginCommand.Execute(ctx, g.Config); err != nil { + return err + } } var accountID string diff --git a/command/login.go b/command/login.go index 27d8162a..7b37dcfa 100644 --- a/command/login.go +++ b/command/login.go @@ -25,51 +25,55 @@ func init() { loginCmd.Flags().BoolP(FlagNoBrowser, "b", false, "Do not open a browser window, printing the URL instead") } -// ShouldUseMachineOutput indicates whether or not we should write to standard output as if the user is a machine. -// -// What this means is implementation specific, but this usually indicates the user is trying to use this program in a script and we should avoid user-friendly output messages associated with values a user might find useful. -func ShouldUseMachineOutput(flags *pflag.FlagSet) bool { - quiet, _ := flags.GetBool(FlagQuiet) - fi, _ := os.Stdout.Stat() - isPiped := fi.Mode()&os.ModeCharDevice == 0 - return isPiped || quiet -} - var loginCmd = &cobra.Command{ Use: "login", Short: "Authenticate with KeyConjurer.", Long: "Login to KeyConjurer using OAuth2. You will be required to open the URL printed to the console or scan a QR code.", RunE: func(cmd *cobra.Command, args []string) error { - config := ConfigFromCommand(cmd) - if !HasTokenExpired(config.Tokens) { - return nil + var loginCmd LoginCommand + if err := loginCmd.Parse(cmd.Flags(), args); err != nil { + return err } - oidcDomain, _ := cmd.Flags().GetString(FlagOIDCDomain) - clientID, _ := cmd.Flags().GetString(FlagClientID) - urlOnly, _ := cmd.Flags().GetBool(FlagURLOnly) - noBrowser, _ := cmd.Flags().GetBool(FlagNoBrowser) - command := LoginCommand{ - Config: config, - OIDCDomain: oidcDomain, - ClientID: clientID, - MachineOutput: ShouldUseMachineOutput(cmd.Flags()) || urlOnly, - NoBrowser: noBrowser, + if err := loginCmd.Validate(); err != nil { + return err } - return command.Execute(cmd.Context()) + return loginCmd.Execute(cmd.Context(), ConfigFromCommand(cmd)) }, } +// ShouldUseMachineOutput indicates whether or not we should write to standard output as if the user is a machine. +// +// What this means is implementation specific, but this usually indicates the user is trying to use this program in a script and we should avoid user-friendly output messages associated with values a user might find useful. +func ShouldUseMachineOutput(flags *pflag.FlagSet) bool { + quiet, _ := flags.GetBool(FlagQuiet) + fi, _ := os.Stdout.Stat() + isPiped := fi.Mode()&os.ModeCharDevice == 0 + return isPiped || quiet +} + type LoginCommand struct { - Config *Config OIDCDomain string ClientID string MachineOutput bool NoBrowser bool } -func (c LoginCommand) Execute(ctx context.Context) error { +func (c *LoginCommand) Parse(flags *pflag.FlagSet, args []string) error { + c.OIDCDomain, _ = flags.GetString(FlagOIDCDomain) + c.ClientID, _ = flags.GetString(FlagClientID) + c.NoBrowser, _ = flags.GetBool(FlagNoBrowser) + urlOnly, _ := flags.GetBool(FlagURLOnly) + c.MachineOutput = ShouldUseMachineOutput(flags) || urlOnly + return nil +} + +func (c LoginCommand) Execute(ctx context.Context, config *Config) error { + if !HasTokenExpired(config.Tokens) { + return nil + } + oauthCfg, err := oauth2.DiscoverConfig(ctx, c.OIDCDomain, c.ClientID) if err != nil { return err @@ -111,7 +115,7 @@ func (c LoginCommand) Execute(ctx context.Context) error { return fmt.Errorf("id_token not found in token response") } - return c.Config.SaveOAuthToken(accessToken, idToken) + return config.SaveOAuthToken(accessToken, idToken) } var ErrNoPortsAvailable = errors.New("no ports available") diff --git a/internal/api/json.go b/internal/api/json.go index 0b28abf9..8a00cee6 100644 --- a/internal/api/json.go +++ b/internal/api/json.go @@ -20,12 +20,11 @@ func ServeJSON[T any](w *events.ALBTargetGroupResponse, data T) { w.Body = string(buf) } -func ServeJSONError(w *events.ALBTargetGroupResponse, statusCode int, msg string) { - var jsonError struct { - Message string `json:"error"` - } +type JSONError struct { + Message string `json:"error"` +} - jsonError.Message = msg +func ServeJSONError(w *events.ALBTargetGroupResponse, statusCode int, msg string) { w.StatusCode = statusCode - ServeJSON(w, jsonError) + ServeJSON(w, JSONError{Message: msg}) }