package secret import ( "bufio" "io" "os" "strings" "syscall" ) type environment map[string][]byte // Environment provides environment variables as secrets. func Environment() Provider { return EnvironmentPrefix("") } // EnvironmentPrefix provides environment variables with a prefix as secrets. // // The prefix is stripped from the final secret key name. func EnvironmentPrefix(prefix string) Provider { env := make(environment) for _, line := range syscall.Environ() { if !strings.HasPrefix(line, prefix) { continue } kv := strings.SplitN(line[len(prefix):], "=", 2) if len(kv) == 2 { env[kv[0]] = []byte(strings.TrimSpace(kv[1])) } } return env } // EnvironmentFile reads a file containing key-value pairs. // // Line starting with `#` or `//` are ignored. // // Example: // // key=value // # This comment is ignored func EnvironmentFile(name string) (Provider, error) { f, err := os.Open(name) if err != nil { return nil, err } defer func() { _ = f.Close() }() return EnvironmentReader(f) } // EnvironmentReader reads key-value pairs separated by newlines. // // Line starting with `#` or `//` are ignored. // // Example: // // key=value // # This comment is ignored func EnvironmentReader(r io.Reader) (Provider, error) { s := bufio.NewScanner(r) s.Split(bufio.ScanLines) env := make(environment) for s.Scan() { if err := s.Err(); err != nil { if err == io.EOF { break } return nil, err } line := strings.TrimSpace(s.Text()) if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "//") { continue } kv := strings.SplitN(line, "=", 2) if len(kv) == 2 { env[strings.TrimSpace(kv[0])] = []byte(strings.TrimSpace(kv[1])) } } return env, nil } func (env environment) GetSecret(key string) (value []byte, err error) { var ok bool if value, ok = env[key]; ok { return } return nil, NotFound{key} }