module Snap.AtlassianConnect.Connect
( initConnectSnaplet
) where
import qualified Paths_atlassian_connect_core as PACC
import Data.ConfigurationHelpers
import qualified Data.Connect.Descriptor as D
import Snap.AtlassianConnect.Data
import qualified Snap.AtlassianConnect.PageToken as PT
import qualified Snap.AtlassianConnect.Routes as CR
import qualified Snap.AtlassianConnect.TimeUnits as TU
import qualified Control.Monad as CM
import qualified Control.Monad.IO.Class as MI
import qualified Crypto.Cipher.AES as CCA
import qualified Data.ByteString.Char8 as BSC
import qualified Data.Configurator as DC
import qualified Data.Configurator.Types as DCT
import qualified Data.EnvironmentHelpers as DE
import Data.Maybe (fromMaybe)
import Data.Text
import Data.Time.Units
import qualified Network.HostName as HN
import qualified Network.URI as NU
import qualified Snap.Snaplet as SS
initConnectSnaplet :: D.Plugin -> SS.SnapletInit b Connect
initConnectSnaplet plugin = SS.makeSnaplet "connect" "Atlassian Connect" (Just dataDir) $ do
SS.addRoutes CR.connectRoutes
configurationDirectory <- SS.getSnapletFilePath
MI.liftIO . fmap (toConnect plugin) $ SS.loadAppConfig "connect.cfg" configurationDirectory >>= loadConnectConfig
dataDir :: IO FilePath
dataDir = CM.liftM (++"/resources") PACC.getDataDir
data ConnectConfig = ConnectConfig
{ ccSecretKey :: BSC.ByteString
, ccBaseUrl :: NU.URI
, ccPageTokenTimeout :: TU.ConnectSecond
, ccHostWhiteList :: [Text]
}
toConnect :: D.Plugin -> ConnectConfig -> Connect
toConnect plugin conf = Connect
{ connectPlugin = plugin
, connectAES = CCA.initAES $ ccSecretKey conf
, connectBaseUrl = ccBaseUrl conf
, connectPageTokenTimeout = D.Timeout . TU.getSecond . ccPageTokenTimeout $ conf
, connectHostWhitelist = ccHostWhiteList conf
}
loadConnectConfig :: DCT.Config -> IO ConnectConfig
loadConnectConfig connectConf = do
rawBaseUrl <- require connectConf "base_url" "Missing base url in connect configuration file."
secret <- require connectConf "secret_key" "Missing secret key in connect configuration file."
hostWhiteListFromConfig <- require connectConf "valid_hosts" "Missing a valid_hosts whitelist."
hostWhiteList <- addLocalHost hostWhiteListFromConfig
let keyLength = BSC.length secret
CM.when (keyLength /= 32) $ fail ("Expected Atlassian Connect secret_key to be 32 Hex Digits long but was actually: " ++ show keyLength)
envBaseUrl <- DE.getEnv "CONNECT_BASE_URL"
envSecretKey <- DE.getEnv "CONNECT_SECRET_KEY"
let baseUrlToParse = fromMaybe rawBaseUrl envBaseUrl
case NU.parseURI baseUrlToParse of
Nothing -> fail("Could not parse the baseUrl in the configuration file: " ++ rawBaseUrl)
Just baseUrl -> do
pageTokenTimeoutInSeconds <- DC.lookupDefault PT.defaultTimeoutSeconds connectConf "page_token_timeout_seconds"
return ConnectConfig
{ ccBaseUrl = baseUrl
, ccSecretKey = maybe secret BSC.pack envSecretKey
, ccPageTokenTimeout = pageTokenTimeoutInSeconds
, ccHostWhiteList = hostWhiteList
}
addLocalHost :: [Text] -> IO [Text]
addLocalHost originalHosts = do
localhost <- HN.getHostName
return $ (pack localhost) : originalHosts