Quellcode durchsuchen

feat: template parsing for env in password fields

jamesread vor 4 Monaten
Ursprung
Commit
011ee866df

+ 1 - 2
service/internal/config/config.go

@@ -171,8 +171,7 @@ type Config struct {
 	BannerCSS                       string                     `koanf:"bannerCss"`
 	Include                         string                     `koanf:"include"`
 
-	sourceFiles            []string
-	passwordTemplateParser func(string, interface{}) string
+	sourceFiles []string
 }
 
 type AuthLocalUsersConfig struct {

+ 18 - 13
service/internal/config/sanitize.go

@@ -2,7 +2,9 @@ package config
 
 import (
 	"strings"
+	"text/template"
 
+	"github.com/OliveTin/OliveTin/internal/env"
 	"github.com/google/uuid"
 	log "github.com/sirupsen/logrus"
 )
@@ -173,26 +175,29 @@ func (cfg *Config) sanitizeLogHistoryPageSize() {
 	}
 }
 
-// SetPasswordTemplateParser sets the function to use for parsing password templates.
-// This is called from main.go to avoid import cycles (config can't import entities).
-func (cfg *Config) SetPasswordTemplateParser(parser func(string, interface{}) string) {
-	cfg.passwordTemplateParser = parser
-}
-
 func (cfg *Config) sanitizeLocalUserPasswords() {
-	if cfg.passwordTemplateParser == nil {
-		return
-	}
-
 	for _, user := range cfg.AuthLocalUsers.Users {
 		if user.Password != "" {
-			// Parse password as template to support environment variables and other template values
-			// Note: .CurrentEntity is nil in this context as local users are not entity-bound
-			user.Password = cfg.passwordTemplateParser(user.Password, nil)
+			user.Password = parsePasswordTemplate(user.Password)
 		}
 	}
 }
 
+// parsePasswordTemplate expands {{ .Env.VAR }} in local user password fields using the process environment.
+func parsePasswordTemplate(source string) string {
+	t, err := template.New("password").Option("missingkey=error").Parse(source)
+	if err != nil {
+		log.WithFields(log.Fields{"error": err}).Debug("Password template parse failed, using literal")
+		return source
+	}
+	var b strings.Builder
+	if err := t.Execute(&b, map[string]interface{}{"Env": env.BuildEnvMap()}); err != nil {
+		log.WithFields(log.Fields{"error": err}).Debug("Password template execute failed, using literal")
+		return source
+	}
+	return b.String()
+}
+
 func getActionID(action *Action) string {
 	if action.ID == "" {
 		return uuid.NewString()

+ 17 - 0
service/internal/env/env.go

@@ -0,0 +1,17 @@
+package env
+
+import (
+	"os"
+	"strings"
+)
+
+func BuildEnvMap() map[string]string {
+	envMap := make(map[string]string)
+	for _, e := range os.Environ() {
+		parts := strings.SplitN(e, "=", 2)
+		if len(parts) == 2 {
+			envMap[parts[0]] = parts[1]
+		}
+	}
+	return envMap
+}

+ 2 - 14
service/internal/tpl/templates.go

@@ -2,12 +2,12 @@ package tpl
 
 import (
 	"fmt"
-	"os"
 	"regexp"
 	"strings"
 	"text/template"
 
 	"github.com/OliveTin/OliveTin/internal/entities"
+	"github.com/OliveTin/OliveTin/internal/env"
 	"github.com/OliveTin/OliveTin/internal/installationinfo"
 	log "github.com/sirupsen/logrus"
 )
@@ -49,7 +49,7 @@ func init() {
 		Runtime: installationinfo.Runtime,
 	}
 
-	cachedEnvMap = buildEnvMap()
+	cachedEnvMap = env.BuildEnvMap()
 }
 
 func GetNewGeneralTemplateContext() *generalTemplateContext {
@@ -59,18 +59,6 @@ func GetNewGeneralTemplateContext() *generalTemplateContext {
 	}
 }
 
-func buildEnvMap() map[string]string {
-	envMap := make(map[string]string)
-	for _, env := range os.Environ() {
-		parts := strings.SplitN(env, "=", 2)
-		if len(parts) == 2 {
-			envMap[parts[0]] = parts[1]
-		}
-	}
-
-	return envMap
-}
-
 func migrateLegacyEntityProperties(rawShellCommand string) string {
 	foundArgumentNames := legacyEntityPropertiesRegex.FindAllStringSubmatch(rawShellCommand, -1)