Files
filestash/server/common/config_state.go

117 lines
3.3 KiB
Go

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()
}