diff --git a/config/compatability.json b/config/compatability.json new file mode 100644 index 0000000..379a014 --- /dev/null +++ b/config/compatability.json @@ -0,0 +1,6 @@ +{ + "0.1.0": "1.0.0", + "0.1.1": "1.0.0", + "0.1.2": "1.1.0", + "0.1.3": "1.1.0" +} \ No newline at end of file diff --git a/config/settings.yml b/config/settings.yml index 4f00f02..b56286a 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -28,4 +28,7 @@ ip-from-header: "_env:YESOD_IP_FROM_HEADER:false" # NB: If you need a numeric value (e.g. 123) to parse as a String, wrap it in single quotes (e.g. "_env:YESOD_PGPASS:'123'") # See https://github.com/yesodweb/yesod/wiki/Configuration#parsing-numeric-values-as-strings -app-compatibility-path: "_env:APP_COMPATIBILITY_CONFIG:/etc/start9/registry/compatibility.json" \ No newline at end of file +app-compatibility-path: "_env:APP_COMPATIBILITY_CONFIG:/etc/start9/registry/compatibility.json" +resources-path: "_env:RESOURCES_PATH:/var/www/html/resources" +ssl-path: "_env:SSL_PATH:/var/ssl" +registry-hostname: "_env:REGISTRY_HOSTNAME:registry.start9labs.com" \ No newline at end of file diff --git a/src/Application.hs b/src/Application.hs index f95ba9c..ffeca29 100644 --- a/src/Application.hs +++ b/src/Application.hs @@ -165,16 +165,15 @@ startApp :: AgentCtx -> IO () startApp foundation = do -- set up ssl certificates putStrLn @Text "Setting up SSL" - setupSsl + _ <- setupSsl <$> getAppSettings putStrLn @Text "SSL Setup Complete" - startWeb foundation startWeb :: AgentCtx -> IO () startWeb foundation = do app <- makeApplication foundation - - putStrLn @Text $ "Launching Web Server on port " <> show (appPort $ appSettings foundation) + let AppSettings{..} = appSettings foundation + putStrLn @Text $ "Launching Web Server on port " <> show appPort action <- async $ runTLS (tlsSettings sslCertLocation sslKeyLocation) (warpSettings foundation) diff --git a/src/Constants.hs b/src/Constants.hs deleted file mode 100644 index 261d480..0000000 --- a/src/Constants.hs +++ /dev/null @@ -1,21 +0,0 @@ -module Constants where - -import Data.Aeson -import Data.Aeson.Types -import Data.Maybe -import Data.Version (showVersion) -import Lib.Types.Semver -import Paths_start9_registry (version) -import Startlude - -sslPath :: FilePath -sslPath = "/var/ssl" - -resourcesDir :: FilePath -resourcesDir = "/var/www/html/resources" -- "./resources" -- - -registryVersion :: AppVersion -registryVersion = fromJust . parseMaybe parseJSON . String . toS . showVersion $ version - -getRegistryHostname :: IsString a => a -getRegistryHostname = "registry.start9labs.com" diff --git a/src/Handler/Apps.hs b/src/Handler/Apps.hs index 575461f..9483663 100644 --- a/src/Handler/Apps.hs +++ b/src/Handler/Apps.hs @@ -23,8 +23,9 @@ import Yesod.Core import Foundation import Lib.Registry import Lib.Semver -import System.FilePath ((<.>)) +import System.FilePath ((<.>), ()) import System.Posix.Files (fileSize, getFileStatus) +import Settings pureLog :: Show a => a -> Handler a pureLog = liftA2 (*>) ($logInfo . show) pure @@ -38,13 +39,22 @@ instance Show FileExtension where show (FileExtension f (Just e)) = f <.> e getAppsManifestR :: Handler TypedContent -getAppsManifestR = respondSource typePlain $ CB.sourceFile appManifestPath .| awaitForever sendChunkBS +getAppsManifestR = do + AppSettings{..} <- appSettings <$> getYesod + let appResourceDir = resourcesDir "apps" "apps.yaml" + respondSource typePlain $ CB.sourceFile appResourceDir .| awaitForever sendChunkBS getSysR :: Extension "" -> Handler TypedContent -getSysR = getApp sysResourceDir +getSysR e = do + AppSettings{..} <- appSettings <$> getYesod + let sysResourceDir = resourcesDir "sys" + getApp sysResourceDir e getAppR :: Extension "s9pk" -> Handler TypedContent -getAppR = getApp appResourceDir +getAppR e = do + AppSettings{..} <- appSettings <$> getYesod + let appResourceDir = resourcesDir "apps" "apps.yaml" + getApp appResourceDir e getApp :: KnownSymbol a => FilePath -> Extension a -> Handler TypedContent getApp rootDir ext = do diff --git a/src/Handler/Icons.hs b/src/Handler/Icons.hs index 0cf44ad..13a9027 100644 --- a/src/Handler/Icons.hs +++ b/src/Handler/Icons.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE RecordWildCards #-} module Handler.Icons where @@ -12,10 +13,13 @@ import Yesod.Core import Foundation import Lib.Registry +import Settings +import System.FilePath (()) getIconsR :: Extension "png" -> Handler TypedContent getIconsR ext = do - mPng <- liftIO $ getUnversionedFileFromDir iconsResourceDir ext + AppSettings{..} <- appSettings <$> getYesod + mPng <- liftIO $ getUnversionedFileFromDir (resourcesDir "icons") ext case mPng of Nothing -> notFound Just pngPath -> do diff --git a/src/Handler/Version.hs b/src/Handler/Version.hs index 84a08a7..a230b9d 100644 --- a/src/Handler/Version.hs +++ b/src/Handler/Version.hs @@ -2,6 +2,8 @@ {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE RecordWildCards #-} + module Handler.Version where import Startlude @@ -14,24 +16,30 @@ import qualified Data.Text as T import Network.HTTP.Types import Yesod.Core -import Constants import Foundation import Handler.Types.Status import Lib.Registry import Lib.Semver import Lib.Types.Semver +import Settings +import System.FilePath (()) getVersionR :: Handler AppVersionRes -getVersionR = pure . AppVersionRes registryVersion $ Nothing +getVersionR = do + AppSettings{..} <- appSettings <$> getYesod + pure . AppVersionRes registryVersion $ Nothing getVersionAppR :: Text -> Handler (Maybe AppVersionRes) -getVersionAppR appId = getVersionWSpec appResourceDir appExt +getVersionAppR appId = do + AppSettings{..} <- appSettings <$> getYesod + getVersionWSpec (resourcesDir "apps") appExt where appExt = Extension (toS appId) :: Extension "s9pk" getVersionSysR :: Text -> Handler (Maybe AppVersionRes) getVersionSysR sysAppId = runMaybeT $ do - avr <- MaybeT $ getVersionWSpec sysResourceDir sysExt + AppSettings{..} <- appSettings <$> getYesod + avr <- MaybeT $ getVersionWSpec (resourcesDir "sys") sysExt minComp <- lift $ case sysAppId of "agent" -> Just <$> meshCompanionCompatibility (appVersionVersion avr) _ -> pure Nothing diff --git a/src/Lib/Registry.hs b/src/Lib/Registry.hs index 3e3e288..0db0957 100644 --- a/src/Lib/Registry.hs +++ b/src/Lib/Registry.hs @@ -14,25 +14,9 @@ import System.Directory import System.FilePath import Yesod.Core -import Constants import Lib.Semver import Lib.Types.Semver -appResourceDir :: FilePath -appResourceDir = resourcesDir "apps" - -sysResourceDir :: FilePath -sysResourceDir = resourcesDir "sys" - -iconsResourceDir :: FilePath -iconsResourceDir = resourcesDir "icons" - -appManifestPath :: FilePath -appManifestPath = appResourceDir appManifestFile - -appManifestFile :: FilePath -appManifestFile = "apps.yaml" - type Registry = HashMap String (HashMap AppVersion FilePath) newtype RegisteredAppVersion = RegisteredAppVersion (AppVersion, FilePath) deriving (Eq, Show) diff --git a/src/Lib/Ssl.hs b/src/Lib/Ssl.hs index d1a1383..c28f8f2 100644 --- a/src/Lib/Ssl.hs +++ b/src/Lib/Ssl.hs @@ -1,58 +1,49 @@ {-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE RecordWildCards #-} + module Lib.Ssl where import Startlude import Data.String.Interpolate.IsString import System.Directory -import System.FilePath import System.Process - -import Constants +import Settings -- openssl genrsa -out key.pem 2048 -- openssl req -new -key key.pem -out certificate.csr -- openssl x509 -req -in certificate.csr -signkey key.pem -out certificate.pem -sslKeyLocation :: FilePath -sslKeyLocation = sslPath "key.pem" - -sslCsrLocation :: FilePath -sslCsrLocation = sslPath "certificate.csr" - -sslCertLocation :: FilePath -sslCertLocation = sslPath "certificate.pem" - -checkForSslCert :: IO Bool -checkForSslCert = - doesPathExist sslKeyLocation <&&> doesPathExist sslCertLocation - -generateSslKey :: IO ExitCode -generateSslKey = rawSystem "openssl" ["genrsa", "-out", sslKeyLocation, "2048"] - -generateSslCert :: Text -> IO ExitCode -generateSslCert name = rawSystem - "openssl" - ["req", "-new", "-key", sslKeyLocation, "-out", sslCsrLocation, "-subj", [i|/CN=#{name}.local|]] - -selfSignSslCert :: IO ExitCode -selfSignSslCert = rawSystem - "openssl" - [ "x509" - , "-req" - , "-in" - , sslCsrLocation - , "-signkey" - , sslKeyLocation - , "-out" - , sslCertLocation - ] - -setupSsl :: IO () -setupSsl = do +setupSsl :: AppSettings -> IO () +setupSsl AppSettings{..} = do exists <- checkForSslCert unless exists $ do void $ system $ "mkdir -p " <> sslPath void generateSslKey - void $ generateSslCert getRegistryHostname + void $ generateSslCert registryHostname void selfSignSslCert + where + checkForSslCert :: IO Bool + checkForSslCert = + doesPathExist sslKeyLocation <&&> doesPathExist sslCertLocation + + generateSslKey :: IO ExitCode + generateSslKey = rawSystem "openssl" ["genrsa", "-out", sslKeyLocation, "2048"] + + generateSslCert :: Text -> IO ExitCode + generateSslCert name = rawSystem + "openssl" + ["req", "-new", "-key", sslKeyLocation, "-out", sslCsrLocation, "-subj", [i|/CN=#{name}.local|]] + + selfSignSslCert :: IO ExitCode + selfSignSslCert = rawSystem + "openssl" + [ "x509" + , "-req" + , "-in" + , sslCsrLocation + , "-signkey" + , sslKeyLocation + , "-out" + , sslCertLocation + ] \ No newline at end of file diff --git a/src/Settings.hs b/src/Settings.hs index 0729683..f6ad150 100644 --- a/src/Settings.hs +++ b/src/Settings.hs @@ -10,11 +10,17 @@ module Settings where import Startlude import qualified Control.Exception as Exception +import Data.Maybe import Data.Aeson +import Data.Aeson.Types +import Data.Version (showVersion) import Data.FileEmbed (embedFile) import Data.Yaml (decodeEither') import Network.Wai.Handler.Warp (HostPreference) import Yesod.Default.Config2 (applyEnvValue, configSettingsYml) +import Paths_start9_registry (version) +import Lib.Types.Semver +import System.FilePath (()) -- | Runtime settings to configure this application. These settings can be -- loaded from various sources: defaults, environment variables, config files, @@ -33,6 +39,13 @@ data AppSettings = AppSettings , appShouldLogAll :: Bool -- ^ Should all log messages be displayed? , appCompatibilityPath :: FilePath + , resourcesDir :: FilePath + , sslPath :: FilePath + , registryHostname :: Text + , registryVersion :: AppVersion + , sslKeyLocation :: FilePath + , sslCsrLocation :: FilePath + , sslCertLocation :: FilePath } instance FromJSON AppSettings where @@ -43,7 +56,15 @@ instance FromJSON AppSettings where appDetailedRequestLogging <- o .:? "detailed-logging" .!= True appShouldLogAll <- o .:? "should-log-all" .!= False appCompatibilityPath <- o .: "app-compatibility-path" - + resourcesDir <- o .: "resources-path" + sslPath <- o .: "ssl-path" + registryHostname <- o .: "registry-hostname" + + let sslKeyLocation = sslPath "key.pem" + let sslCsrLocation = sslPath "certificate.csr" + let sslCertLocation = sslPath "certificate.pem" + let registryVersion = fromJust . parseMaybe parseJSON . String . toS . showVersion $ version + return AppSettings { .. } -- | Raw bytes at compile time of @config/settings.yml@