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  }