Found core function who is responsible to read .env file and prepare mapping. Original function is splitting line to string slice base on = sign separator, which means:
example:
if I have in .env file values below:
HOST=test
SECRETKEY=YWRtaW50ZXN0Cg==
SECRETKEY will be invalid, because it contains = signs more than one time, what if end user want to have complex secrets containing = signs or want to encode in base64 which 99% cases contains = sign than all such values will be invalid:
My solution is replace
Original function:
func NewEnVarFromFile(envFile string) (*Envar, error) {
var outMap = make(map[string]string)
file := ToAbs(envFile)
data, err := ioutil.ReadFile(file)
// if it managed to find the env file load it
// otherwise skip it
content := strings.Split(string(data), "\n")
if err == nil {
for ix, line := range content {
// skips comments
if strings.HasPrefix(strings.Trim(line, " "), "#") ||
len(strings.Trim(line, " ")) == 0 ||
strings.HasPrefix(strings.Trim(line, " "), "\r") ||
strings.HasPrefix(strings.Trim(line, " "), "\n") {
continue
}
keyValue := strings.Split(line, "=")
if len(keyValue) != 2 {
return nil, fmt.Errorf("invalid env file format in line %d: '%s'\n", ix, line)
}
outMap[keyValue[0]] = removeTrail(keyValue[1])
}
} else {
Debug("cannot load env file: %s", err.Error())
}
return &Envar{
Vars: outMap,
}, nil
}
with modification below, which fixes that issues:
func NewEnVarFromFile(envFile string) (*Envar, error) {
var outMap = make(map[string]string)
file := ToAbs(envFile)
data, err := ioutil.ReadFile(file)
// if it managed to find the env file load it
// otherwise skip it
content := strings.Split(string(data), "\n")
if err == nil {
for ix, line := range content {
// skips comments
if strings.HasPrefix(strings.Trim(line, " "), "#") ||
len(strings.Trim(line, " ")) == 0 ||
strings.HasPrefix(strings.Trim(line, " "), "\r") ||
strings.HasPrefix(strings.Trim(line, " "), "\n") {
continue
}
//here ensuring that keyValue will be split on 2 strings
//example: Key=Keyvalue or Key=Keyvalue= or other case
//this is required because base64 values very often contains = signs, example: YWRtaW50ZXN0Cg==
keyValue := strings.SplitN(line, "=", 2)
//Checking if value doesn't have spaces, for example: Key=value123 val
//if contains such value is invalid
if strings.Contains(keyValue[1], " ") {
return nil, fmt.Errorf("invalid env file format in line %d: '%s'\n", ix, line)
}
outMap[keyValue[0]] = removeTrail(keyValue[1])
}
} else {
Debug("cannot load env file: %s", err.Error())
}
return &Envar{
Vars: outMap,
}, nil
}