yesod-auth-hashdb 1.5.1.3 → 1.6
raw patch · 11 files changed
+303/−106 lines, 11 filesdep +aesondep +unordered-containersdep −cryptohash
Dependencies added: aeson, unordered-containers
Dependencies removed: cryptohash
Files
- ChangeLog.md +17/−0
- Yesod/Auth/HashDB.hs +104/−52
- stack.yaml +1/−1
- test/ExampleData.hs +4/−8
- test/IntegrationTest.hs +75/−1
- test/NonDBTests.hs +18/−35
- test/TestSite.hs +24/−4
- test/integration.hs +8/−3
- test/stack.yaml +7/−0
- test/standalone-testsite.cabal +39/−0
- yesod-auth-hashdb.cabal +6/−2
ChangeLog.md view
@@ -1,3 +1,20 @@+## 1.6++This release completes the breaking changes started in 1.5. For details+of upgrading, please see+[Upgrading.md](https://github.com/paul-rouse/yesod-auth-hashdb/blob/master/Upgrading.md).++* Complete removal of compatibility with old databases designed for versions before 1.3+* Add JSON support++## 1.5.1.3++* Fix test failure with basic-prelude >= 0.6 (#6)++## 1.5.1.2++* Relax upper bound to allow persistent-2.6+ ## 1.5.1.1 * Minor documentation improvement
Yesod/Auth/HashDB.hs view
@@ -17,9 +17,8 @@ -- A Yesod authentication plugin designed to look users up in a Persistent -- database where the hash of their password is stored. ----- __Release 1.5 is the first of two which remove compatibility with old__--- __(pre 1.3) databases. Some other deprecated functionality is removed__--- __too. Please see__+-- __Releases 1.6 finishes the process of removing compatibility with old__+-- __(pre 1.3) databases. Please see__ -- __<https://github.com/paul-rouse/yesod-auth-hashdb/blob/master/Upgrading.md>__ -- -- To use this in a Yesod application, the foundation data type must be an@@ -105,6 +104,52 @@ -- included in the widget to add it - see @defaultForm@ in the source -- code of this module for an example. --+-- == JSON Interface+--+-- This plugin provides sufficient tools to build a complete JSON-based+-- authentication flow. We assume that a design goal is to avoid URLs+-- being built into the client, so all of the URLs needed are passed in+-- JSON data.+--+-- To start the process, Yesod's defaultErrorHandler produces a JSON+-- response if the HTTP Accept header gives \"application/json\"+-- precedence over HTML. For a NotAuthenticated error, the status is+-- 401 and the response contains the URL to use for authentication: this+-- is the route which will be handled by the loginHandler method of the+-- YesodAuth instance, which normally returns a login form.+--+-- Leaving the loginHandler aside for a moment, the final step - supported+-- by this plugin since version 1.6 - is to POST the credentials for+-- authentication in a JSON object. This object must include the+-- properties "username" and "password". In the HTML case this would be+-- the form submission, but here we want to use JSON instead.+--+-- In a JSON interface, the purpose of the loginHandler is to tell the+-- client the URL for submitting the credentials. This requires a+-- custom loginHandler, since the default one generates HTML only.+-- It can find the correct URL by using the 'submitRouteHashDB'+-- function defined in this module.+--+-- Writing the loginHandler is made a little messy by the fact that its+-- type allows only HTML content. A work-around is to send JSON as a+-- short-circuit response, but we still make the choice using selectRep+-- so as to get its matching of content types. Here is an example which+-- is geared around using HashDB on its own, supporting both JSON and HTML+-- clients:+--+-- > instance YesodAuth App where+-- > ....+-- > loginHandler = do+-- > submission <- submitRouteHashDB+-- > render <- lift getUrlRender+-- > typedContent@(TypedContent ct _) <- selectRep $ do+-- > provideRepType typeHtml $ return emptyContent+ -- Dummy: the real Html version is at the end+-- > provideJson $ object [("loginUrl", toJSON $ render submission)]+-- > when (ct == typeJson) $+-- > sendResponse typedContent -- Short-circuit JSON response+-- > defaultLoginHandler -- Html response+-- ------------------------------------------------------------------------------- module Yesod.Auth.HashDB ( HashDBUser(..)@@ -117,18 +162,19 @@ , validateUser , authHashDB , authHashDBWithForm+ , submitRouteHashDB ) where #if __GLASGOW_HASKELL__ < 710-import Control.Applicative ((<$>), (<*>))+import Control.Applicative ((<$>), (<*>), pure) #endif-import qualified Crypto.Hash as CH (SHA1, Digest, hash) import Crypto.PasswordStore (makePassword, strengthenPassword, verifyPassword, passwordStrength)+import Data.Aeson ((.:?)) import qualified Data.ByteString.Char8 as BS (pack, unpack) import Data.Maybe (fromMaybe)-import Data.Text (Text, pack, unpack, append)+import Data.Text (Text, pack, unpack) import Yesod.Auth import qualified Yesod.Auth.Message as Msg import Yesod.Core@@ -146,36 +192,23 @@ defaultStrength = 17 -- | The type representing user information stored in the database should--- be an instance of this class. It just provides the getters and setters+-- be an instance of this class. It just provides the getter and setter -- used by the functions in this module. class HashDBUser user where- -- | Retrieve password hash from user data+ -- | Getter used by 'validatePass' and 'upgradePasswordHash' to+ -- retrieve the password hash from user data+ -- userPasswordHash :: user -> Maybe Text- -- | Retrieve salt for password from user data. This is needed only for- -- compatibility with old database entries, which contain the salt- -- as a separate field. New implementations do not require a separate- -- salt field in the user data, and should leave this as the default.- userPasswordSalt :: user -> Maybe Text- userPasswordSalt _ = Just "" - -- | Callback for 'setPassword' and 'upgradePasswordHash'. Produces a+ -- | Setter used by 'setPassword' and 'upgradePasswordHash'. Produces a -- version of the user data with the hash set to the new value. -- setPasswordHash :: Text -- ^ Password hash -> user -> user {-# MINIMAL userPasswordHash, setPasswordHash #-}-{-# DEPRECATED userPasswordSalt "Verification against old data containing a separate salt field will be removed in version 1.6" #-} --- | Calculate salted hash using SHA1. Retained for compatibility with--- hashes in existing databases, but will not be used for new passwords.-saltedHash :: Text -- ^ Salt- -> Text -- ^ Password- -> Text-saltedHash salt pw =- pack $ show (CH.hash $ BS.pack $ unpack $ append salt pw :: CH.Digest CH.SHA1)- -- | Calculate a new-style password hash using "Crypto.PasswordStore". passwordHash :: MonadIO m => Int -> Text -> m Text passwordHash strength pwd = do@@ -200,11 +233,6 @@ setPassword = setPasswordStrength defaultStrength -- | Validate a plaintext password against the hash in the user data structure.--- This function retains compatibility with user data produced by old--- versions of this module (prior to 1.3), although the hashes are less--- secure and should be upgraded as soon as possible. They can be--- upgraded using 'upgradePasswordHash', or by insisting that users set--- new passwords. -- -- The result distinguishes two types of validation failure, which may -- be useful in an application which supports multiple authentication@@ -213,27 +241,24 @@ -- * Just False - the user has a password set up, but the given one does -- not match it ----- * Nothing - the user does not have a password (the hash is Nothing)+-- * Nothing - the user does not have a password ('userPasswordHash' returns+-- Nothing) -- -- Since 1.4.1 -- validatePass :: HashDBUser u => u -> Text -> Maybe Bool validatePass user passwd = do hash <- userPasswordHash user- salt <- userPasswordSalt user- -- NB plaintext password characters are truncated to 8 bits here, and also- -- in saltedHash and passwordHash above (the hash and old salt are already- -- 8 bit). This is for historical compatibility, but in practice it is+ -- NB plaintext password characters are truncated to 8 bits here,+ -- and also in passwordHash above (the hash is already 8 bit).+ -- This is for historical compatibility, but in practice it is -- unlikely to reduce the entropy of most users' alphabets by much. let hash' = BS.pack $ unpack hash- passwd' = BS.pack $ unpack $ if salt == "" then passwd- else- -- Extra layer for an upgraded old hash- saltedHash salt passwd+ passwd' = BS.pack $ unpack passwd if passwordStrength hash' > 0- -- Will give >0 for new-style hash, else fall back+ -- Will give >0 for valid hash format, else treat as if wrong password then return $ verifyPassword passwd' hash'- else return $ hash == saltedHash salt passwd+ else return False -- | Upgrade existing user credentials to a stronger hash. The existing -- hash will have been produced from a weaker setting in the current@@ -246,25 +271,21 @@ -- but may have been upgraded using earlier versions of this function. -- -- Returns Nothing if the user has no password (ie if 'userPasswordHash' u--- is 'Nothing'), if the password hash is not in the new format, or if the--- user has a non-empty salt field resulting from the old-style hashing--- algorithm.+-- is 'Nothing') or if the password hash is not in the correct format.+-- upgradePasswordHash :: (MonadIO m, HashDBUser user) => Int -> user -> m (Maybe user) upgradePasswordHash strength u = do let old = userPasswordHash u- oldSalt = fromMaybe "" $ userPasswordSalt u case old of Just oldHash -> do let oldHash' = BS.pack $ unpack oldHash if passwordStrength oldHash' > 0 then- -- Already a new-style hash, so only strengthen it as needed+ -- Valid hash format, so strengthen it as needed let newHash = pack $ BS.unpack $ strengthenPassword oldHash' strength- in if oldSalt == ""- then return $ Just $ setPasswordHash newHash u- else return Nothing -- Can't handle non-empty salt+ in return $ Just $ setPasswordHash newHash u else do- -- Old-style hash: cannot upgrade+ -- Invalid hash format (perhaps from old version of this module) return Nothing Nothing -> return Nothing @@ -288,6 +309,15 @@ , PersistEntity user ) +-- Internal data type for receiving JSON encoded username and password+data UserPass = UserPass (Maybe Text) (Maybe Text)++instance FromJSON UserPass where+ parseJSON (Object v) = UserPass <$>+ v .:? "username" <*>+ v .:? "password"+ parseJSON _ = pure $ UserPass Nothing Nothing+ -- | Given a user ID and password in plaintext, validate them against -- the database values. This function simply looks up the user id in the -- database and calls 'validatePass' to do the work.@@ -308,13 +338,21 @@ -- | Handle the login form. First parameter is function which maps -- username (whatever it might be) to unique user ID.+--+-- Since version 1.6, the data may be submitted as a JSON object.+-- See the \"JSON Interface\" section above for more details. postLoginR :: HashDBPersist site user => (Text -> Maybe (Unique user)) -> HandlerT Auth (HandlerT site IO) TypedContent postLoginR uniq = do- (mu,mp) <- lift $ runInputPost $ (,)- <$> iopt textField "username"- <*> iopt textField "password"+ ct <- lookupHeader "Content-Type"+ let jsonContent = ((== "application/json") . simpleContentType) <$> ct+ UserPass mu mp <-+ case jsonContent of+ Just True -> requireJsonBody+ _ -> lift $ runInputPost $ UserPass+ <$> iopt textField "username"+ <*> iopt textField "password" isValid <- lift $ fromMaybe (return False) (validateUser <$> (uniq =<< mu) <*> mp)@@ -386,3 +424,17 @@ } |]+++-- | The route, in the parent site, to which the username and password+-- should be sent in order to log in. This function is particularly+-- useful in constructing a 'loginHandler' function which provides a+-- JSON response. See the \"JSON Interface\" section above for more+-- details.+--+-- Since 1.6+submitRouteHashDB :: YesodAuth site =>+ HandlerT Auth (HandlerT site IO) (Route site)+submitRouteHashDB = do+ toParent <- getRouteToParent+ return $ toParent login
stack.yaml view
@@ -1,4 +1,4 @@-resolver: lts-5.4+resolver: lts-6.6 packages: - . extra-deps: []
test/ExampleData.hs view
@@ -12,13 +12,16 @@ oldStyleUpgradedUser, newStyleValidUser, newStyleBadUser,- newStyleInOldFormat, stronger ) where import Yesod.Auth.HashDB (HashDBUser(..), defaultStrength) import Data.Text (Text) +-- OldStyleUser is retained in the tests so that naive (incorrect)+-- upgrading can be tested; the naive upgrade consists of removing+-- the `userPasswordSalt` method without setting new passwords which+-- have empty salt. data OldStyleUser = OldStyleUser { oldStyleName :: Text, oldStylePass :: Maybe Text,@@ -27,7 +30,6 @@ instance HashDBUser OldStyleUser where userPasswordHash = oldStylePass- userPasswordSalt = oldStyleSalt setPasswordHash h u = u { oldStyleSalt = Just "", oldStylePass = Just h }@@ -85,12 +87,6 @@ newStyleBadUser = NewStyleUser "bad" Nothing--newStyleInOldFormat :: OldStyleUser-newStyleInOldFormat =- OldStyleUser "fox"- (Just "sha256|14|2hL7cNopkA/dGy/5CQTuSg==|CUTPW6ICMISSjohFep851f9PdqIn7Y4B75/I77BvEYM=")- (Just "") stronger :: Int stronger = defaultStrength + 2
test/IntegrationTest.hs view
@@ -8,6 +8,9 @@ ) where import BasicPrelude+import Data.Aeson (FromJSON, parseJSON, (.:))+import qualified Data.Aeson as JSON+import Network.Wai.Test (simpleBody) import Test.Hspec (Spec, SpecWith, before, describe, context, it) import qualified Yesod.Test as YT@@ -25,6 +28,37 @@ withApp app = before $ return app #endif +authUrl :: Text+authUrl = "http://localhost:3000/auth/login"++data AuthUrl = AuthUrl Text deriving Eq+instance FromJSON AuthUrl where+ parseJSON (JSON.Object v) = AuthUrl <$> v .: "authentication_url"+ parseJSON _ = mempty++loginUrl :: Text+loginUrl = "http://localhost:3000/auth/page/hashdb/login"++data LoginUrl = LoginUrl Text deriving Eq+instance FromJSON LoginUrl where+ parseJSON (JSON.Object v) = LoginUrl <$> v .: "loginUrl"+ parseJSON _ = mempty++successMsg :: Text+successMsg = "Login Successful"++data SuccessMsg = SuccessMsg Text deriving Eq+instance FromJSON SuccessMsg where+ parseJSON (JSON.Object v) = SuccessMsg <$> v .: "message"+ parseJSON _ = mempty++getBodyJSON :: FromJSON a => YT.YesodExample site (Maybe a)+getBodyJSON = do+ resp <- YT.getResponse+ let body = simpleBody <$> resp+ result = JSON.decode =<< body+ return result+ integrationSpec :: SpecWith MyTestApp integrationSpec = do describe "The home page" $ do@@ -70,5 +104,45 @@ loc <- doLoginPart1 "paul" "WrongPassword" checkFailedLogin loc it "fails when unknown user name given" $ do- loc <- doLoginPart1 "paul" "WrongPassword"+ loc <- doLoginPart1 "xyzzy" "WrongPassword" checkFailedLogin loc++ describe "JSON Login" $ do+ it "JSON access to protected page gives JSON object with auth URL" $ do+ YT.request $ do+ YT.setMethod "GET"+ YT.setUrl ProtectedR+ YT.addRequestHeader ("Accept", "application/json")+ YT.statusIs 401+ auth <- getBodyJSON+ YT.assertEqual "Authentication URL" auth (Just $ AuthUrl authUrl)+ it "Custom loginHandler using submitRouteHashDB has correct URL in JSON" $ do+ YT.request $ do+ YT.setMethod "GET"+ YT.setUrl authUrl+ YT.addRequestHeader ("Accept", "application/json")+ YT.statusIs 200+ login <- getBodyJSON+ YT.assertEqual "Login URL" login (Just $ LoginUrl loginUrl)+#if MIN_VERSION_yesod_test(1,5,0)+ -- Disable this example for yesod-test < 1.5.0.1, since it uses the wrong+ -- content type for JSON (https://github.com/yesodweb/yesod/issues/1063).+ it "Sending JSON username and password produces JSON success message" $ do+ -- This first request is only to get the CSRF token cookie, used below+ YT.request $ do+ YT.setMethod "GET"+ YT.setUrl authUrl+ YT.addRequestHeader ("Accept", "application/json")+ YT.request $ do+ YT.setMethod "POST"+ YT.setUrl loginUrl+ YT.addRequestHeader ("Accept", "application/json")+ YT.addRequestHeader ("Content-Type", "application/json; charset=utf-8")+ YT.setRequestBody "{\"username\":\"paul\",\"password\":\"MyPassword\"}"+ -- CSRF token is being checked, since yesod-core >= 1.4.14 is a+ -- dependency of yesod-test >= 1.5 on which this item is conditional.+ YT.addTokenFromCookie+ YT.statusIs 200+ msg <- getBodyJSON+ YT.assertEqual "Login success" msg (Just $ SuccessMsg successMsg)+#endif
test/NonDBTests.hs view
@@ -17,23 +17,23 @@ describe "validatePass" $ do - context "Old-style valid user" $ do- it "verifies OK with correct password" $- validatePass oldStyleValidUser mypassword `shouldBe` Just True- it "fails validation with a wrong password giving Just False" $+ context "Naively upgraded old-style valid user" $ do+ it "no longer checks good password (wrong format, so Just False)" $+ validatePass oldStyleValidUser mypassword `shouldBe` Just False+ it "no longer checks bad password (wrong format, so Just False)" $ validatePass oldStyleValidUser changedpw `shouldBe` Just False - context "Old-style user with no password hash" $ do+ context "Naively upgraded old-style user with no password hash" $ do it "fails validation giving Nothing" $ validatePass oldStyleBadUser1 mypassword `shouldBe` Nothing - context "Old-style user with no salt" $ do- it "fails validation giving Nothing" $- validatePass oldStyleBadUser2 mypassword `shouldBe` Nothing+ context "Naively upgraded old-style user with no salt" $ do+ it "fails validation (wrong format, so Just False)" $+ validatePass oldStyleBadUser2 mypassword `shouldBe` Just False context "Previously upgraded old-style user" $ do- it "verifies OK with correct password" $- validatePass oldStyleUpgradedUser mypassword `shouldBe` Just True+ it "no longer verifies with correct password as it still needs salt" $+ validatePass oldStyleUpgradedUser mypassword `shouldBe` Just False it "fails validation with a wrong password giving Just False" $ validatePass oldStyleUpgradedUser changedpw `shouldBe` Just False @@ -47,27 +47,23 @@ it "fails validation giving Nothing" $ validatePass newStyleBadUser mypassword `shouldBe` Nothing - context "New-style hash in old-style format with blank salt" $ do- it "verifies OK with correct password" $- validatePass newStyleInOldFormat mypassword `shouldBe` Just True- it "fails validation with a wrong password giving Just False" $- validatePass newStyleInOldFormat changedpw `shouldBe` Just False - describe "upgradePasswordHash" $ do - context "Upgrade of old-style password hash" $ do- it "is Nothing if the user has a valid password hash" $ do+ context "Upgrade of naively upgraded old-style password hash" $ do+ it "is Nothing if the user has a password (format is wrong)" $ do newuser <- upgradePasswordHash defaultStrength oldStyleValidUser newuser `shouldBe` Nothing- it "is Nothing if there is no password hash (but salt non-empty)" $ do+ it "is Nothing if there is no password hash" $ do newuser <- upgradePasswordHash defaultStrength oldStyleBadUser1 newuser `shouldBe` Nothing context "Upgrade of previously upgraded old-style user" $ do- it "is Nothing since salt is non-empty" $ do+ it "silently succeeds producing a password which won't verify as it still needs salt" $ do newuser <- upgradePasswordHash defaultStrength oldStyleUpgradedUser- newuser `shouldBe` Nothing+ case newuser of+ Nothing -> expectationFailure "should not produce Nothing"+ Just u -> validatePass u mypassword `shouldBe` Just False context "Upgrade of new-style password hash to stronger setting" $ do it "really does have a hash containing the new strength" $ do@@ -83,33 +79,20 @@ newuser <- upgradePasswordHash stronger newStyleBadUser newuser `shouldBe` Nothing - context "Upgrade of new-style hash in old-style format with blank salt" $ do- it "really does have a hash containing the new strength" $ do- newuser <- upgradePasswordHash stronger newStyleInOldFormat- let s = pack $ "|" ++ show stronger ++ "|"- found = fmap (s `isInfixOf`) $ newuser >>= oldStylePass- found `shouldBe` Just True- it "still verifies with the same password" $ do- newuser <- upgradePasswordHash stronger newStyleInOldFormat- let valid = newuser >>= flip validatePass mypassword- valid `shouldBe` Just True - describe "setPassword" $ do it "produces hash which verifies OK starting from old-style user" $ do newuser <- setPassword changedpw oldStyleValidUser validatePass newuser changedpw `shouldBe` Just True it "produces empty salt (in the case of old-style user)" $ do newuser <- setPassword changedpw oldStyleValidUser- userPasswordSalt newuser `shouldBe` Just ""+ oldStyleSalt newuser `shouldBe` Just "" it "produces hash which verifies OK starting from new-style user" $ do newuser <- setPassword changedpw newStyleValidUser validatePass newuser changedpw `shouldBe` Just True describe "Only the bottom 8 bits of password characters are used" $ do- it "when verifying old-style password hash" $- validatePass oldStyleValidUser equivpassword `shouldBe` Just True it "when verifying new-style password hash" $ validatePass newStyleValidUser equivpassword `shouldBe` Just True it "when setting a new password" $ do
test/TestSite.hs view
@@ -23,16 +23,25 @@ import Control.Applicative ((<$>)) import Data.Typeable (Typeable) #endif+import Control.Monad (when) import Data.Text import Database.Persist.Sqlite import Network.HTTP.Client.Conduit (Manager) import Yesod import Yesod.Auth-import Yesod.Auth.HashDB (HashDBUser(..), authHashDB)+import Yesod.Auth.HashDB (HashDBUser(..), authHashDB,+ submitRouteHashDB) import Yesod.Auth.Message (AuthMessage (InvalidLogin))-#if MIN_VERSION_yesod_core(1,4,14)-import Yesod.Core (defaultCsrfMiddleware,- defaultYesodMiddleware)++#if ! MIN_VERSION_yesod_auth(1,4,9)+import Yesod.Auth.Message (AuthMessage (LoginTitle))+defaultLoginHandler :: AuthHandler master Html+defaultLoginHandler = do+ tp <- getRouteToParent+ lift $ authLayout $ do+ setTitleI LoginTitle+ master <- getYesod+ mapM_ (flip apLogin tp) (authPlugins master) #endif @@ -104,6 +113,17 @@ authPlugins _ = [ authHashDB (Just . UniqueUser) ] authHttpManager = appHttpManager++ loginHandler = do+ submission <- submitRouteHashDB+ render <- lift getUrlRender+ typedContent@(TypedContent ct _) <- selectRep $ do+ provideRepType typeHtml $ return emptyContent+ -- Dummy: the real Html version is at the end+ provideJson $ object [("loginUrl", toJSON $ render submission)]+ when (ct == typeJson) $+ sendResponse typedContent -- Short-circuit JSON response+ defaultLoginHandler -- Html response instance YesodAuthPersist App
test/integration.hs view
@@ -9,7 +9,9 @@ import Yesod import Yesod.Auth.HashDB (setPassword) +#ifndef STANDALONE import IntegrationTest+#endif import TestSite main :: IO ()@@ -19,7 +21,10 @@ validUser <- setPassword "MyPassword" $ User "paul" Nothing insert_ validUser mgr <- newManager- -- To try this as a server, replace the `hspec` line below with this one,- -- and remove the import of IntegrationTest above.- -- warp 3000 $ App mgr conn+#ifdef STANDALONE+ -- Run as a stand-alone server - see the cabal file in this directory+ warp 3000 $ App mgr conn+#else+ -- Otherwise run the tests hspec $ withApp (App mgr conn) integrationSpec+#endif
+ test/stack.yaml view
@@ -0,0 +1,7 @@+# Used for building standalone-testsite+packages:+- ..+- .+extra-deps: []+resolver: lts-6.6+compiler-check: newer-minor
+ test/standalone-testsite.cabal view
@@ -0,0 +1,39 @@+name: standalone-testsite+version: 0.1.1+license: MIT+author: Paul Rouse+maintainer: Paul Rouse <pyr@doynton.org>+synopsis: Stand-alone version of test for Yesod.Auth.HashDB+category: Web, Yesod+stability: Stable+cabal-version: >= 1.8.0+build-type: Simple+homepage: https://github.com/paul-rouse/yesod-auth-hashdb+bug-reports: https://github.com/paul-rouse/yesod-auth-hashdb/issues+description:+ Stand-alone integration test for Yesod.Auth.HashDB, run as a server.+ .+ Normally the integration test is run using Yesod.Test. However, it+ may be handy to build the example server as a stand-alone application+ and debug it. To do so, use this cabal file and the accompanying+ stack.yaml. TestSite.hs needs MIN_VERSION_yesod_test, so a dummy+ is provided here. STANDALONE is used in integration.hs to replace+ the tests with code which uses warp to make a server.++executable integration+ main-is: integration.hs+ hs-source-dirs: .+ ghc-options: -Wall+ cpp-options: -DMIN_VERSION_yesod_test(a,b,c)=1 -DSTANDALONE+ other-modules: TestSite+ build-depends: base >= 4 && < 5+ , hspec+ , http-conduit+ , monad-logger+ , persistent-sqlite+ , resourcet+ , text+ , yesod+ , yesod-auth+ , yesod-auth-hashdb+ , yesod-core
yesod-auth-hashdb.cabal view
@@ -1,5 +1,5 @@ name: yesod-auth-hashdb-version: 1.5.1.3+version: 1.6 license: MIT license-file: LICENSE author: Patrick Brisbin, later changes Paul Rouse@@ -28,6 +28,8 @@ if you wish to use email verification to set up accounts). extra-source-files: ChangeLog.md stack.yaml+ test/stack.yaml+ test/standalone-testsite.cabal library build-depends: base >= 4 && < 5@@ -39,7 +41,7 @@ , persistent >= 2.1 && < 2.7 , yesod-form >= 1.4 && < 1.5 , pwstore-fast >= 2.2- , cryptohash >= 0.8+ , aeson exposed-modules: Yesod.Auth.HashDB ghc-options: -Wall@@ -65,6 +67,7 @@ , TestSite , TestTools build-depends: base >= 4 && < 5+ , aeson , bytestring , basic-prelude , containers@@ -76,6 +79,7 @@ , persistent-sqlite , resourcet , text+ , unordered-containers , wai-extra , yesod , yesod-auth