github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/cli/config/configfile/file.go (about) 1 package configfile 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 13 "github.com/docker/docker/api/types" 14 ) 15 16 const ( 17 // This constant is only used for really old config files when the 18 // URL wasn't saved as part of the config file and it was just 19 // assumed to be this value. 20 defaultIndexserver = "https://index.docker.io/v1/" 21 ) 22 23 // ConfigFile ~/.docker/config.json file info 24 type ConfigFile struct { 25 AuthConfigs map[string]types.AuthConfig `json:"auths"` 26 HTTPHeaders map[string]string `json:"HttpHeaders,omitempty"` 27 PsFormat string `json:"psFormat,omitempty"` 28 ImagesFormat string `json:"imagesFormat,omitempty"` 29 NetworksFormat string `json:"networksFormat,omitempty"` 30 PluginsFormat string `json:"pluginsFormat,omitempty"` 31 VolumesFormat string `json:"volumesFormat,omitempty"` 32 StatsFormat string `json:"statsFormat,omitempty"` 33 DetachKeys string `json:"detachKeys,omitempty"` 34 CredentialsStore string `json:"credsStore,omitempty"` 35 CredentialHelpers map[string]string `json:"credHelpers,omitempty"` 36 Filename string `json:"-"` // Note: for internal use only 37 ServiceInspectFormat string `json:"serviceInspectFormat,omitempty"` 38 ServicesFormat string `json:"servicesFormat,omitempty"` 39 TasksFormat string `json:"tasksFormat,omitempty"` 40 } 41 42 // LegacyLoadFromReader reads the non-nested configuration data given and sets up the 43 // auth config information with given directory and populates the receiver object 44 func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error { 45 b, err := ioutil.ReadAll(configData) 46 if err != nil { 47 return err 48 } 49 50 if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil { 51 arr := strings.Split(string(b), "\n") 52 if len(arr) < 2 { 53 return fmt.Errorf("The Auth config file is empty") 54 } 55 authConfig := types.AuthConfig{} 56 origAuth := strings.Split(arr[0], " = ") 57 if len(origAuth) != 2 { 58 return fmt.Errorf("Invalid Auth config file") 59 } 60 authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1]) 61 if err != nil { 62 return err 63 } 64 authConfig.ServerAddress = defaultIndexserver 65 configFile.AuthConfigs[defaultIndexserver] = authConfig 66 } else { 67 for k, authConfig := range configFile.AuthConfigs { 68 authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth) 69 if err != nil { 70 return err 71 } 72 authConfig.Auth = "" 73 authConfig.ServerAddress = k 74 configFile.AuthConfigs[k] = authConfig 75 } 76 } 77 return nil 78 } 79 80 // LoadFromReader reads the configuration data given and sets up the auth config 81 // information with given directory and populates the receiver object 82 func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error { 83 if err := json.NewDecoder(configData).Decode(&configFile); err != nil { 84 return err 85 } 86 var err error 87 for addr, ac := range configFile.AuthConfigs { 88 ac.Username, ac.Password, err = decodeAuth(ac.Auth) 89 if err != nil { 90 return err 91 } 92 ac.Auth = "" 93 ac.ServerAddress = addr 94 configFile.AuthConfigs[addr] = ac 95 } 96 return nil 97 } 98 99 // ContainsAuth returns whether there is authentication configured 100 // in this file or not. 101 func (configFile *ConfigFile) ContainsAuth() bool { 102 return configFile.CredentialsStore != "" || 103 len(configFile.CredentialHelpers) > 0 || 104 len(configFile.AuthConfigs) > 0 105 } 106 107 // SaveToWriter encodes and writes out all the authorization information to 108 // the given writer 109 func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error { 110 // Encode sensitive data into a new/temp struct 111 tmpAuthConfigs := make(map[string]types.AuthConfig, len(configFile.AuthConfigs)) 112 for k, authConfig := range configFile.AuthConfigs { 113 authCopy := authConfig 114 // encode and save the authstring, while blanking out the original fields 115 authCopy.Auth = encodeAuth(&authCopy) 116 authCopy.Username = "" 117 authCopy.Password = "" 118 authCopy.ServerAddress = "" 119 tmpAuthConfigs[k] = authCopy 120 } 121 122 saveAuthConfigs := configFile.AuthConfigs 123 configFile.AuthConfigs = tmpAuthConfigs 124 defer func() { configFile.AuthConfigs = saveAuthConfigs }() 125 126 data, err := json.MarshalIndent(configFile, "", "\t") 127 if err != nil { 128 return err 129 } 130 _, err = writer.Write(data) 131 return err 132 } 133 134 // Save encodes and writes out all the authorization information 135 func (configFile *ConfigFile) Save() error { 136 if configFile.Filename == "" { 137 return fmt.Errorf("Can't save config with empty filename") 138 } 139 140 if err := os.MkdirAll(filepath.Dir(configFile.Filename), 0700); err != nil { 141 return err 142 } 143 f, err := os.OpenFile(configFile.Filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) 144 if err != nil { 145 return err 146 } 147 defer f.Close() 148 return configFile.SaveToWriter(f) 149 } 150 151 // encodeAuth creates a base64 encoded string to containing authorization information 152 func encodeAuth(authConfig *types.AuthConfig) string { 153 if authConfig.Username == "" && authConfig.Password == "" { 154 return "" 155 } 156 157 authStr := authConfig.Username + ":" + authConfig.Password 158 msg := []byte(authStr) 159 encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg))) 160 base64.StdEncoding.Encode(encoded, msg) 161 return string(encoded) 162 } 163 164 // decodeAuth decodes a base64 encoded string and returns username and password 165 func decodeAuth(authStr string) (string, string, error) { 166 if authStr == "" { 167 return "", "", nil 168 } 169 170 decLen := base64.StdEncoding.DecodedLen(len(authStr)) 171 decoded := make([]byte, decLen) 172 authByte := []byte(authStr) 173 n, err := base64.StdEncoding.Decode(decoded, authByte) 174 if err != nil { 175 return "", "", err 176 } 177 if n > decLen { 178 return "", "", fmt.Errorf("Something went wrong decoding auth config") 179 } 180 arr := strings.SplitN(string(decoded), ":", 2) 181 if len(arr) != 2 { 182 return "", "", fmt.Errorf("Invalid auth configuration file") 183 } 184 password := strings.Trim(arr[1], "\x00") 185 return arr[0], password, nil 186 }