module PostgREST.Middleware where
import Data.Aeson (Value (..))
import qualified Data.HashMap.Strict as M
import qualified Hasql.Transaction as H
import Network.HTTP.Types.Status (unauthorized401, status500)
import Network.Wai (Application, Response,
responseLBS)
import Network.Wai.Middleware.Cors (cors)
import Network.Wai.Middleware.Gzip (def, gzip)
import Network.Wai.Middleware.Static (only, staticPolicy)
import PostgREST.ApiRequest (ApiRequest(..), ContentType(..),
toHeader)
import PostgREST.Auth (claimsToSQL, JWTAttempt(..))
import PostgREST.Config (AppConfig (..), corsPolicy)
import PostgREST.Error (errResponse)
import Protolude hiding (concat, null)
runWithClaims :: AppConfig -> JWTAttempt ->
(ApiRequest -> H.Transaction Response) ->
ApiRequest -> H.Transaction Response
runWithClaims conf eClaims app req =
case eClaims of
JWTExpired -> return $ unauthed "JWT expired"
JWTInvalid -> return $ unauthed "JWT invalid"
JWTMissingSecret -> return $ errResponse status500 "Server lacks JWT secret"
JWTClaims claims -> do
let setClaims = claimsToSQL (M.union claims (M.singleton "role" anon))
H.sql $ mconcat setClaims
mapM_ H.sql customReqCheck
app req
where
anon = String . toS $ configAnonRole conf
customReqCheck = (\f -> "select " <> toS f <> "();") <$> configReqCheck conf
unauthed message = responseLBS unauthorized401
[ toHeader CTApplicationJSON
, ( "WWW-Authenticate"
, "Bearer error=\"invalid_token\", " <>
"error_description=\"" <> message <> "\""
)
]
(toS $ "{\"message\":\""<>message<>"\"}")
defaultMiddle :: Application -> Application
defaultMiddle =
gzip def
. cors corsPolicy
. staticPolicy (only [("favicon.ico", "static/favicon.ico")])