packages feed

apiary-clientsession 0.13.2.1 → 0.16.0

raw patch · 4 files changed

+95/−79 lines, 4 filesdep −reflectiondep ~apiarydep ~apiary-cookiePVP ok

version bump matches the API change (PVP)

Dependencies removed: reflection

Dependency ranges changed: apiary, apiary-cookie

API changes (from Hackage documentation)

- Web.Apiary.ClientSession: type HasSession = Given Session
- Web.Apiary.ClientSession: withSession :: MonadIO m => SessionConfig -> (HasSession => m b) -> m b
- Web.Apiary.ClientSession.Explicit: KeyByteString :: ByteString -> KeySource
- Web.Apiary.ClientSession.Explicit: KeyFile :: FilePath -> KeySource
- Web.Apiary.ClientSession.Explicit: SessionConfig :: KeySource -> DiffTime -> Maybe ByteString -> Maybe ByteString -> Bool -> Bool -> Maybe ByteString -> ByteString -> Either HeaderName ByteString -> Int -> SessionConfig
- Web.Apiary.ClientSession.Explicit: angularXsrfCookieName :: SessionConfig -> Maybe ByteString
- Web.Apiary.ClientSession.Explicit: checkToken :: (Functor n, MonadIO n) => Session -> ApiaryT c n m a -> ApiaryT c n m a
- Web.Apiary.ClientSession.Explicit: csrfToken :: MonadIO m => Session -> ActionT m ByteString
- Web.Apiary.ClientSession.Explicit: csrfTokenCheckingName :: SessionConfig -> Either HeaderName ByteString
- Web.Apiary.ClientSession.Explicit: csrfTokenCookieName :: SessionConfig -> ByteString
- Web.Apiary.ClientSession.Explicit: csrfTokenLength :: SessionConfig -> Int
- Web.Apiary.ClientSession.Explicit: data KeySource
- Web.Apiary.ClientSession.Explicit: data Session
- Web.Apiary.ClientSession.Explicit: data SessionConfig
- Web.Apiary.ClientSession.Explicit: embedDefaultKeyConfig :: ExpQ
- Web.Apiary.ClientSession.Explicit: embedKeyConfig :: FilePath -> ExpQ
- Web.Apiary.ClientSession.Explicit: getSessionValue :: Session -> UTCTime -> ByteString -> Maybe ByteString
- Web.Apiary.ClientSession.Explicit: mkSessionCookie :: SessionConfig -> Key -> ByteString -> ByteString -> IO SetCookie
- Web.Apiary.ClientSession.Explicit: session :: (Functor n, MonadIO n, Strategy w, Query a) => Session -> ByteString -> proxy (w a) -> ApiaryT (SNext w as a) n m b -> ApiaryT as n m b
- Web.Apiary.ClientSession.Explicit: sessionDomain :: SessionConfig -> Maybe ByteString
- Web.Apiary.ClientSession.Explicit: sessionHttpOnly :: SessionConfig -> Bool
- Web.Apiary.ClientSession.Explicit: sessionKey :: SessionConfig -> KeySource
- Web.Apiary.ClientSession.Explicit: sessionMaxAge :: SessionConfig -> DiffTime
- Web.Apiary.ClientSession.Explicit: sessionPath :: SessionConfig -> Maybe ByteString
- Web.Apiary.ClientSession.Explicit: sessionSecure :: SessionConfig -> Bool
- Web.Apiary.ClientSession.Explicit: setSession :: MonadIO m => Session -> ByteString -> ByteString -> ActionT m ()
- Web.Apiary.ClientSession.Explicit: withSession :: MonadIO m => SessionConfig -> (Session -> m b) -> m b
+ Web.Apiary.ClientSession: data Session
+ Web.Apiary.ClientSession: getSessionConfig :: (Has Session exts, Monad m) => ActionT exts m SessionConfig
+ Web.Apiary.ClientSession: initSession :: MonadIO m => SessionConfig -> Initializer' m Session
+ Web.Apiary.ClientSession: sessionTimeoutAction :: SessionConfig -> forall e m. MonadIO m => ActionT e m ()
+ Web.Apiary.ClientSession: setSessionWith :: (Has Session exts, MonadIO m) => SessionConfig -> ByteString -> ByteString -> ActionT exts m ()
- Web.Apiary.ClientSession: SessionConfig :: KeySource -> DiffTime -> Maybe ByteString -> Maybe ByteString -> Bool -> Bool -> Maybe ByteString -> ByteString -> Either HeaderName ByteString -> Int -> SessionConfig
+ Web.Apiary.ClientSession: SessionConfig :: KeySource -> DiffTime -> Maybe ByteString -> Maybe ByteString -> Bool -> Bool -> (forall e m. MonadIO m => ActionT e m ()) -> Maybe ByteString -> ByteString -> Either HeaderName ByteString -> Int -> SessionConfig
- Web.Apiary.ClientSession: checkToken :: (Functor n, MonadIO n, HasSession) => ApiaryT c n m a -> ApiaryT c n m a
+ Web.Apiary.ClientSession: checkToken :: (Has Session exts, MonadIO actM) => ApiaryT exts prms actM m () -> ApiaryT exts prms actM m ()
- Web.Apiary.ClientSession: csrfToken :: (MonadIO m, HasSession) => ActionT m ByteString
+ Web.Apiary.ClientSession: csrfToken :: (Has Session exts, MonadIO m) => ActionT exts m ByteString
- Web.Apiary.ClientSession: session :: (Functor n, MonadIO n, Strategy w, Query a, HasSession) => ByteString -> proxy (w a) -> ApiaryT (SNext w as a) n m b -> ApiaryT as n m b
+ Web.Apiary.ClientSession: session :: (Has Session exts, Query a, Strategy w, MonadIO actM) => ByteString -> w a -> ApiaryT exts (SNext w prms a) actM m () -> ApiaryT exts prms actM m ()
- Web.Apiary.ClientSession: setSession :: (MonadIO m, HasSession) => ByteString -> ByteString -> ActionT m ()
+ Web.Apiary.ClientSession: setSession :: (Has Session exts, MonadIO m) => ByteString -> ByteString -> ActionT exts m ()

