diff --git a/cmd/helm/chart_login.go b/cmd/helm/chart_login.go index 729c68f3d..a093dc38c 100644 --- a/cmd/helm/chart_login.go +++ b/cmd/helm/chart_login.go @@ -17,8 +17,15 @@ limitations under the License. package main import ( + "bufio" + "errors" + "fmt" "io" + "io/ioutil" + "os" + "strings" + "github.com/docker/docker/pkg/term" "github.com/spf13/cobra" "helm.sh/helm/cmd/helm/require" @@ -30,14 +37,98 @@ Authenticate to a remote registry. ` func newChartLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { - return &cobra.Command{ + var usernameOpt, passwordOpt string + var passwordFromStdinOpt bool + + cmd := &cobra.Command{ Use: "login [host]", Short: "login to a registry", Long: chartLoginDesc, Args: require.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { hostname := args[0] - return action.NewChartLogin(cfg).Run(out, hostname, "myuser", "mypass") + + username, password, err := getUsernamePassword(usernameOpt, passwordOpt, passwordFromStdinOpt) + if err != nil { + return err + } + + return action.NewChartLogin(cfg).Run(out, hostname, username, password) }, } + + f := cmd.Flags() + f.StringVarP(&usernameOpt, "username", "u", "", "registry username") + f.StringVarP(&passwordOpt, "password", "p", "", "registry password or identity token") + f.BoolVarP(&passwordFromStdinOpt, "password-stdin", "", false, "read password or identity token from stdin") + + return cmd +} + +// Adapted from https://github.com/deislabs/oras +func getUsernamePassword(usernameOpt string, passwordOpt string, passwordFromStdinOpt bool) (string, string, error) { + var err error + username := usernameOpt + password := passwordOpt + + if passwordFromStdinOpt { + passwordFromStdin, err := ioutil.ReadAll(os.Stdin) + if err != nil { + return "", "", err + } + password = strings.TrimSuffix(string(passwordFromStdin), "\n") + password = strings.TrimSuffix(password, "\r") + } else if password == "" { + if username == "" { + username, err = readLine("Username: ", false) + if err != nil { + return "", "", err + } + username = strings.TrimSpace(username) + } + if username == "" { + password, err = readLine("Token: ", true) + if err != nil { + return "", "", err + } else if password == "" { + return "", "", errors.New("token required") + } + } else { + password, err = readLine("Password: ", true) + if err != nil { + return "", "", err + } else if password == "" { + return "", "", errors.New("password required") + } + } + } else { + fmt.Fprintln(os.Stderr, "WARNING! Using --password via the CLI is insecure. Use --password-stdin.") + } + + return username, password, nil +} + +// Copied from https://github.com/deislabs/oras +func readLine(prompt string, slient bool) (string, error) { + fmt.Print(prompt) + if slient { + fd := os.Stdin.Fd() + state, err := term.SaveState(fd) + if err != nil { + return "", err + } + term.DisableEcho(fd, state) + defer term.RestoreTerminal(fd, state) + } + + reader := bufio.NewReader(os.Stdin) + line, _, err := reader.ReadLine() + if err != nil { + return "", err + } + if slient { + fmt.Println() + } + + return string(line), nil }