Files
filestash/server/common/config_state.go
MickaelK 5e420cf5f3 fix (config): save config when disk is full
before this, if the user had a full disk, there wouldn't be any error
reported back whenever editing something in the admin
console as file.Close() would return nil ....

The only way to go around it is to wait for the sync to be done.
2024-11-28 02:03:35 +11:00

117 lines
3.4 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/ioutil"
"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 := ioutil.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()
}