Files

apiary-clientsession.cabal view
@@ -1,5 +1,5 @@ name:                apiary-clientsession-version:             0.13.2.1+version:             0.16.0 synopsis:            clientsession support for apiary web framework. description:   examples:@@ -24,23 +24,22 @@  library   exposed-modules:     Web.Apiary.ClientSession-                       Web.Apiary.ClientSession.Explicit   other-modules:       Web.Apiary.ClientSession.Internal-  other-extensions:       build-depends:       base               >=4.6   && <4.8                      , template-haskell-                     , directory          >=1.2   && <1.3-                     , bytestring         >=0.10  && <0.11-                     , apiary             >=0.13  && <0.16-                     , apiary-cookie      >=0.13  && <0.14                      , clientsession      >=0.9   && <0.10-                     , time               >=1.4   && <1.5-                     , data-default-class >=0.0   && <0.1-                     , reflection         >=1.4   && <1.6-                     , binary             >=0.7   && <0.8+                     , apiary             >=0.16  && <0.17+                     , apiary-cookie      >=0.16  && <0.17++                     , directory          >=1.2   && <1.3                      , crypto-random      >=0.0   && <0.1                      , cprng-aes          >=0.5   && <0.6++                     , binary             >=0.7   && <0.8+                     , bytestring         >=0.10  && <0.11                      , base64-bytestring  >=1.0   && <1.1+                     , time               >=1.4   && <1.5+                     , data-default-class >=0.0   && <0.1                      , http-types         >=0.8   && <0.9                      , blaze-html         >=0.7   && <0.8 
src/Web/Apiary/ClientSession.hs view
@@ -1,56 +1,86 @@ {-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}  module Web.Apiary.ClientSession-    ( HasSession+    ( I.Session+    -- * config     , I.SessionConfig(..), I.KeySource(..)-    , withSession     , I.embedKeyConfig, I.embedDefaultKeyConfig+    -- * initializer+    , initSession+    -- * getter+    , getSessionConfig     -- * setter     , setSession     , csrfToken+    -- ** with sessionConfig+    , setSessionWith     -- * filter     , session     , checkToken     -- * Reexport-    , module Data.Default.Class     -- | deleteCookie     , module Web.Apiary.Cookie     ) where  import Web.Apiary -import Data.Default.Class+import Data.Apiary.Extension+import Data.Apiary.Proxy+ import qualified Web.Apiary.ClientSession.Internal as I import Web.Apiary.Cookie (deleteCookie)-import Data.Reflection import qualified Data.ByteString as S import Control.Monad.Apiary.Filter.Internal.Strategy -type HasSession = Given I.Session+initSession :: MonadIO m => I.SessionConfig -> Initializer' m I.Session+initSession c = initializer $ I.withSession c return -withSession :: MonadIO m => I.SessionConfig -> (HasSession => m b) -> m b-withSession c m = I.withSession c (\s -> give s m)+setSession :: (Has I.Session exts, MonadIO m)+           => S.ByteString -> S.ByteString+           -> ActionT exts m ()+setSession k v = do+    sess <- getExt (Proxy :: Proxy I.Session)+    I.setSession sess k v -setSession :: (MonadIO m, HasSession)-           => S.ByteString -> S.ByteString -> ActionT m ()-setSession = I.setSession given+getSessionConfig :: (Has I.Session exts, Monad m)+                 => ActionT exts m I.SessionConfig+getSessionConfig = do+    sess <- getExt (Proxy :: Proxy I.Session)+    return $ I.sessionConfig sess +setSessionWith :: (Has I.Session exts, MonadIO m)+               => I.SessionConfig+               -> S.ByteString -> S.ByteString+               -> ActionT exts m ()+setSessionWith cfg k v = do+    sess <- getExt (Proxy :: Proxy I.Session)+    I.setSession sess { I.sessionConfig = cfg } k v++session :: (Has I.Session exts, Query a, Strategy w, MonadIO actM)+        => S.ByteString -> w a+        -> ApiaryT exts (SNext w prms a) actM m ()+        -> ApiaryT exts prms actM m ()+session k w m = do+    sess <- apiaryExt (Proxy :: Proxy I.Session)+    I.session sess k w m+ -- | create crypto random (generate random by AES CTR(cprng-aes package) and encode by base64), -- -- set it client session cookie, set XSRF-TOKEN header(when Just angularXsrfCookieName), -- -- and return value. since 0.9.0.0.-csrfToken :: (MonadIO m, HasSession) => ActionT m S.ByteString-csrfToken = I.csrfToken given--session :: (Functor n, MonadIO n, Strategy w, Query a, HasSession)-        => S.ByteString -> proxy (w a)-        -> ApiaryT (SNext w as a) n m b -> ApiaryT as n m b-session = I.session given+csrfToken :: (Has I.Session exts, MonadIO m) => ActionT exts m S.ByteString+csrfToken = getExt (Proxy :: Proxy I.Session) >>= I.csrfToken  -- | check csrf token. since 0.9.0.0.-checkToken :: (Functor n, MonadIO n, HasSession)-           => ApiaryT c n m a -> ApiaryT c n m a-checkToken = I.checkToken given+checkToken :: (Has I.Session exts, MonadIO actM)+           => ApiaryT exts prms actM m () -> ApiaryT exts prms actM m ()+checkToken m = do+    sess <- apiaryExt (Proxy :: Proxy I.Session)+    I.checkToken sess m+
− src/Web/Apiary/ClientSession/Explicit.hs
@@ -1,21 +0,0 @@-module Web.Apiary.ClientSession.Explicit-    (-      Session, SessionConfig(..), KeySource(..)-    , withSession-    , embedKeyConfig, embedDefaultKeyConfig-    -- * actions-    , setSession-    , csrfToken-    -- * filters-    , session, checkToken-    -- * lowlevels-    , mkSessionCookie, getSessionValue-    -- * reexports-    , module Data.Default.Class-    -- | deleteCookie-    , module Web.Apiary.Cookie-    ) where--import Web.Apiary.ClientSession.Internal-import Data.Default.Class-import Web.Apiary.Cookie(deleteCookie)
src/Web/Apiary/ClientSession/Internal.hs view
@@ -24,9 +24,8 @@ import Control.Monad.Apiary.Filter.Internal.Strategy  import Web.Apiary.Wai-import Web.Apiary hiding (Default(..))+import Web.Apiary import Web.Apiary.Cookie-import Web.Apiary.Cookie.Internal import Web.ClientSession  import qualified Network.HTTP.Types as HTTP @@ -46,9 +45,9 @@ import qualified Data.ByteString.Lazy as L  data Session = Session-    { key       :: Key-    , tokenGen  :: IORef AESRNG-    , config    :: SessionConfig+    { key           :: Key+    , tokenGen      :: IORef AESRNG+    , sessionConfig :: SessionConfig     }  data KeySource@@ -60,12 +59,13 @@  -- | generate and embed key at compile time. since 0.13.2. ----- This function embed as SessionConfig with default config. so you can configure it.--- but don't configure sessionKey.+-- This function embed as SessionsessionConfig with default sessionConfig. so you can sessionConfigure it.+-- but DON'T sessionConfigure sessionKey.+--+-- this function is convenient when create heroku project. --  -- @--- withSession $embedDefaultKeyConfig { csrfTokenCookieName = \"foo\" } $ run 3000 . runApiary def $ do---     route define ...+-- embedsessionConfig = $embedDefaultKeysessionConfig { csrfTokenCookieName = \"foo\" } -- @ embedKeyConfig :: FilePath -> ExpQ embedKeyConfig keyfile = do@@ -97,6 +97,8 @@     , sessionHttpOnly       :: Bool     , sessionSecure         :: Bool +    , sessionTimeoutAction  :: forall e m. MonadIO m => ActionT e m ()+     , angularXsrfCookieName :: Maybe S.ByteString     , csrfTokenCookieName   :: S.ByteString @@ -104,10 +106,17 @@     , csrfTokenLength       :: Int     } +defaultCheckTokenFailAction :: Monad actM => ActionT exts actM ()+defaultCheckTokenFailAction = do+    reset+    status status401+    bytes "session timeout\n"+    stop+ instance Default SessionConfig where     def = SessionConfig         (KeyFile defaultKeyFile) (24 * 60 * 60) Nothing Nothing True True-        Nothing "_token" (Right "_token") 40+        defaultCheckTokenFailAction Nothing "_token" (Right "_token") 40  withSession :: MonadIO m => SessionConfig -> (Session -> m b) -> m b withSession cfg@SessionConfig{..} m = do@@ -151,9 +160,9 @@         Right (_, _, (BinUTCTime t, v)) -> if c < t then Just v else Nothing         _ -> Nothing -setSession :: MonadIO m => Session -> S.ByteString -> S.ByteString -> ActionT m ()+setSession :: MonadIO m => Session -> S.ByteString -> S.ByteString -> ActionT exts m () setSession sess k v = do-    s <- liftIO $ mkSessionCookie (config sess) (key sess) k v+    s <- liftIO $ mkSessionCookie (sessionConfig sess) (key sess) k v     setCookie s  newToken :: Int -> IORef AESRNG -> IO S.ByteString@@ -162,12 +171,12 @@   where      swap (a,b) = (b,a) -csrfToken :: MonadIO m => Session -> ActionT m S.ByteString+csrfToken :: MonadIO m => Session -> ActionT exts m S.ByteString csrfToken Session{..} = do-    tok <- liftIO $ newToken (csrfTokenLength config) tokenGen -    sc <- liftIO $ mkSessionCookie config key (csrfTokenCookieName config) tok+    tok <- liftIO $ newToken (csrfTokenLength sessionConfig) tokenGen +    sc <- liftIO $ mkSessionCookie sessionConfig key (csrfTokenCookieName sessionConfig) tok     setCookie sc-    maybe (return ()) (setCookie . ngCookie sc tok) (angularXsrfCookieName config)+    maybe (return ()) (setCookie . ngCookie sc tok) (angularXsrfCookieName sessionConfig)     return tok   where     ngCookie sc tok k = sc { setCookieName     = k@@ -175,32 +184,31 @@                            , setCookieHttpOnly = False                            } -session :: (Functor n, MonadIO n, Strategy w, Query a) => Session-        -> S.ByteString -> proxy (w a) -> ApiaryT (SNext w as a) n m b -> ApiaryT as n m b+session :: (MonadIO actM, Strategy w, Query a) => Session+        -> S.ByteString -> w a -> ApiaryT exts (SNext w prms a) actM m () -> ApiaryT exts prms actM m () session sess k p = focus (DocPrecondition $ toHtml (show k) <> " session cookie required") $ \l -> do     r   <- getRequest     t   <- liftIO getCurrentTime     let mbr = readStrategy readQuery ((k ==) . fst) p             (map (second $ getSessionValue sess t) $ cookie' r) l-    maybe empty return mbr+    maybe mzero return mbr -checkToken :: (Functor n, MonadIO n)+checkToken :: MonadIO actM            => Session-           -> ApiaryT c n m a-           -> ApiaryT c n m a+           -> ApiaryT exts prms actM m ()+           -> ApiaryT exts prms actM m () checkToken sess@Session{..} = focus (DocPrecondition "CSRF token required") $ \l -> do     r <- getRequest     p <- getReqParams      t <- liftIO getCurrentTime     let stok = getSessionValue sess t =<< -               lookup (csrfTokenCookieName config) (cookie' r)+               lookup (csrfTokenCookieName sessionConfig) (cookie' r)     guard (isJust stok)     -    qtok <- return . join $ case csrfTokenCheckingName config of+    qtok <- return . join $ case csrfTokenCheckingName sessionConfig of         Right name -> lookup name $ reqParams pByteString r p []         Left name  -> lookup name $ map (\(k,v) -> (k, Just v)) $ requestHeaders r     guard (isJust qtok) -    if qtok == stok then return l else empty-+    if qtok == stok then return l else sessionTimeoutAction sessionConfig >> mzero