packages feed

yesod-test 1.4.3.1 → 1.4.4

raw patch · 4 files changed

+126/−3 lines, 4 filesdep ~yesod-core

Dependency ranges changed: yesod-core

Files

ChangeLog.md view
@@ -1,3 +1,12 @@+## 1.4.4++test helpers for CRSF middleware such as addTokenFromCookie++## 1.4.3.2++* Add `addTokenFromCookie` and `addTokenFromCookieNamedToHeaderNamed`, which support the new CSRF token middleware [#1058](https://github.com/yesodweb/yesod/pull/1058)+* Add `getRequestCookies`, which returns the cookies from the most recent request [#1058](https://github.com/yesodweb/yesod/pull/1058)+ ## 1.4.3.1  * Improved README
Yesod/Test.hs view
@@ -77,6 +77,8 @@     , addToken_     , addNonce     , addNonce_+    , addTokenFromCookie+    , addTokenFromCookieNamedToHeaderNamed      -- * Assertions     , assertEqual@@ -93,6 +95,7 @@     -- * Grab information     , getTestYesod     , getResponse+    , getRequestCookies      -- * Debug output     , printBody@@ -133,6 +136,7 @@ import qualified Web.Cookie as Cookie import qualified Blaze.ByteString.Builder as Builder import Data.Time.Clock (getCurrentTime)+import Control.Applicative ((<$>))  -- | The state used in a single test case defined using 'yit' --@@ -589,6 +593,65 @@ addToken :: RequestBuilder site () addToken = addToken_ "" +-- | Calls 'addTokenFromCookieNamedToHeaderNamed' with the 'defaultCsrfCookieName' and 'defaultCsrfHeaderName'.+--+-- Use this function if you're using the CSRF middleware from "Yesod.Core" and haven't customized the cookie or header name.+--+-- ==== __Examples__+--+-- > request $ do+-- >   addTokenFromCookie+--+-- Since 1.4.3.2+addTokenFromCookie :: RequestBuilder site ()+addTokenFromCookie = addTokenFromCookieNamedToHeaderNamed defaultCsrfCookieName defaultCsrfHeaderName++-- | Looks up the CSRF token stored in the cookie with the given name and adds it to the request headers. An error is thrown if the cookie can't be found.+--+-- Use this function if you're using the CSRF middleware from "Yesod.Core" and have customized the cookie or header name.+--+-- See "Yesod.Core.Handler" for details on this approach to CSRF protection.+--+-- ==== __Examples__+--+-- > import Data.CaseInsensitive (CI)+-- > request $ do+-- >   addTokenFromCookieNamedToHeaderNamed "cookieName" (CI "headerName")+--+-- Since 1.4.3.2+addTokenFromCookieNamedToHeaderNamed :: ByteString -- ^ The name of the cookie+                                     -> CI ByteString -- ^ The name of the header+                                     -> RequestBuilder site ()+addTokenFromCookieNamedToHeaderNamed cookieName headerName = do+  cookies <- getRequestCookies+  case M.lookup cookieName cookies of+        Just csrfCookie -> addRequestHeader (headerName, Cookie.setCookieValue csrfCookie)+        Nothing -> failure $ T.concat+          [ "addTokenFromCookieNamedToHeaderNamed failed to lookup CSRF cookie with name: "+          , T.pack $ show cookieName+          , ". Cookies were: "+          , T.pack $ show cookies+          ]++-- | Returns the 'Cookies' from the most recent request. If a request hasn't been made, an error is raised.+--+-- ==== __Examples__+--+-- > request $ do+-- >   cookies <- getRequestCookies+-- >   liftIO $ putStrLn $ "Cookies are: " ++ show cookies+--+-- Since 1.4.3.2+getRequestCookies :: RequestBuilder site Cookies+getRequestCookies = do+  requestBuilderData <- ST.get+  headers <- case simpleHeaders <$> rbdResponse requestBuilderData of+                  Just h -> return h+                  Nothing -> failure "getRequestCookies: No request has been made yet; the cookies can't be looked up."++  return $ M.fromList $ map (\c -> (Cookie.setCookieName c, c)) (parseSetCookies headers)++ -- | Perform a POST request to @url@. -- -- ==== __Examples__@@ -759,7 +822,7 @@             { httpVersion = H.http11             }         }) app-    let newCookies = map (Cookie.parseSetCookie . snd) $ DL.filter (("Set-Cookie"==) . fst) $ simpleHeaders response+    let newCookies = parseSetCookies $ simpleHeaders response         cookies' = M.fromList [(Cookie.setCookieName c, c) | c <- newCookies] `M.union` cookies     ST.put $ YesodExampleData app site cookies' (Just response)   where@@ -845,6 +908,10 @@       , rawQueryString = H.renderQuery False urlQuery       , queryString = urlQuery       }+++parseSetCookies :: [H.Header] -> [Cookie.SetCookie]+parseSetCookies headers = map (Cookie.parseSetCookie . snd) $ DL.filter (("Set-Cookie"==) . fst) $ headers  -- Yes, just a shortcut failure :: (MonadIO a) => T.Text -> a b
test/main.hs view
@@ -2,6 +2,10 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE CPP #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TypeFamilies #-}+ import Test.HUnit hiding (Test) import Test.Hspec @@ -166,7 +170,27 @@             statusIs 200             printBody             bodyContains "Foo"+    describe "CSRF with cookies/headers" $ yesodSpec CsrfApp $ do+        yit "Should receive a CSRF cookie and add its value to the headers" $ do+            get ("/" :: Text)+            statusIs 200 +            request $ do+                setMethod "POST"+                setUrl ("/" :: Text)+                addTokenFromCookie+            statusIs 200+        yit "Should 403 requests if we don't add the CSRF token" $ do+            get ("/" :: Text)+            statusIs 200++            request $ do+                setMethod "POST"+                setUrl ("/" :: Text)+            statusIs 403+++ instance RenderMessage LiteApp FormMessage where     renderMessage _ _ = defaultFormMessage @@ -210,3 +234,26 @@             setMessage "Foo"             redirect ("/cookie/home" :: Text)             return ()++data CsrfApp = CsrfApp++mkYesod "CsrfApp" [parseRoutes|+/ HomeR GET POST+|]++instance Yesod CsrfApp where+    yesodMiddleware = defaultYesodMiddleware . defaultCsrfMiddleware++getHomeR :: Handler Html+getHomeR = defaultLayout+    [whamlet|+        <p>+            Welcome to my test application.+    |]++postHomeR :: Handler Html+postHomeR = defaultLayout+    [whamlet|+        <p>+            Welcome to my test application.+    |]
yesod-test.cabal view
@@ -1,5 +1,5 @@ name:               yesod-test-version:            1.4.3.1+version:            1.4.4 license:            MIT license-file:       LICENSE author:             Nubis <nubis@woobiz.com.ar>@@ -37,7 +37,7 @@                    , time                    , blaze-builder                    , cookie-                   , yesod-core                >= 1.4+                   , yesod-core                >= 1.4.14      exposed-modules: Yesod.Test                      Yesod.Test.CssQuery