diff --git a/internal/app/config.go b/internal/app/config.go index 16cf53b5..9d4480b7 100644 --- a/internal/app/config.go +++ b/internal/app/config.go @@ -18,14 +18,6 @@ func LoadConfig(v any) { } } -func LoadSecret(v any) { - for _, data := range secrets { - if err := yaml.Unmarshal(data, v); err != nil { - Logger.Warn().Err(err).Send() - } - } -} - func PatchConfig(path []string, value any) error { if ConfigPath == "" { return errors.New("config file disabled") @@ -42,27 +34,6 @@ func PatchConfig(path []string, value any) error { return os.WriteFile(ConfigPath, b, 0644) } -func PatchSecret(path []string, value any) error { - if SecretPath == "" { - return errors.New("secret file disabled") - } - - // empty config is OK - b, _ := os.ReadFile(SecretPath) - - b, err := yaml.Patch(b, path, value) - if err != nil { - return err - } - - if err := os.WriteFile(SecretPath, b, 0644); err == nil { - secrets = [][]byte{b} - } - - return err -} - - type flagConfig []string func (c *flagConfig) String() string { @@ -75,7 +46,6 @@ func (c *flagConfig) Set(value string) error { } var configs [][]byte -var secrets [][]byte func initConfig(confs flagConfig) { if confs == nil { @@ -116,23 +86,6 @@ func initConfig(confs flagConfig) { } } -func initSecret(secret string) { - if secret == "" { - secret = "go2rtc.secrets" - } - - SecretPath = secret - - if SecretPath != "" { - if !filepath.IsAbs(SecretPath) { - if cwd, err := os.Getwd(); err == nil { - SecretPath = filepath.Join(cwd, SecretPath) - } - } - Info["secret_path"] = SecretPath - } -} - func parseConfString(s string) []byte { i := strings.IndexByte(s, '=') if i < 0 { diff --git a/internal/app/secrets.go b/internal/app/secrets.go new file mode 100644 index 00000000..12fce1ef --- /dev/null +++ b/internal/app/secrets.go @@ -0,0 +1,129 @@ +package app + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/AlexxIT/go2rtc/pkg/yaml" +) + +var secrets [][]byte + +var templateRegex = regexp.MustCompile(`\{\{\s*([^\}]+)\s*\}\}`) + +func ResolveSecrets(template string) string { + if !templateRegex.MatchString(template) { + return template + } + + var secretsMap map[string]interface{} + LoadSecret(&secretsMap) + + // ex template: rtsp://{{ my_camera.username }}:{{ my_camera.password }}@192.168.178.1:554/stream + result := templateRegex.ReplaceAllStringFunc(template, func(match string) string { + varName := strings.TrimSpace(templateRegex.FindStringSubmatch(match)[1]) + pathParts := strings.Split(varName, ".") + value := getNestedValue(secretsMap, pathParts) + + if value != nil { + return stringify(value) + } + + return "" + }) + + return result +} + +func LoadSecret(v any) { + for _, data := range secrets { + if err := yaml.Unmarshal(data, v); err != nil { + Logger.Warn().Err(err).Send() + } + } +} + +func PatchSecret(path []string, value any) error { + if SecretPath == "" { + return errors.New("secret file disabled") + } + + // empty config is OK + b, _ := os.ReadFile(SecretPath) + + b, err := yaml.Patch(b, path, value) + if err != nil { + return err + } + + if err := os.WriteFile(SecretPath, b, 0644); err == nil { + secrets = [][]byte{b} + } + + return err +} + +func initSecret(secret string) { + if secret == "" { + secret = "go2rtc.secrets" + } + + SecretPath = secret + + if SecretPath != "" { + if !filepath.IsAbs(SecretPath) { + if cwd, err := os.Getwd(); err == nil { + SecretPath = filepath.Join(cwd, SecretPath) + } + } + Info["secret_path"] = SecretPath + } +} + +func getNestedValue(m map[string]interface{}, path []string) interface{} { + if len(path) == 0 || m == nil { + return nil + } + + key := path[0] + value, exists := m[key] + if !exists { + return nil + } + + if len(path) == 1 { + return value + } + + // Für verschachtelte Maps + switch nextMap := value.(type) { + case map[string]interface{}: + return getNestedValue(nextMap, path[1:]) + case map[interface{}]interface{}: + // Konvertiere map[interface{}]interface{} zu map[string]interface{} + stringMap := make(map[string]interface{}) + for k, v := range nextMap { + if keyStr, ok := k.(string); ok { + stringMap[keyStr] = v + } + } + return getNestedValue(stringMap, path[1:]) + default: + return nil + } +} + +func stringify(value interface{}) string { + switch v := value.(type) { + case string: + return v + case int, int64, float64, bool: + return fmt.Sprintf("%v", v) + default: + return "" + } +} \ No newline at end of file diff --git a/internal/streams/handlers.go b/internal/streams/handlers.go index 3240abb5..bd394fc8 100644 --- a/internal/streams/handlers.go +++ b/internal/streams/handlers.go @@ -4,6 +4,7 @@ import ( "errors" "strings" + "github.com/AlexxIT/go2rtc/internal/app" "github.com/AlexxIT/go2rtc/pkg/core" ) @@ -46,7 +47,8 @@ func GetProducer(url string) (core.Producer, error) { } if handler, ok := handlers[scheme]; ok { - return handler(url) + parsedURL := ParseURL(url) + return handler(parsedURL) } } @@ -95,3 +97,7 @@ func GetConsumer(url string) (core.Consumer, func(), error) { return nil, nil, errors.New("streams: unsupported scheme: " + url) } + +func ParseURL(url string) string { + return app.ResolveSecrets(url) +} \ No newline at end of file