evcc-io/util/redact/redactor.go

64 lines
1.5 KiB
Go

package redact
import (
"fmt"
"maps"
"regexp"
"slices"
"strings"
"github.com/evcc-io/evcc/util/templates"
"github.com/samber/lo"
)
var (
configRedactRegex *regexp.Regexp
configRedactSecrets []string
)
func init() {
// fields that are not covered by template params (yet)
additional := []string{
"sponsortoken", "plant", // global settings
"app", "chats", "recipients", // push messaging
}
// Combine generated params with additional fields
configRedactSecrets = slices.Concat(redactableParams(), additional)
configRedactRegex = regexp.MustCompile(fmt.Sprintf(`(?i)\b(%s)\b.*?:.*`, strings.Join(configRedactSecrets, "|")))
}
func redactableParams() []string {
// Collect all sensitive params from templates (includes defaults)
var params []string
for _, class := range templates.ClassValues() {
for _, tmpl := range templates.ByClass(class) {
for _, p := range tmpl.Params {
if p.IsMasked() || p.IsPrivate() {
params = append(params, strings.ToLower(p.Name))
}
}
}
}
return lo.Uniq(params)
}
// String redacts a configuration string by replacing sensitive values with *****
func String(src string) string {
return configRedactRegex.ReplaceAllString(src, "$1: *****")
}
// Map redacts sensitive keys in a configuration map
func Map(src map[string]any) map[string]any {
res := maps.Clone(src)
for k := range res {
if slices.ContainsFunc(configRedactSecrets, func(s string) bool {
return strings.EqualFold(k, s)
}) {
res[k] = "*****"
}
}
return res
}