@@ -3,8 +3,6 @@ package command
33import (
44 "bufio"
55 "context"
6- "encoding/base64"
7- "encoding/json"
86 "fmt"
97 "io"
108 "os"
@@ -21,13 +19,9 @@ import (
2119 "github.com/pkg/errors"
2220)
2321
24- // EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload
22+ // EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload.
2523func EncodeAuthToBase64 (authConfig registrytypes.AuthConfig ) (string , error ) {
26- buf , err := json .Marshal (authConfig )
27- if err != nil {
28- return "" , err
29- }
30- return base64 .URLEncoding .EncodeToString (buf ), nil
24+ return registrytypes .EncodeAuthConfig (authConfig )
3125}
3226
3327// RegistryAuthenticationPrivilegedFunc returns a RequestPrivilegeFunc from the specified registry index info
@@ -45,7 +39,7 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
4539 if err != nil {
4640 return "" , err
4741 }
48- return EncodeAuthToBase64 (authConfig )
42+ return registrytypes . EncodeAuthConfig (authConfig )
4943 }
5044}
5145
@@ -89,7 +83,14 @@ func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, is
8983
9084// ConfigureAuth handles prompting of user's username and password if needed
9185func ConfigureAuth (cli Cli , flUser , flPassword string , authconfig * registrytypes.AuthConfig , isDefaultRegistry bool ) error {
92- // On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
86+ // On Windows, force the use of the regular OS stdin stream.
87+ //
88+ // See:
89+ // - https://github.com/moby/moby/issues/14336
90+ // - https://github.com/moby/moby/issues/14210
91+ // - https://github.com/moby/moby/pull/17738
92+ //
93+ // TODO(thaJeztah): we need to confirm if this special handling is still needed, as we may not be doing this in other places.
9394 if runtime .GOOS == "windows" {
9495 cli .SetIn (streams .NewIn (os .Stdin ))
9596 }
@@ -113,8 +114,11 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
113114 fmt .Fprintln (cli .Out (), "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one." )
114115 }
115116 promptWithDefault (cli .Out (), "Username" , authconfig .Username )
116- flUser = readInput (cli .In (), cli .Out ())
117- flUser = strings .TrimSpace (flUser )
117+ var err error
118+ flUser , err = readInput (cli .In ())
119+ if err != nil {
120+ return err
121+ }
118122 if flUser == "" {
119123 flUser = authconfig .Username
120124 }
@@ -128,12 +132,15 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
128132 return err
129133 }
130134 fmt .Fprintf (cli .Out (), "Password: " )
131- term .DisableEcho (cli .In ().FD (), oldState )
132-
133- flPassword = readInput (cli .In (), cli .Out ())
135+ _ = term .DisableEcho (cli .In ().FD (), oldState )
136+ defer func () {
137+ _ = term .RestoreTerminal (cli .In ().FD (), oldState )
138+ }()
139+ flPassword , err = readInput (cli .In ())
140+ if err != nil {
141+ return err
142+ }
134143 fmt .Fprint (cli .Out (), "\n " )
135-
136- term .RestoreTerminal (cli .In ().FD (), oldState )
137144 if flPassword == "" {
138145 return errors .Errorf ("Error: Password Required" )
139146 }
@@ -145,14 +152,15 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *registrytypes
145152 return nil
146153}
147154
148- func readInput (in io.Reader , out io.Writer ) string {
149- reader := bufio .NewReader (in )
150- line , _ , err := reader .ReadLine ()
155+ // readInput reads, and returns user input from in. It tries to return a
156+ // single line, not including the end-of-line bytes, and trims leading
157+ // and trailing whitespace.
158+ func readInput (in io.Reader ) (string , error ) {
159+ line , _ , err := bufio .NewReader (in ).ReadLine ()
151160 if err != nil {
152- fmt .Fprintln (out , err .Error ())
153- os .Exit (1 )
161+ return "" , errors .Wrap (err , "error while reading input" )
154162 }
155- return string (line )
163+ return strings . TrimSpace ( string (line )), nil
156164}
157165
158166func promptWithDefault (out io.Writer , prompt string , configDefault string ) {
@@ -163,14 +171,19 @@ func promptWithDefault(out io.Writer, prompt string, configDefault string) {
163171 }
164172}
165173
166- // RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete image
174+ // RetrieveAuthTokenFromImage retrieves an encoded auth token given a complete
175+ // image. The auth configuration is serialized as a base64url encoded RFC4648,
176+ // section 5) JSON string for sending through the X-Registry-Auth header.
177+ //
178+ // For details on base64url encoding, see:
179+ // - RFC4648, section 5: https://tools.ietf.org/html/rfc4648#section-5
167180func RetrieveAuthTokenFromImage (ctx context.Context , cli Cli , image string ) (string , error ) {
168181 // Retrieve encoded auth token from the image reference
169182 authConfig , err := resolveAuthConfigFromImage (ctx , cli , image )
170183 if err != nil {
171184 return "" , err
172185 }
173- encodedAuth , err := EncodeAuthToBase64 (authConfig )
186+ encodedAuth , err := registrytypes . EncodeAuthConfig (authConfig )
174187 if err != nil {
175188 return "" , err
176189 }
0 commit comments