github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/internal/commands/credentials.go (about) 1 package commands 2 3 import ( 4 "context" 5 "encoding/json" 6 "io/ioutil" 7 "os" 8 "strings" 9 10 "github.com/deislabs/cnab-go/bundle" 11 "github.com/deislabs/cnab-go/credentials" 12 "github.com/docker/app/internal" 13 appstore "github.com/docker/app/internal/store" 14 "github.com/docker/cli/cli/command" 15 contextstore "github.com/docker/cli/cli/context/store" 16 "github.com/docker/distribution/reference" 17 "github.com/docker/docker/api/types" 18 "github.com/docker/docker/registry" 19 "github.com/pkg/errors" 20 ) 21 22 type credentialSetOpt func(b *bundle.Bundle, creds credentials.Set) error 23 24 func addNamedCredentialSets(credStore appstore.CredentialStore, namedCredentialsets []string) credentialSetOpt { 25 return func(_ *bundle.Bundle, creds credentials.Set) error { 26 for _, file := range namedCredentialsets { 27 var ( 28 c *credentials.CredentialSet 29 err error 30 ) 31 // Check the credentialset locally first, then try in the credential store 32 if _, e := os.Stat(file); e == nil { 33 c, err = credentials.Load(file) 34 } else { 35 c, err = credStore.Read(file) 36 if os.IsNotExist(err) { 37 err = e 38 } 39 } 40 if err != nil { 41 return err 42 } 43 values, err := c.Resolve() 44 if err != nil { 45 return err 46 } 47 if err := creds.Merge(values); err != nil { 48 return err 49 } 50 } 51 return nil 52 } 53 } 54 55 func parseCommandlineCredential(c string) (string, string, error) { 56 split := strings.SplitN(c, "=", 2) 57 if len(split) != 2 || split[0] == "" { 58 return "", "", errors.Errorf("failed to parse %q as a credential name=value", c) 59 } 60 name := split[0] 61 value := split[1] 62 return name, value, nil 63 } 64 65 func addCredentials(strcreds []string) credentialSetOpt { 66 return func(_ *bundle.Bundle, creds credentials.Set) error { 67 for _, c := range strcreds { 68 name, value, err := parseCommandlineCredential(c) 69 if err != nil { 70 return err 71 } 72 if err := creds.Merge(credentials.Set{ 73 name: value, 74 }); err != nil { 75 return err 76 } 77 } 78 return nil 79 } 80 } 81 82 func addDockerCredentials(contextName string, store contextstore.Store) credentialSetOpt { 83 // docker desktop contexts require some rewriting for being used within a container 84 store = internal.DockerDesktopAwareStore{Store: store} 85 return func(_ *bundle.Bundle, creds credentials.Set) error { 86 if contextName != "" { 87 data, err := ioutil.ReadAll(contextstore.Export(contextName, store)) 88 if err != nil { 89 return err 90 } 91 creds[internal.CredentialDockerContextName] = string(data) 92 } 93 return nil 94 } 95 } 96 97 func addRegistryCredentials(shouldPopulate bool, dockerCli command.Cli) credentialSetOpt { 98 return func(b *bundle.Bundle, creds credentials.Set) error { 99 if _, ok := b.Credentials[internal.CredentialRegistryName]; !ok { 100 return nil 101 } 102 103 registryCreds := map[string]types.AuthConfig{} 104 if shouldPopulate { 105 for _, img := range b.Images { 106 named, err := reference.ParseNormalizedNamed(img.Image) 107 if err != nil { 108 return err 109 } 110 info, err := registry.ParseRepositoryInfo(named) 111 if err != nil { 112 return err 113 } 114 key := registry.GetAuthConfigKey(info.Index) 115 if _, ok := registryCreds[key]; !ok { 116 registryCreds[key] = command.ResolveAuthConfig(context.Background(), dockerCli, info.Index) 117 } 118 } 119 } 120 registryCredsJSON, err := json.Marshal(registryCreds) 121 if err != nil { 122 return err 123 } 124 creds[internal.CredentialRegistryName] = string(registryCredsJSON) 125 return nil 126 } 127 } 128 129 func prepareCredentialSet(b *bundle.Bundle, opts ...credentialSetOpt) (map[string]string, error) { 130 creds := map[string]string{} 131 for _, op := range opts { 132 if err := op(b, creds); err != nil { 133 return nil, err 134 } 135 } 136 return creds, nil 137 }