users 0.1.0.0 → 0.2.0.1
raw patch · 2 files changed
+61/−9 lines, 2 filesdep +bcryptdep ~aeson
Dependencies added: bcrypt
Dependency ranges changed: aeson
Files
- src/Web/Users/Types.hs +58/−7
- users.cabal +3/−2
src/Web/Users/Types.hs view
@@ -3,15 +3,32 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleContexts #-}-module Web.Users.Types where+module Web.Users.Types+ ( -- * The core type class+ UserStorageBackend (..)+ -- * User representation+ , User(..), Password(..), makePassword, hidePassword+ , PasswordPlain(..), verifyPassword+ -- * Token types+ , PasswordResetToken(..), ActivationToken(..), SessionId(..)+ -- * Error types+ , CreateUserError(..), UpdateUserError(..)+ , TokenError(..)+ )+where import Control.Applicative+import Crypto.BCrypt import Data.Aeson import Data.Int+import Data.Maybe+import Data.String import Data.Time.Clock import Data.Typeable import Web.PathPieces import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified System.IO.Unsafe as U -- | Errors that happen on storage level during user creation data CreateUserError@@ -64,7 +81,7 @@ -- | Delete a user deleteUser :: b -> UserId b -> IO () -- | Authentificate a user using username/email and password. The 'NominalDiffTime' describes the session duration- authUser :: b -> T.Text -> T.Text -> NominalDiffTime -> IO (Maybe SessionId)+ authUser :: b -> T.Text -> PasswordPlain -> NominalDiffTime -> IO (Maybe SessionId) -- | Verify a 'SessionId'. The session duration can be extended by 'NominalDiffTime' verifySession :: b -> SessionId -> NominalDiffTime -> IO (Maybe (UserId b)) -- | Destroy a session@@ -74,7 +91,7 @@ -- | Check if a 'PasswordResetToken' is still valid and retrieve the owner of it verifyPasswordResetToken :: (FromJSON a, ToJSON a) => b -> PasswordResetToken -> IO (Maybe (User a)) -- | Apply a new password to the owner of 'PasswordResetToken' iff the token is still valid- applyNewPassword :: b -> PasswordResetToken -> T.Text -> IO (Either TokenError ())+ applyNewPassword :: b -> PasswordResetToken -> Password -> IO (Either TokenError ()) -- | Request an 'ActivationToken' for a given user, valid for 'NominalDiffTime' requestActivationToken :: b -> UserId b -> NominalDiffTime -> IO ActivationToken -- | Activate the owner of 'ActivationToken' iff the token is still valid@@ -95,13 +112,47 @@ = SessionId { unSessionId :: T.Text } deriving (Show, Eq, ToJSON, FromJSON, Typeable, PathPiece) --- | Password representation. When updating or creating a user, set to 'PasswordPlain'+-- | Construct a password from plaintext by hashing it+makePassword :: PasswordPlain -> Password+makePassword (PasswordPlain plainText) =+ let hash =+ T.decodeUtf8 $ fromJustPass $ U.unsafePerformIO $+ hashPasswordUsingPolicy policy (T.encodeUtf8 plainText)+ in PasswordHash hash+ where+ policy =+ HashingPolicy+ { preferredHashCost = 8+ , preferredHashAlgorithm = "$2b$"+ }+ fromJustPass =+ fromMaybe (error "makePassword failed. This is probably a bcrypt library error")++-- | Check a plaintext password against a password+verifyPassword :: PasswordPlain -> Password -> Bool+verifyPassword (PasswordPlain plainText) pwd =+ case pwd of+ PasswordHidden -> False+ PasswordHash hash ->+ validatePassword (T.encodeUtf8 hash) (T.encodeUtf8 plainText)++-- | Plaintext passsword. Used for authentification.+newtype PasswordPlain+ = PasswordPlain { unPasswordPlain :: T.Text }+ deriving (Show, Eq, Typeable, IsString)++-- | Password representation. When updating or creating a user, use 'makePassword' to create one.+-- The implementation details of this type are ONLY for use in backend implementations. data Password- = PasswordPlain !T.Text- | PasswordHash !T.Text+ = PasswordHash !T.Text | PasswordHidden deriving (Show, Eq, Typeable) +-- | Strip the password from the user type.+hidePassword :: User a -> User a+hidePassword user =+ user { u_password = PasswordHidden }+ -- | Core user datatype. Store custom information in the 'u_more' field data User a = User@@ -133,4 +184,4 @@ parsePassword maybePass = case maybePass of Nothing -> PasswordHidden- Just pwd -> PasswordPlain pwd+ Just pwd -> makePassword (PasswordPlain pwd)
users.cabal view
@@ -1,5 +1,5 @@ name: users-version: 0.1.0.0+version: 0.2.0.1 synopsis: A library simplifying user management for web applications description: Scrap the boilerplate for managing user accounts in web applications .@@ -37,8 +37,9 @@ library exposed-modules: Web.Users.Types build-depends:- aeson >=0.8,+ aeson >=0.7, base >=4.6 && <5,+ bcrypt >=0.0.6, path-pieces >=0.1, text >=1.2, time >=1.4