fix(config): redact MasterKey type; drop os.Clearenv; add hex validation test

This commit is contained in:
2026-04-28 13:44:06 +08:00
parent 26d6c72c33
commit baf296abfb
2 changed files with 40 additions and 4 deletions
+19 -2
View File
@@ -4,16 +4,33 @@ package config
import (
"encoding/hex"
"fmt"
"log/slog"
"strings"
"github.com/spf13/viper"
)
// MasterKey wraps a 32-byte AES master key with redacted formatting to prevent
// accidental log/fmt exposure.
type MasterKey []byte
// String redacts when used with %s / fmt.Println.
func (k MasterKey) String() string { return "[REDACTED 32B]" }
// GoString redacts when used with %#v.
func (k MasterKey) GoString() string { return "[REDACTED 32B]" }
// MarshalJSON redacts when serialized to JSON.
func (k MasterKey) MarshalJSON() ([]byte, error) { return []byte(`"[REDACTED]"`), nil }
// LogValue redacts when logged via slog.
func (k MasterKey) LogValue() slog.Value { return slog.StringValue("[REDACTED 32B]") }
// Config 是应用全局配置的根结构。
type Config struct {
Env string `mapstructure:"env"`
DataDir string `mapstructure:"data_dir"`
MasterKey []byte // 解码后的 32 字节
MasterKey MasterKey `mapstructure:"-"` // 解码后的 32 字节,单独从 master_key 解析
HTTP HTTPConfig `mapstructure:"http"`
DB DBConfig `mapstructure:"db"`
Bootstrap BootstrapConfig `mapstructure:"bootstrap"`
@@ -86,7 +103,7 @@ func Load(configFile string) (*Config, error) {
if len(key) != 32 {
return nil, fmt.Errorf("APP_MASTER_KEY must be 32 bytes (got %d)", len(key))
}
cfg.MasterKey = key
cfg.MasterKey = MasterKey(key)
if cfg.DB.DSN == "" {
return nil, fmt.Errorf("APP_DB_DSN required")