module Env where
import Control.Monad.IO.Class
import Control.Monad.Trans.Except
import Data.Aeson
import Data.Aeson.Key qualified as Aeson
import Data.Aeson.KeyMap qualified as Aeson
import Data.Maybe
import Data.Set qualified as Set
import Data.Text.Lazy (Text)
import Data.Text.Lazy qualified as TL
import GHC.Generics
import Network.OAuth2.Experiment
import System.Directory
data OAuthDomains = OAuthDomains
{ auth0Domain :: Text
, oktaDomain :: Text
}
instance FromJSON OAuthDomains where
parseJSON = withObject "parseJSON OAuthDomains" $ \t -> do
auth0Domain <- t .: "auth0"
oktaDomain <- t .: "okta"
pure OAuthDomains {..}
newtype OAuthApps = OAuthApps (Aeson.KeyMap OAuthApp)
deriving (Generic)
unOAuthApps :: OAuthApps -> Aeson.KeyMap OAuthApp
unOAuthApps (OAuthApps x) = x
instance FromJSON OAuthApps
data OAuthApp = OAuthApp
{ clientId :: ClientId
, clientSecret :: ClientSecret
, scopes :: Set.Set Scope
, user :: Maybe UserConfig
}
instance FromJSON OAuthApp where
parseJSON = withObject "parseJSON OAuthApp" $ \t -> do
clientId <- ClientId <$> t .: "client_id"
clientSecret <- ClientSecret <$> t .: "client_secret"
scopeTexts <- t .:? "scopes"
user <- t .:? "user"
let scopes = Set.map Scope (Set.fromList (fromMaybe [] scopeTexts))
pure OAuthApp {..}
data UserConfig = UserConfig
{ username :: Text
, password :: Text
}
deriving (Generic)
instance FromJSON UserConfig
data OAuthConfigs = OAuthConfigs
{ domains :: OAuthDomains
, apps :: OAuthApps
}
instance FromJSON OAuthConfigs where
parseJSON = withObject "parseJSON OAuthConfigs" $ \t -> do
domains <- t .: "domains"
apps <- t .: "apps"
pure OAuthConfigs {..}
envFilePath :: String
envFilePath = ".env.json"
readEnvFile :: MonadIO m => ExceptT Text m OAuthConfigs
readEnvFile = do
withExceptT wrapError $
ExceptT $
liftIO $ do
pwd <- liftIO getCurrentDirectory
eitherDecodeFileStrict (pwd <> "/" <> envFilePath)
where
wrapError :: String -> Text
wrapError = TL.pack . ("Error when try to load .env.json\n" <>)
lookupApp :: MonadIO m => Text -> ExceptT Text m OAuthApp
lookupApp idpAppName = do
envs <- readEnvFile
lookupAppWith envs idpAppName
lookupAppWith :: MonadIO m => OAuthConfigs -> Text -> ExceptT Text m OAuthApp
lookupAppWith OAuthConfigs {..} idpAppName = do
let key = TL.toLower idpAppName
resp = Aeson.lookup (Aeson.fromString $ TL.unpack key) (unOAuthApps apps)
except $
maybe
(Left $ "[ Env.lookupWith ] Unable to load config for " <> key)
Right
resp
lookupAuth0Domain :: MonadIO m => ExceptT Text m Text
lookupAuth0Domain =
auth0Domain . domains <$> readEnvFile