on master help sign in
Add an option to ob run for taking a certificate directory to use for HTTPS.
commit21b616aabceea87f7e722af5febc7320b3fb3a61 authorCale Gibbard <cgibbard@gmail.com> dateFri 21 Aug 2020, 15:45 (6 years ago) parent3fa3600
4 files changed+38−21
lib/command/src/Obelisk/Command.hs+8−3 lib/command/src/Obelisk/Command/Run.hs+3−2 lib/run/obelisk-run.cabal+1 lib/run/src/Obelisk/Run.hs+26−16
lib/command/src/Obelisk/Command.hs+8−3
@@ -84,7 +84,7 @@ initForce = switch (long "force" <> help "Allow ob init to overwrite files")
8484data ObCommand
8585 = ObCommand_Init InitSource Bool
8686 | ObCommand_Deploy DeployCommand
87− | ObCommand_Run [(FilePath, Interpret)]
87+ | ObCommand_Run [(FilePath, Interpret)] (Maybe FilePath)
8888 | ObCommand_Profile String [String]
8989 | ObCommand_Thunk ThunkOption
9090 | ObCommand_Repl [(FilePath, Interpret)]
@@ -109,7 +109,7 @@ obCommand cfg = hsubparser
109109 (mconcat
110110 [ command "init" $ info (ObCommand_Init <$> initSource <*> initForce) $ progDesc "Initialize an Obelisk project"
111111 , command "deploy" $ info (ObCommand_Deploy <$> deployCommand cfg) $ progDesc "Prepare a deployment for an Obelisk project"
112− , command "run" $ info (ObCommand_Run <$> interpretOpts) $ progDesc "Run current project in development mode"
112+ , command "run" $ info (ObCommand_Run <$> interpretOpts <*> certDirOpts) $ progDesc "Run current project in development mode"
113113 , command "profile" $ info (uncurry ObCommand_Profile <$> profileCommand) $ progDesc "Run current project with profiling enabled"
114114 , command "thunk" $ info (ObCommand_Thunk <$> thunkOption) $ progDesc "Manipulate thunk directories"
115115 , command "repl" $ info (ObCommand_Repl <$> interpretOpts) $ progDesc "Open an interactive interpreter"
@@ -281,6 +281,11 @@ interpretOpts = many
281281 where
282282 common = action "directory" <> metavar "DIR"
283283
284+certDirOpts :: Parser (Maybe FilePath)
285+certDirOpts = optional (strOption (short 'c' <> long "cert" <> metavar "DIRECTORY" <> help helpText))
286+ where
287+ helpText = "Specify a directory in which to find \'cert.pem\', \'chain.pem\' and \'privkey.pem\' for use with TLS."
288+
284289shellOpts :: Parser ShellOpts
285290shellOpts = ShellOpts
286291 <$> shellFlags
@@ -391,7 +396,7 @@ ob = \case
391396 Just RemoteBuilder_ObeliskVM -> (:[]) <$> VmBuilder.getNixBuildersArg
392397 DeployCommand_Update -> deployUpdate "."
393398 DeployCommand_Test (platform, extraArgs) -> deployMobile platform extraArgs
394− ObCommand_Run interpretPathsList -> withInterpretPaths interpretPathsList run
399+ ObCommand_Run interpretPathsList certDir -> withInterpretPaths interpretPathsList (run certDir)
395400 ObCommand_Profile basePath rtsFlags -> profile basePath rtsFlags
396401 ObCommand_Thunk to -> case _thunkOption_command to of
397402 ThunkCommand_Update config -> for_ thunks (updateThunkToLatest config)
lib/command/src/Obelisk/Command/Run.hs+3−2
@@ -160,8 +160,8 @@ profile profileBasePattern rtsFlags = withProjectRoot "." $ \root -> do
160160 ] <> rtsFlags
161161 <> [ "-RTS" ]
162162
163−run :: MonadObelisk m => FilePath -> PathTree Interpret -> m ()
164−run root interpretPaths = do
163+run :: MonadObelisk m => Maybe FilePath -> FilePath -> PathTree Interpret -> m ()
164+run certDir root interpretPaths = do
165165 pkgs <- getParsedLocalPkgs root interpretPaths
166166 assets <- findProjectAssets root
167167 putLog Debug $ "Assets impurely loaded from: " <> assets
@@ -171,6 +171,7 @@ run root interpretPaths = do
171171 runGhcid root True (ghciArgs <> dotGhciArgs) pkgs $ Just $ unwords
172172 [ "Obelisk.Run.run"
173173 , show freePort
174+ , "(" ++ show certDir ++ ")"
174175 , "(Obelisk.Run.runServeAsset " ++ show assets ++ ")"
175176 , "Backend.backend"
176177 , "Frontend.frontend"
lib/run/obelisk-run.cabal+1
@@ -14,6 +14,7 @@ library
1414 , cookie
1515 , dependent-sum
1616 , dependent-sum-template
17+ , filepath
1718 , ghcjs-dom
1819 , HsOpenSSL
1920 , http-client
lib/run/src/Obelisk/Run.hs+26−16
@@ -65,6 +65,7 @@ import qualified OpenSSL.X509.Request as X509Request
6565import Reflex.Dom.Core
6666import Snap.Core (Snap)
6767import System.Environment
68+import System.FilePath ((</>))
6869import System.IO
6970import System.Process
7071import Text.URI (URI)
@@ -78,11 +79,13 @@ import qualified System.Which
7879
7980run
8081 :: Int -- ^ Port to run the backend
82+ -> Maybe FilePath -- ^ Optional directory in which to find "cert.pem", "chain.pem" and "privkey.pem" to be used for TLS.
83+ -- If this is Nothing and TLS is enabled, we'll generate a self-signed cert.
8184 -> ([Text] -> Snap ()) -- ^ Static asset handler
8285 -> Backend backendRoute frontendRoute -- ^ Backend
8386 -> Frontend (R frontendRoute) -- ^ Frontend
8487 -> IO ()
85−run port serveStaticAsset backend frontend = do
88+run port certDir serveStaticAsset backend frontend = do
8689 prettifyOutput
8790 let handleBackendErr (e :: IOException) = hPutStrLn stderr $ "backend stopped; make a change to your code to reload - error " <> show e
8891 --TODO: Use Obelisk.Backend.runBackend; this will require separating the checking and running phases
@@ -102,7 +105,7 @@ run port serveStaticAsset backend frontend = do
102105 appRouteToUrl (k :/ v) = renderObeliskRoute validFullEncoder (FullRoute_Frontend (ObeliskRoute_App k) :/ v)
103106 allJsUrl = renderAllJsPath validFullEncoder
104107
105− let conf = defRunConfig { _runConfig_redirectPort = port }
108+ let conf = defRunConfig { _runConfig_redirectPort = port, _runConfig_certDir = certDir }
106109 runWidget conf publicConfigs frontend validFullEncoder `finally` killThread backendTid
107110
108111-- Convenience wrapper to handle path segments for 'Snap.serveAsset'
@@ -135,24 +138,29 @@ runWidget conf configs frontend validFullEncoder = do
135138 -- Providing TLS here will also incidentally provide it to proxied requests to the backend.
136139 prepareRunner = case uri ^? uriScheme . _Just . unRText of
137140 Just "https" -> do
138− -- Generate a private key and self-signed certificate for TLS
139− privateKey <- RSA.generateRSAKey' 2048 3
141+ case _runConfig_certDir conf of
142+ Nothing -> do
143+ -- Generate a private key and self-signed certificate for TLS
144+ privateKey <- RSA.generateRSAKey' 2048 3
140145
141− certRequest <- X509Request.newX509Req
142− _ <- X509Request.setPublicKey certRequest privateKey
143− _ <- X509Request.signX509Req certRequest privateKey Nothing
146+ certRequest <- X509Request.newX509Req
147+ _ <- X509Request.setPublicKey certRequest privateKey
148+ _ <- X509Request.signX509Req certRequest privateKey Nothing
144149
145− cert <- X509.newX509 >>= X509Request.makeX509FromReq certRequest
146− _ <- X509.setPublicKey cert privateKey
147− now <- getCurrentTime
148− _ <- X509.setNotBefore cert $ addUTCTime (-1) now
149− _ <- X509.setNotAfter cert $ addUTCTime (365 * 24 * 60 * 60) now
150− _ <- X509.signX509 cert privateKey Nothing
150+ cert <- X509.newX509 >>= X509Request.makeX509FromReq certRequest
151+ _ <- X509.setPublicKey cert privateKey
152+ now <- getCurrentTime
153+ _ <- X509.setNotBefore cert $ addUTCTime (-1) now
154+ _ <- X509.setNotAfter cert $ addUTCTime (365 * 24 * 60 * 60) now
155+ _ <- X509.signX509 cert privateKey Nothing
151156
152− certByteString <- BSUTF8.fromString <$> PEM.writeX509 cert
153− privateKeyByteString <- BSUTF8.fromString <$> PEM.writePKCS8PrivateKey privateKey Nothing
157+ certByteString <- BSUTF8.fromString <$> PEM.writeX509 cert
158+ privateKeyByteString <- BSUTF8.fromString <$> PEM.writePKCS8PrivateKey privateKey Nothing
154159
155− return $ runTLSSocket (tlsSettingsMemory certByteString privateKeyByteString)
160+ return $ runTLSSocket (tlsSettingsMemory certByteString privateKeyByteString)
161+ Just certDir -> do
162+ putStrLn $ "Using certificate information from: " ++ certDir
163+ return $ runTLSSocket (tlsSettingsChain (certDir </> "cert.pem") [certDir </> "chain.pem"] (certDir </> "privkey.pem"))
156164 _ -> return runSettingsSocket
157165 runner <- prepareRunner
158166 bracket
@@ -257,6 +265,7 @@ data RunConfig = RunConfig
257265 , _runConfig_redirectHost :: ByteString
258266 , _runConfig_redirectPort :: Int
259267 , _runConfig_retryTimeout :: Int -- seconds
268+ , _runConfig_certDir :: Maybe FilePath
260269 }
261270
262271defRunConfig :: RunConfig
@@ -265,4 +274,5 @@ defRunConfig = RunConfig
265274 , _runConfig_redirectHost = "127.0.0.1"
266275 , _runConfig_redirectPort = 3001
267276 , _runConfig_retryTimeout = 1
277+ , _runConfig_certDir = Nothing
268278 }