github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/api/client/login.go (about) 1 package client 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "os" 8 "runtime" 9 "strings" 10 11 Cli "github.com/docker/docker/cli" 12 flag "github.com/docker/docker/pkg/mflag" 13 "github.com/docker/docker/pkg/term" 14 "github.com/docker/engine-api/client" 15 "github.com/docker/engine-api/types" 16 ) 17 18 // CmdLogin logs in or registers a user to a Docker registry service. 19 // 20 // If no server is specified, the user will be logged into or registered to the registry's index server. 21 // 22 // Usage: docker login SERVER 23 func (cli *DockerCli) CmdLogin(args ...string) error { 24 cmd := Cli.Subcmd("login", []string{"[SERVER]"}, Cli.DockerCommands["login"].Description+".\nIf no server is specified, the default is defined by the daemon.", true) 25 cmd.Require(flag.Max, 1) 26 27 flUser := cmd.String([]string{"u", "-username"}, "", "Username") 28 flPassword := cmd.String([]string{"p", "-password"}, "", "Password") 29 flEmail := cmd.String([]string{"e", "-email"}, "", "Email") 30 31 cmd.ParseFlags(args, true) 32 33 // On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210 34 if runtime.GOOS == "windows" { 35 cli.in = os.Stdin 36 } 37 38 var serverAddress string 39 if len(cmd.Args()) > 0 { 40 serverAddress = cmd.Arg(0) 41 } else { 42 serverAddress = cli.electAuthServer() 43 } 44 45 authConfig, err := cli.configureAuth(*flUser, *flPassword, *flEmail, serverAddress) 46 if err != nil { 47 return err 48 } 49 50 response, err := cli.client.RegistryLogin(authConfig) 51 if err != nil { 52 if client.IsErrUnauthorized(err) { 53 delete(cli.configFile.AuthConfigs, serverAddress) 54 if err2 := cli.configFile.Save(); err2 != nil { 55 fmt.Fprintf(cli.out, "WARNING: could not save config file: %v\n", err2) 56 } 57 } 58 return err 59 } 60 61 if err := cli.configFile.Save(); err != nil { 62 return fmt.Errorf("Error saving config file: %v", err) 63 } 64 fmt.Fprintf(cli.out, "WARNING: login credentials saved in %s\n", cli.configFile.Filename()) 65 66 if response.Status != "" { 67 fmt.Fprintf(cli.out, "%s\n", response.Status) 68 } 69 return nil 70 } 71 72 func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) { 73 if configDefault == "" { 74 fmt.Fprintf(cli.out, "%s: ", prompt) 75 } else { 76 fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault) 77 } 78 } 79 80 func (cli *DockerCli) configureAuth(flUser, flPassword, flEmail, serverAddress string) (types.AuthConfig, error) { 81 authconfig, ok := cli.configFile.AuthConfigs[serverAddress] 82 if !ok { 83 authconfig = types.AuthConfig{} 84 } 85 86 if flUser == "" { 87 cli.promptWithDefault("Username", authconfig.Username) 88 flUser = readInput(cli.in, cli.out) 89 flUser = strings.TrimSpace(flUser) 90 if flUser == "" { 91 flUser = authconfig.Username 92 } 93 } 94 95 if flPassword == "" { 96 oldState, err := term.SaveState(cli.inFd) 97 if err != nil { 98 return authconfig, err 99 } 100 fmt.Fprintf(cli.out, "Password: ") 101 term.DisableEcho(cli.inFd, oldState) 102 103 flPassword = readInput(cli.in, cli.out) 104 fmt.Fprint(cli.out, "\n") 105 106 term.RestoreTerminal(cli.inFd, oldState) 107 if flPassword == "" { 108 return authconfig, fmt.Errorf("Error : Password Required") 109 } 110 } 111 112 // Assume that a different username means they may not want to use 113 // the email from the config file, so prompt it 114 if flUser != authconfig.Username { 115 if flEmail == "" { 116 cli.promptWithDefault("Email", authconfig.Email) 117 flEmail = readInput(cli.in, cli.out) 118 if flEmail == "" { 119 flEmail = authconfig.Email 120 } 121 } 122 } else { 123 // However, if they don't override the username use the 124 // email from the cmd line if specified. IOW, allow 125 // then to change/override them. And if not specified, just 126 // use what's in the config file 127 if flEmail == "" { 128 flEmail = authconfig.Email 129 } 130 } 131 authconfig.Username = flUser 132 authconfig.Password = flPassword 133 authconfig.Email = flEmail 134 authconfig.ServerAddress = serverAddress 135 cli.configFile.AuthConfigs[serverAddress] = authconfig 136 return authconfig, nil 137 } 138 139 func readInput(in io.Reader, out io.Writer) string { 140 reader := bufio.NewReader(in) 141 line, _, err := reader.ReadLine() 142 if err != nil { 143 fmt.Fprintln(out, err.Error()) 144 os.Exit(1) 145 } 146 return string(line) 147 }