fix: segregate env setup

This commit is contained in:
Lakhan Samani
2022-02-26 09:44:55 +05:30
parent 332269ecf9
commit 4e19f73845
9 changed files with 478 additions and 84 deletions

205
server/env/env.go vendored
View File

@@ -1,22 +1,80 @@
package env
import (
"fmt"
"log"
"os"
"strings"
"github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/crypto"
"github.com/authorizerdev/authorizer/server/envstore"
"github.com/authorizerdev/authorizer/server/utils"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/joho/godotenv"
)
// InitRequiredEnv to initialize EnvData and through error if required env are not present
func InitRequiredEnv() {
envPath := os.Getenv(constants.EnvKeyEnvPath)
if envPath == "" {
envPath = `.env`
}
if envstore.ARG_ENV_FILE != nil && *envstore.ARG_ENV_FILE != "" {
envPath = *envstore.ARG_ENV_FILE
}
err := godotenv.Load(envPath)
if err != nil {
log.Printf("using OS env instead of %s file", envPath)
}
dbURL := os.Getenv(constants.EnvKeyDatabaseURL)
dbType := os.Getenv(constants.EnvKeyDatabaseType)
dbName := os.Getenv(constants.EnvKeyDatabaseName)
if dbType == "" {
if envstore.ARG_DB_TYPE != nil && *envstore.ARG_DB_TYPE != "" {
dbType = *envstore.ARG_DB_TYPE
}
if dbType == "" {
panic("DATABASE_TYPE is required")
}
}
if dbURL == "" {
if envstore.ARG_DB_URL != nil && *envstore.ARG_DB_URL != "" {
dbURL = *envstore.ARG_DB_URL
}
if dbURL == "" {
panic("DATABASE_URL is required")
}
}
if dbName == "" {
if dbName == "" {
dbName = "authorizer"
}
}
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEnvPath, envPath)
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseURL, dbURL)
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseType, dbType)
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyDatabaseName, dbName)
}
// InitEnv to initialize EnvData and through error if required env are not present
func InitEnv() {
// get clone of current store
envData := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
func InitAllEnv() {
envData, err := GetEnvData()
if err != nil {
log.Println("No env data found in db, using local clone of env data")
// get clone of current store
envData = envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
}
if envData.StringEnv[constants.EnvKeyEnv] == "" {
envData.StringEnv[constants.EnvKeyEnv] = os.Getenv(constants.EnvKeyEnv)
@@ -36,19 +94,6 @@ func InitEnv() {
envData.StringEnv[constants.EnvKeyAppURL] = os.Getenv(constants.EnvKeyAppURL)
}
if envData.StringEnv[constants.EnvKeyEnvPath] == "" {
envData.StringEnv[constants.EnvKeyEnvPath] = `.env`
}
if envstore.ARG_ENV_FILE != nil && *envstore.ARG_ENV_FILE != "" {
envData.StringEnv[constants.EnvKeyEnvPath] = *envstore.ARG_ENV_FILE
}
err := godotenv.Load(envData.StringEnv[constants.EnvKeyEnvPath])
if err != nil {
log.Printf("using OS env instead of %s file", envData.StringEnv[constants.EnvKeyEnvPath])
}
if envData.StringEnv[constants.EnvKeyPort] == "" {
envData.StringEnv[constants.EnvKeyPort] = os.Getenv(constants.EnvKeyPort)
if envData.StringEnv[constants.EnvKeyPort] == "" {
@@ -60,37 +105,6 @@ func InitEnv() {
envData.StringEnv[constants.EnvKeyAdminSecret] = os.Getenv(constants.EnvKeyAdminSecret)
}
if envData.StringEnv[constants.EnvKeyDatabaseType] == "" {
envData.StringEnv[constants.EnvKeyDatabaseType] = os.Getenv(constants.EnvKeyDatabaseType)
if envstore.ARG_DB_TYPE != nil && *envstore.ARG_DB_TYPE != "" {
envData.StringEnv[constants.EnvKeyDatabaseType] = *envstore.ARG_DB_TYPE
}
if envData.StringEnv[constants.EnvKeyDatabaseType] == "" {
panic("DATABASE_TYPE is required")
}
}
if envData.StringEnv[constants.EnvKeyDatabaseURL] == "" {
envData.StringEnv[constants.EnvKeyDatabaseURL] = os.Getenv(constants.EnvKeyDatabaseURL)
if envstore.ARG_DB_URL != nil && *envstore.ARG_DB_URL != "" {
envData.StringEnv[constants.EnvKeyDatabaseURL] = *envstore.ARG_DB_URL
}
if envData.StringEnv[constants.EnvKeyDatabaseURL] == "" {
panic("DATABASE_URL is required")
}
}
if envData.StringEnv[constants.EnvKeyDatabaseName] == "" {
envData.StringEnv[constants.EnvKeyDatabaseName] = os.Getenv(constants.EnvKeyDatabaseName)
if envData.StringEnv[constants.EnvKeyDatabaseName] == "" {
envData.StringEnv[constants.EnvKeyDatabaseName] = "authorizer"
}
}
if envData.StringEnv[constants.EnvKeySmtpHost] == "" {
envData.StringEnv[constants.EnvKeySmtpHost] = os.Getenv(constants.EnvKeySmtpHost)
}
@@ -111,32 +125,83 @@ func InitEnv() {
envData.StringEnv[constants.EnvKeySenderEmail] = os.Getenv(constants.EnvKeySenderEmail)
}
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret)
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
envData.StringEnv[constants.EnvKeyJwtSecret] = uuid.New().String()
}
}
if envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] == "" {
envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] = os.Getenv(constants.EnvKeyCustomAccessTokenScript)
}
if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" {
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = os.Getenv(constants.EnvKeyJwtPrivateKey)
}
if envData.StringEnv[constants.EnvKeyJwtPublicKey] == "" {
envData.StringEnv[constants.EnvKeyJwtPublicKey] = os.Getenv(constants.EnvKeyJwtPublicKey)
}
algo := ""
if envData.StringEnv[constants.EnvKeyJwtType] == "" {
envData.StringEnv[constants.EnvKeyJwtType] = os.Getenv(constants.EnvKeyJwtType)
if envData.StringEnv[constants.EnvKeyJwtType] == "" {
envData.StringEnv[constants.EnvKeyJwtType] = "HS256"
envData.StringEnv[constants.EnvKeyJwtType] = "RS256"
algo = envData.StringEnv[constants.EnvKeyJwtType]
} else {
algo = envData.StringEnv[constants.EnvKeyJwtType]
if !crypto.IsHMACA(algo) && !crypto.IsRSA(algo) && !crypto.IsECDSA(algo) {
panic("JWT_TYPE is invalid")
}
}
}
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" && crypto.IsHMACA(algo) {
envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret)
if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
envData.StringEnv[constants.EnvKeyJwtSecret] = crypto.NewHMACKey()
}
}
if crypto.IsRSA(algo) || crypto.IsECDSA(algo) {
privateKey, publicKey := "", ""
if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" {
privateKey = os.Getenv(constants.EnvKeyJwtPrivateKey)
}
if envData.StringEnv[constants.EnvKeyJwtPublicKey] == "" {
publicKey = os.Getenv(constants.EnvKeyJwtPublicKey)
}
// if algo is RSA / ECDSA, then we need to have both private and public key
// if either of them is not present generate new keys
if privateKey == "" || publicKey == "" {
if crypto.IsRSA(algo) {
_, privateKey, publicKey, err = crypto.NewRSAKey()
if err != nil {
panic(err)
}
} else if crypto.IsECDSA(algo) {
_, privateKey, publicKey, err = crypto.NewECDSAKey()
if err != nil {
panic(err)
}
}
} else {
// parse keys to make sure they are valid
if crypto.IsRSA(algo) {
_, err = crypto.ParseRsaPrivateKeyFromPemStr(privateKey)
if err != nil {
panic(err)
}
_, err = crypto.ParseRsaPublicKeyFromPemStr(publicKey)
if err != nil {
panic(err)
}
} else if crypto.IsECDSA(algo) {
_, err = crypto.ParseEcdsaPrivateKeyFromPemStr(privateKey)
if err != nil {
panic(err)
}
_, err = crypto.ParseEcdsaPublicKeyFromPemStr(publicKey)
if err != nil {
panic(err)
}
}
fmt.Println("=> keys parsed successfully")
}
fmt.Println(privateKey)
fmt.Println(publicKey)
envData.StringEnv[constants.EnvKeyJwtPrivateKey] = privateKey
envData.StringEnv[constants.EnvKeyJwtPublicKey] = publicKey
}
if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" {
envData.StringEnv[constants.EnvKeyJwtRoleClaim] = os.Getenv(constants.EnvKeyJwtRoleClaim)
@@ -145,6 +210,10 @@ func InitEnv() {
}
}
if envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] == "" {
envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] = os.Getenv(constants.EnvKeyCustomAccessTokenScript)
}
if envData.StringEnv[constants.EnvKeyRedisURL] == "" {
envData.StringEnv[constants.EnvKeyRedisURL] = os.Getenv(constants.EnvKeyRedisURL)
}

