github.com/saucelabs/saucectl@v0.175.1/internal/cmd/configure/cmd.go (about) 1 package configure 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "strings" 8 9 "github.com/AlecAivazis/survey/v2" 10 "github.com/fatih/color" 11 "github.com/rs/zerolog/log" 12 "github.com/saucelabs/saucectl/internal/credentials" 13 "github.com/saucelabs/saucectl/internal/iam" 14 "github.com/saucelabs/saucectl/internal/msg" 15 "github.com/saucelabs/saucectl/internal/segment" 16 "github.com/spf13/cobra" 17 ) 18 19 var ( 20 configureUse = "configure" 21 configureShort = "Configure your Sauce Labs credentials" 22 configureLong = `Persist locally your Sauce Labs credentials` 23 configureExample = "saucectl configure" 24 cliUsername = "" 25 cliAccessKey = "" 26 ) 27 28 // Command creates the `configure` command 29 func Command() *cobra.Command { 30 cmd := &cobra.Command{ 31 Use: configureUse, 32 Short: configureShort, 33 Long: configureLong, 34 Example: configureExample, 35 SilenceUsage: true, 36 Run: func(cmd *cobra.Command, args []string) { 37 tracker := segment.DefaultTracker 38 39 go func() { 40 tracker.Collect("Configure", nil) 41 _ = tracker.Close() 42 }() 43 44 if err := Run(); err != nil { 45 log.Err(err).Msg("failed to execute configure command") 46 os.Exit(1) 47 } 48 }, 49 } 50 cmd.Flags().StringVarP(&cliUsername, "username", "u", "", "username, available on your sauce labs account") 51 cmd.Flags().StringVarP(&cliAccessKey, "accessKey", "a", "", "accessKey, available on your sauce labs account") 52 53 cmd.AddCommand(ListCommand()) 54 return cmd 55 } 56 57 func printCreds(creds iam.Credentials) { 58 fmt.Println() 59 60 labelStyle := color.New(color.Bold) 61 valueStyle := color.New(color.FgBlue) 62 63 fmt.Println("Currently configured credentials:") 64 fmt.Println(labelStyle.Sprint("\t Username:"), valueStyle.Sprint(creds.Username)) 65 fmt.Println(labelStyle.Sprint("\tAccess key:"), valueStyle.Sprint(mask(creds.AccessKey))) 66 67 fmt.Println() 68 fmt.Printf("Collected from: %s", creds.Source) 69 70 fmt.Println() 71 fmt.Println() 72 } 73 74 // interactiveConfiguration expect user to manually type-in its credentials 75 func interactiveConfiguration() (iam.Credentials, error) { 76 overwrite := true 77 var err error 78 79 creds := credentials.Get() 80 81 if creds.IsSet() { 82 printCreds(creds) 83 84 qs := &survey.Confirm{ 85 Message: "Overwrite existing credentials?", 86 } 87 err = survey.AskOne(qs, &overwrite) 88 if err != nil { 89 return creds, err 90 } 91 } 92 93 if overwrite { 94 if !creds.IsSet() { 95 fmt.Println(msg.SignupMessage) 96 } 97 98 qs := []*survey.Question{ 99 { 100 Name: "username", 101 Prompt: &survey.Input{ 102 Message: "SauceLabs username", 103 }, 104 Validate: func(val interface{}) error { 105 str, ok := val.(string) 106 if !ok { 107 return errors.New(msg.InvalidUsername) 108 } 109 str = strings.TrimSpace(str) 110 if str == "" { 111 return errors.New(msg.EmptyUsername) 112 113 } 114 return nil 115 }, 116 }, 117 { 118 Name: "accessKey", 119 Prompt: &survey.Password{ 120 Message: "SauceLabs access key", 121 }, 122 Validate: func(val interface{}) error { 123 str, ok := val.(string) 124 if !ok { 125 return errors.New(msg.InvalidAccessKey) 126 } 127 str = strings.TrimSpace(str) 128 if str == "" { 129 return errors.New(msg.EmptyAccessKey) 130 131 } 132 return nil 133 }, 134 }, 135 } 136 137 fmt.Println() // visual paragraph break 138 if err = survey.Ask(qs, &creds); err != nil { 139 return creds, err 140 } 141 fmt.Println() // visual paragraph break 142 } 143 144 return creds, nil 145 } 146 147 // Run starts the configure command 148 func Run() error { 149 var creds iam.Credentials 150 var err error 151 152 if cliUsername == "" && cliAccessKey == "" { 153 creds, err = interactiveConfiguration() 154 } else { 155 creds = iam.Credentials{ 156 Username: cliUsername, 157 AccessKey: cliAccessKey, 158 } 159 } 160 if err != nil { 161 return err 162 } 163 164 if !creds.IsSet() { 165 log.Error().Msg("The provided credentials appear to be invalid and will NOT be saved.") 166 return fmt.Errorf(msg.InvalidCredentials) 167 } 168 if err := credentials.ToFile(creds); err != nil { 169 return fmt.Errorf("unable to save credentials: %s", err) 170 } 171 fmt.Println("You're all set!") 172 return nil 173 } 174 175 func mask(str string) string { 176 n := len(str) 177 if n == 0 { 178 return "" 179 } 180 res := []byte{} 181 for i := 0; i < n; i++ { 182 if str[i] == '-' { 183 res = append(res, str[i]) 184 } else if i >= n-4 { 185 res = append(res, str[i]) 186 } else { 187 res = append(res, '*') 188 } 189 } 190 return string(res) 191 }