module Core.Configuration ( adminEmail, appPort , confLinkLength, dataPath, dbPath , encKey, getRuntimeEnvironment , keyFileInit, main) where import qualified Data.ByteString as B import Control.Monad (mapM) import Core.Types import Crypto.Saltine.Core.SecretBox (newKey) import Crypto.Saltine.Class (encode) import Configuration.Dotenv import System.Directory (doesFileExist) import System.Environment (getEnv, lookupEnv) -- Load environment variables from dotenv file if required main :: IO () main = do reqEnvLookup <- getRequiredEnv if (Nothing `elem` reqEnvLookup) then checkEnvFile requiredEnvVars else pure () where getRequiredEnv :: IO [Maybe String] getRequiredEnv = mapM (\s -> lookupEnv s) requiredEnvVars checkEnvFile :: [String] -> IO () checkEnvFile requiredEnv = do dotEnvExists <- doesFileExist "./.env" if dotEnvExists then do loadFile defaultConfig fromEnvFile <- getRequiredEnv if (Nothing `elem` fromEnvFile) then error $ missingEnvMsg requiredEnv else pure () else error $ "Cannot find .env file in application directory.\n" ++ missingEnvMsg requiredEnv missingEnvMsg :: [String] -> String missingEnvMsg required = "Missing required environment variable(s).\n" ++ "All required environment variables:\n" ++ unlines required -- Check if an encryption key exists on the filesystem and create one if not keyFileInit :: IO () keyFileInit = do dataPathStr <- dataPath keyExists <- doesFileExist $ dataPathStr ++ "data/encryptionKey" case keyExists of True -> putStrLn "Using existing key" False -> do key <- newKey B.writeFile (dataPathStr ++ "data/encryptionKey") (encode key) putStrLn "Creating new encryption key; any pre-existing DB entries will not decrypt" -- Read and return the encryption key on the filesystem as a ByteString encKey :: IO B.ByteString encKey = do dataPathStr <- dataPath B.readFile (dataPathStr ++ "data/encryptionKey") -- Helper functions for getting the value of environment variables adminEmail :: IO String adminEmail = getEnv "ADMINEMAIL" getRuntimeEnvironment :: IO String getRuntimeEnvironment = getEnv "ENVIRONMENT" appPort :: IO String appPort = getEnv "APPLICATIONPORT" dataPath :: IO String dataPath = getEnv "DATADIR" dbPath :: String dbPath = "data/Purr.sqlite" confLinkLength :: IO String confLinkLength = getEnv "LINKLENGTH" requiredEnvVars :: [String] requiredEnvVars = [ "ADMINEMAIL", "APPLICATIONHOST", "APPLICATIONPORT" , "DATADIR", "ENVIRONMENT", "LINKLENGTH" ]