module Foundation.Yesod.Session ( makeSessionBackend ) where import Import.NoFoundation hiding (makeSessionBackend) import Foundation.Type import qualified Web.ServerSession.Core as ServerSession import qualified Web.ServerSession.Frontend.Yesod.Jwt as JwtSession import qualified Network.Wai as W import qualified Network.HTTP.Types.Header as W import qualified Network.Wai.Middleware.HttpAuth as W (extractBearerAuth) import Web.Cookie makeSessionBackend :: Yesod UniWorX => UniWorX -> IO (Maybe SessionBackend) makeSessionBackend app@UniWorX{ appSettings' = AppSettings{..}, ..} = notForBearer . sameSite $ case appSessionStore of SessionStorageMemcachedSql sqlStore -> mkBackend . stateSettings =<< ServerSession.createState sqlStore SessionStorageAcid acidStore | appServerSessionAcidFallback -> mkBackend . stateSettings =<< ServerSession.createState acidStore _other -> return Nothing where cfg = JwtSession.ServerSessionJwtConfig { sJwtJwkSet = appJSONWebKeySet , sJwtStart = Nothing , sJwtExpiration = appSessionTokenExpiration , sJwtEncoding = appSessionTokenEncoding , sJwtIssueBy = appInstanceID , sJwtIssueFor = appClusterID } mkBackend :: forall sto. ( ServerSession.SessionData sto ~ Map Text ByteString , ServerSession.Storage sto ) => ServerSession.State sto -> IO (Maybe SessionBackend) mkBackend = JwtSession.backend cfg (JwtSession.siteApproot app) stateSettings :: forall sto. ServerSession.State sto -> ServerSession.State sto stateSettings = ServerSession.setCookieName (toPathPiece CookieSession) . applyServerSessionSettings appServerSessionConfig sameSite | Just sameSiteStrict == cookieSameSite (getCookieSettings app CookieSession) = strictSameSiteSessions | Just sameSiteLax == cookieSameSite (getCookieSettings app CookieSession) = laxSameSiteSessions | otherwise = id notForBearer :: IO (Maybe SessionBackend) -> IO (Maybe SessionBackend) notForBearer = fmap $ fmap notForBearer' where notForBearer' :: SessionBackend -> SessionBackend notForBearer' (SessionBackend load) = let load' req | aHdrs <- mapMaybe (\(h, v) -> v <$ guard (h == W.hAuthorization)) $ W.requestHeaders req , any (is _Just . W.extractBearerAuth) aHdrs = return (mempty, const $ return []) | otherwise = load req in SessionBackend load'