-- This file is part of persona-idp - Persona (BrowserID) Identity Provider -- Copyright (C) 2013, 2014, 2015 Fraser Tweedale -- -- persona-idp is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU Affero General Public License for more details. -- -- You should have received a copy of the GNU Affero General Public License -- along with this program. If not, see . {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} module Serve (ServeOpts) where import Control.Monad.IO.Class import System.Exit import Control.Lens import Data.Aeson (eitherDecode, toJSON) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import Network.HTTP.Types.Status import Options.Applicative hiding (header) import Text.Blaze.Renderer.Text import Text.Hamlet import Text.Julius import Web.Scotty import Crypto.JOSE (encodeCompact) import Crypto.JWT (fromString) import Crypto.Persona import Command import Config import Middleware import Provision data ServeOpts = ServeOpts Int instance Command ServeOpts where parser = ServeOpts <$> option auto ( long "port" <> value 3000 <> showDefault <> metavar "N" <> help "Port on which to listen" ) run (ServeOpts port) = do let handleError = either (\e -> print e >> exitFailure) return delegatedSupport <- handleError =<< readConfigJSON "delegated-support.json" support <- handleError =<< readConfigJSON "support.json" k <- handleError =<< readConfigJSON "key.json" scotty port $ do middleware remoteUserX509Middleware get "/delegated-support" $ json delegatedSupport get "/support" $ json support get "/.well-known/browserid" $ json support get "/provisioning" $ html $ renderMarkup $(shamletFile "src/provisioning.hamlet") get "/provisioning.js" $ do let template = $(juliusFile "src/provisioning.julius") text $ renderJavascriptUrl (\_ _ -> undefined) template setHeader "Content-Type" "text/javascript; charset=UTF-8" post "/provisioning" $ do provReq' <- body case eitherDecode provReq' of Left e -> respondWith badRequest400 e Right provReq -> do remoteUser <- header "REMOTE_USER" if remoteUser == Just (TL.fromStrict $ provReq ^. eml) then do let iss = fromString $ T.pack $ delegatedSupport ^. authority result <- liftIO ((>>= encodeCompact) <$> provision k iss provReq) case result of Left e -> respondWith internalServerError500 (show e) Right cert -> raw cert else status forbidden403 respondWith :: Status -> String -> ActionM () respondWith e s = status e >> text (TL.pack $ show s)