feat: template parsing for env in password fields

This commit is contained in:
jamesread
2026-02-13 23:53:43 +00:00
parent 1248ee8765
commit 011ee866df
4 changed files with 38 additions and 29 deletions
+1 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)