PromptUserForCredentials handles the CLI prompt for the user to input credentials. If argUser is not empty, then the user is only prompted for their password. If argPassword is not empty, then the user is only prompted for their username If neither argUser nor argPassword are empty, then the user is
(ctx context.Context, cli Cli, argUser, argPassword, defaultUsername, serverAddress string)
| 98 | // and the user can hit enter without inputting a username to use that default |
| 99 | // username. |
| 100 | func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword, defaultUsername, serverAddress string) (registrytypes.AuthConfig, error) { |
| 101 | // On Windows, force the use of the regular OS stdin stream. |
| 102 | // |
| 103 | // See: |
| 104 | // - https://github.com/moby/moby/issues/14336 |
| 105 | // - https://github.com/moby/moby/issues/14210 |
| 106 | // - https://github.com/moby/moby/pull/17738 |
| 107 | // |
| 108 | // TODO(thaJeztah): we need to confirm if this special handling is still needed, as we may not be doing this in other places. |
| 109 | if runtime.GOOS == "windows" { |
| 110 | cli.SetIn(streams.NewIn(os.Stdin)) |
| 111 | } |
| 112 | |
| 113 | argUser = strings.TrimSpace(argUser) |
| 114 | if argUser == "" { |
| 115 | if serverAddress == authConfigKey { |
| 116 | // When signing in to the default (Docker Hub) registry, we display |
| 117 | // hints for creating an account, and (if hints are enabled), using |
| 118 | // a token instead of a password. |
| 119 | _, _ = fmt.Fprintln(cli.Out(), registerSuggest) |
| 120 | if hints.Enabled() { |
| 121 | _, _ = fmt.Fprintln(cli.Out(), patSuggest) |
| 122 | _, _ = fmt.Fprintln(cli.Out()) |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | var msg string |
| 127 | defaultUsername = strings.TrimSpace(defaultUsername) |
| 128 | if defaultUsername == "" { |
| 129 | msg = "Username: " |
| 130 | } else { |
| 131 | msg = fmt.Sprintf("Username (%s): ", defaultUsername) |
| 132 | } |
| 133 | |
| 134 | var err error |
| 135 | argUser, err = prompt.ReadInput(ctx, cli.In(), cli.Out(), msg) |
| 136 | if err != nil { |
| 137 | return registrytypes.AuthConfig{}, err |
| 138 | } |
| 139 | if argUser == "" { |
| 140 | argUser = defaultUsername |
| 141 | } |
| 142 | if argUser == "" { |
| 143 | return registrytypes.AuthConfig{}, errors.New("error: username is required") |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | isEmpty := strings.TrimSpace(argPassword) == "" |
| 148 | if isEmpty { |
| 149 | restoreInput, err := prompt.DisableInputEcho(cli.In()) |
| 150 | if err != nil { |
| 151 | return registrytypes.AuthConfig{}, err |
| 152 | } |
| 153 | defer func() { |
| 154 | if err := restoreInput(); err != nil { |
| 155 | // TODO(thaJeztah): we should consider printing instructions how |
| 156 | // to restore this manually (other than restarting the shell). |
| 157 | // e.g., 'run stty echo' when in a Linux or macOS shell, but |