package common /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNI * WARNING - CHANGE IN THIS FILE CAN SILENTLY BREAK OTHER INSTALLATION - WARNING * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARN * * Some contributors wanted to be able to load and persist config in other system * like S3 and provide custom encryption layer on top of it. Those contributors have * custom plugins which run generators that override this file before the build is * generated. Indeed for that specific use case we couldn't extend the runtime plugin * mechanism so had to fallback to this approach which would set the config loader at * build time, hence this warning. */ import ( "fmt" "github.com/tidwall/gjson" "github.com/tidwall/sjson" "io" "os" ) var ( configKeysToEncrypt []string = []string{ "middleware.identity_provider.params", "middleware.attribute_mapping.params", } config_path func() string ) func init() { config_path = func() string { return GetAbsolutePath(CONFIG_PATH, "config.json") } } func LoadConfig() ([]byte, error) { file, err := os.OpenFile(config_path(), os.O_RDONLY, os.ModePerm) if err != nil { if os.IsNotExist(err) { os.MkdirAll(GetAbsolutePath(CONFIG_PATH), os.ModePerm) return []byte(""), nil } return nil, err } cFile, err := io.ReadAll(file) file.Close() if err != nil { return nil, err } configStr := string(cFile) for _, jsonPathWithEncryptedData := range configKeysToEncrypt { p := gjson.Get(configStr, jsonPathWithEncryptedData).String() if p == "" { continue } key := os.Getenv("CONFIG_SECRET") if key == "" { InitSecretDerivate(gjson.Get(configStr, "general.secret_key").String()) key = SECRET_KEY_DERIVATE_FOR_PROOF } t, err := DecryptString(Hash(key, 16), p) if err != nil { Log.Warning("common::config_state::load cannot decrypt config path '%s': %s", jsonPathWithEncryptedData, err.Error()) continue } val, err := sjson.Set(configStr, jsonPathWithEncryptedData, t) if err != nil { Log.Warning("common::config_state::load cannot put json value in config '%s': %s", jsonPathWithEncryptedData, err.Error()) continue } configStr = val } return []byte(configStr), nil } func SaveConfig(v []byte) error { file, err := os.Create(config_path()) if err != nil { return fmt.Errorf( "Filestash needs to be able to create/edit its own configuration which it can't at the moment. "+ "Change the permission for filestash to create and edit `%s`", config_path(), ) } configStr := string(v) for _, jsonPathWithEncryptedData := range configKeysToEncrypt { key := os.Getenv("CONFIG_SECRET") if key == "" { key = SECRET_KEY_DERIVATE_FOR_PROOF } p := gjson.Get(configStr, jsonPathWithEncryptedData).String() if p == "" { continue } t, err := EncryptString(Hash(key, 16), p) if err != nil { Log.Warning("common::config_state::save cannot encrypt config path '%s': %s", jsonPathWithEncryptedData, err.Error()) continue } val, err := sjson.Set(configStr, jsonPathWithEncryptedData, t) if err != nil { Log.Warning("common::config_state::save cannot put json value in config '%s': %s", jsonPathWithEncryptedData, err.Error()) continue } configStr = val } file.Write(PrettyPrint([]byte(configStr))) if err = file.Sync(); err != nil { file.Close() return err } return file.Close() }