package nativeapi
import (
"context"
"encoding/json"
"fmt"
"net/http"
"slices"
"strings"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/log"
)
var sensitiveFieldsPartialMask = []string{
"LastFM.ApiKey",
"LastFM.Secret",
"Prometheus.MetricsPath",
"DevAutoLoginUsername",
}
var sensitiveFieldsFullMask = []string{
"DevAutoCreateAdminPassword",
"PasswordEncryptionKey",
"Prometheus.Password",
}
type configResponse struct {
ID string `json:"id"`
ConfigFile string `json:"configFile"`
Config map[string]any `json:"config"`
}
func redactValue(key string, value string) string {
if len(value) == 0 {
return value
}
if slices.Contains(sensitiveFieldsFullMask, key) {
return "****"
}
for _, field := range sensitiveFieldsPartialMask {
if field == key {
if len(value) < 7 {
return "****"
}
return string(value[0]) + strings.Repeat("*", len(value)-2) + string(value[len(value)-1])
}
}
return value
}
func applySensitiveFieldMasking(ctx context.Context, config map[string]any, prefix string) {
for key, value := range config {
fullKey := key
if prefix != "" {
fullKey = prefix + "." + key
}
switch v := value.(type) {
case map[string]any:
applySensitiveFieldMasking(ctx, v, fullKey)
case string:
config[key] = redactValue(fullKey, v)
default:
if str := fmt.Sprint(v); str != "" {
masked := redactValue(fullKey, str)
if masked != str {
config[key] = masked
}
}
}
}
}
func getConfig(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
configBytes, err := json.Marshal(conf.Server)
if err != nil {
log.Error(ctx, "Error marshaling config", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
var configMap map[string]any
err = json.Unmarshal(configBytes, &configMap)
if err != nil {
log.Error(ctx, "Error unmarshaling config to map", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
applySensitiveFieldMasking(ctx, configMap, "")
resp := configResponse{
ID: "config",
ConfigFile: conf.Server.ConfigFile,
Config: configMap,
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
log.Error(ctx, "Error encoding config response", err)
}
}