View File

@@ -15,6 +15,40 @@ import (
"github.com/google/uuid"
)
// GetEnvData returns the env data from database
func GetEnvData() (envstore.Store, error) {
var result envstore.Store
env, err := db.Provider.GetEnv()
// config not found in db
if err != nil {
return result, err
}
encryptionKey := env.Hash
decryptedEncryptionKey, err := utils.DecryptB64(encryptionKey)
if err != nil {
return result, err
}
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
b64DecryptedConfig, err := utils.DecryptB64(env.EnvData)
if err != nil {
return result, err
}
decryptedConfigs, err := utils.DecryptAES([]byte(b64DecryptedConfig))
if err != nil {
return result, err
}
err = json.Unmarshal(decryptedConfigs, &result)
if err != nil {
return result, err
}
return result, err
}
// PersistEnv persists the environment variables to the database
func PersistEnv() error {
env, err := db.Provider.GetEnv()
@@ -29,22 +63,16 @@ func PersistEnv() error {
if err != nil {
return err
}
// configData, err := json.Marshal()
// if err != nil {
// return err
// }
// encryptedConfig, err := utils.EncryptAES(configData)
// if err != nil {
// return err
// }
env = models.Env{
Hash: encodedHash,
EnvData: encryptedConfig,
}
db.Provider.AddEnv(env)
env, err = db.Provider.AddEnv(env)
if err != nil {
return err
}
} else {
// decrypt the config data from db
// decryption can be done using the hash stored in db
@@ -134,6 +162,7 @@ func PersistEnv() error {
}
envstore.EnvInMemoryStoreObj.UpdateEnvStore(storeData)
if hasChanged {
encryptedConfig, err := utils.EncryptEnvData(storeData)
if err != nil {
@@ -147,8 +176,11 @@ func PersistEnv() error {
return err
}
}
}
// ID of env is used to identify the config and declared as client id
// this client id can be used in `aud` section of JWT token
envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyClientID, env.ID)
return nil
}