authorizer/server/env/persist_env.go
2021-12-31 13:52:10 +05:30

156 lines
3.7 KiB
Go

package env
import (
"encoding/json"
"log"
"os"
"reflect"
"strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/db"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/google/uuid"
)
func PersistEnv() error {
config, err := db.Mgr.GetConfig()
// config not found in db
if err != nil {
// AES encryption needs 32 bit key only, so we chop off last 4 characters from 36 bit uuid
hash := uuid.New().String()[:36-4]
constants.EnvData.ENCRYPTION_KEY = hash
encodedHash := utils.EncryptB64(hash)
configData, err := json.Marshal(constants.EnvData)
if err != nil {
return err
}
encryptedConfig, err := utils.EncryptAES(configData)
if err != nil {
return err
}
config = db.Config{
Hash: encodedHash,
Config: encryptedConfig,
}
db.Mgr.AddConfig(config)
} else {
// decrypt the config data from db
// decryption can be done using the hash stored in db
encryptionKey := config.Hash
decryptedEncryptionKey, err := utils.DecryptB64(encryptionKey)
if err != nil {
return err
}
constants.EnvData.ENCRYPTION_KEY = decryptedEncryptionKey
decryptedConfigs, err := utils.DecryptAES(config.Config)
if err != nil {
return err
}
// temp json to validate with env
var jsonData map[string]interface{}
err = json.Unmarshal(decryptedConfigs, &jsonData)
if err != nil {
return err
}
log.Println("=> persisted data:", jsonData)
// if env is changed via env file or OS env
// give that higher preference and update db, but we don't recommend it
hasChanged := false
for key, value := range jsonData {
fieldType := reflect.TypeOf(value).String()
// check only for derivative keys
// No need to check for ENCRYPTION_KEY which special key we use for encrypting config data
// as we have removed it from json
envValue := strings.TrimSpace(os.Getenv(key))
// env is not empty
if envValue != "" {
// check the type
// currently we have 3 types of env vars: string, bool, []string{}
if fieldType == "string" {
if value != envValue {
jsonData[key] = envValue
hasChanged = true
}
}
if fieldType == "bool" {
newValue := envValue == "true"
if value != newValue {
jsonData[key] = newValue
hasChanged = true
}
}
if fieldType == "[]interface {}" {
stringArr := []string{}
envStringArr := strings.Split(envValue, ",")
for _, v := range value.([]interface{}) {
stringArr = append(stringArr, v.(string))
}
if !utils.IsStringArrayEqual(stringArr, envStringArr) {
jsonData[key] = envStringArr
}
}
}
}
// handle derivative cases like disabling email verification & magic login
// in case SMTP is off but env is set to true
if jsonData["SMTP_HOST"] == "" || jsonData["SENDER_EMAIL"] == "" || jsonData["SENDER_PASSWORD"] == "" {
if !jsonData["DISABLE_EMAIL_VERIFICATION"].(bool) {
jsonData["DISABLE_EMAIL_VERIFICATION"] = true
hasChanged = true
}
if !jsonData["DISABLE_MAGIC_LINK_LOGIN"].(bool) {
jsonData["DISABLE_MAGIC_LINK_LOGIN"] = true
hasChanged = true
}
}
log.Println("has changed:", hasChanged)
if hasChanged {
jsonBytes, err := json.Marshal(jsonData)
if err != nil {
return err
}
err = json.Unmarshal(jsonBytes, &constants.EnvData)
if err != nil {
return err
}
}
configData, err := json.Marshal(constants.EnvData)
if err != nil {
return err
}
encryptedConfig, err := utils.EncryptAES(configData)
if err != nil {
return err
}
config.Config = encryptedConfig
_, err = db.Mgr.UpdateConfig(config)
if err != nil {
log.Println("error updating config:", err)
return err
}
}
return nil
}