- refactor secrets

- add support for env in config
- redact sensitive information in logs/responses
This commit is contained in:
seydx
2025-05-26 21:56:45 +02:00
parent e8e798d955
commit bf45f64a7e
14 changed files with 202 additions and 160 deletions
+6
View File
@@ -6,6 +6,8 @@ import (
"strconv"
"strings"
"time"
"github.com/AlexxIT/go2rtc/internal/app"
)
const (
@@ -77,3 +79,7 @@ func Caller() string {
_, file, line, _ := runtime.Caller(1)
return file + ":" + strconv.Itoa(line)
}
func NewSecret(name string, defaultValues interface{}) (*app.Secret, error) {
return app.NewSecret(name, defaultValues)
}
-6
View File
@@ -1,7 +1,5 @@
package core
import "github.com/AlexxIT/go2rtc/internal/app"
type EventFunc func(msg any)
// Listener base struct for all classes with support feedback
@@ -18,7 +16,3 @@ func (l *Listener) Fire(msg any) {
f(msg)
}
}
func (l *Listener) NewSecret(name string, defaultValues interface{}) *app.Secret {
return app.NewSecret(name, defaultValues)
}
+117
View File
@@ -1,12 +1,22 @@
package shell
import (
"fmt"
"os"
"os/signal"
"path/filepath"
"regexp"
"strings"
"sync"
"syscall"
"github.com/AlexxIT/go2rtc/pkg/yaml"
)
var (
secretReplacer *strings.Replacer
secretValues map[string]bool // Tracker für alle bekannten Secret-Werte
secretMutex sync.RWMutex
)
func QuoteSplit(s string) []string {
@@ -40,6 +50,15 @@ func QuoteSplit(s string) []string {
// ReplaceEnvVars - support format ${CAMERA_PASSWORD} and ${RTSP_USER:admin}
func ReplaceEnvVars(text string) string {
var cfg struct {
Env map[string]string `yaml:"env"`
Secrets map[string]map[string]string `yaml:"secrets"`
}
yaml.Unmarshal([]byte(text), &cfg)
buildSecretReplacer(cfg)
re := regexp.MustCompile(`\${([^}{]+)}`)
return re.ReplaceAllStringFunc(text, func(match string) string {
key := match[2 : len(match)-1]
@@ -63,6 +82,23 @@ func ReplaceEnvVars(text string) string {
return value
}
if cfg.Env != nil {
if value, ok := cfg.Env[key]; ok {
return value
}
}
if cfg.Secrets != nil {
for secretName, secretValues := range cfg.Secrets {
for k, v := range secretValues {
name := fmt.Sprintf("%s_%s", secretName, k)
if key == name {
return v
}
}
}
}
if dok {
return def
}
@@ -76,3 +112,84 @@ func RunUntilSignal() {
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
println("exit with signal:", (<-sigs).String())
}
func Redact(text string) string {
secretMutex.RLock()
defer secretMutex.RUnlock()
if secretReplacer == nil {
return text
}
return secretReplacer.Replace(text)
}
func buildSecretReplacer(cfg struct {
Env map[string]string `yaml:"env"`
Secrets map[string]map[string]string `yaml:"secrets"`
}) {
secretMutex.Lock()
defer secretMutex.Unlock()
if secretValues == nil {
secretValues = make(map[string]bool)
}
var newSecrets []string
if dir, ok := os.LookupEnv("CREDENTIALS_DIRECTORY"); ok {
entries, err := os.ReadDir(dir)
if err == nil {
for _, entry := range entries {
if !entry.IsDir() {
value, err := os.ReadFile(filepath.Join(dir, entry.Name()))
if err == nil {
cleanValue := strings.TrimSpace(string(value))
if len(cleanValue) > 0 && !secretValues[cleanValue] {
secretValues[cleanValue] = true
newSecrets = append(newSecrets, cleanValue)
}
}
}
}
}
}
if cfg.Env != nil {
for _, value := range cfg.Env {
if len(value) > 0 && !secretValues[value] {
secretValues[value] = true
newSecrets = append(newSecrets, value)
}
}
}
if cfg.Secrets != nil {
for _, secretMap := range cfg.Secrets {
for _, value := range secretMap {
if len(value) > 0 && !secretValues[value] {
secretValues[value] = true
newSecrets = append(newSecrets, value)
}
}
}
}
if len(newSecrets) > 0 {
rebuildReplacer()
}
}
func rebuildReplacer() {
var replacements []string
for secret := range secretValues {
replacements = append(replacements, secret, "*****")
}
if len(replacements) > 0 {
secretReplacer = strings.NewReplacer(replacements...)
} else {
secretReplacer = nil
}
}