package commands import ( "bufio" gocontext "context" "crypto/tls" "fmt" "net" "net/http" "strings" "time" "github.com/containerd/console" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" "github.com/pkg/errors" "github.com/urfave/cli" ) // PushTracker returns a new InMemoryTracker which tracks the ref status var PushTracker = docker.NewInMemoryTracker() func passwordPrompt() (string, error) { c := console.Current() defer c.Reset() if err := c.DisableEcho(); err != nil { return "", errors.Wrap(err, "failed to disable echo") } line, _, err := bufio.NewReader(c).ReadLine() if err != nil { return "", errors.Wrap(err, "failed to read line") } return string(line), nil } // GetResolver prepares the resolver from the environment and options func GetResolver(ctx gocontext.Context, clicontext *cli.Context) (remotes.Resolver, error) { username := clicontext.String("user") var secret string if i := strings.IndexByte(username, ':'); i > 0 { secret = username[i+1:] username = username[0:i] } options := docker.ResolverOptions{ PlainHTTP: clicontext.Bool("plain-http"), Tracker: PushTracker, } if username != "" { if secret == "" { fmt.Printf("Password: ") var err error secret, err = passwordPrompt() if err != nil { return nil, err } fmt.Print("\n") } } else if rt := clicontext.String("refresh"); rt != "" { secret = rt } options.Credentials = func(host string) (string, string, error) { // Only one host return username, secret, nil } tr := &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, DualStack: true, }).DialContext, MaxIdleConns: 10, IdleConnTimeout: 30 * time.Second, TLSHandshakeTimeout: 10 * time.Second, TLSClientConfig: &tls.Config{ InsecureSkipVerify: clicontext.Bool("insecure"), }, ExpectContinueTimeout: 5 * time.Second, } options.Client = &http.Client{ Transport: tr, } return docker.NewResolver(options), nil }