-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Authentication plugin for Yesod.
--   
--   This package is the Yesod.Auth.HashDB plugin, originally included as
--   part of yesod-auth, but now modified to be more secure and placed in a
--   separate package.
--   
--   It provides authentication using hashed passwords stored in a
--   database, and works best in situations where an administrator is
--   involved in setting up a user with an initial password.
--   
--   The complete login process, including a default form, is implemented
--   by this plugin, but the application developer must design the
--   interfaces for setting up users and allowing them to change their own
--   passwords, since only the low-level password-setting functions are
--   provided by this package. (Note that other authentication plugins may
--   be more appropriate if you wish to use email verification to set up
--   accounts).
@package yesod-auth-hashdb
@version 1.4.2.2


-- | A yesod-auth AuthPlugin designed to look users up in a Persistent
--   database where the hash of their password is stored.
--   
--   This module was removed from <tt>yesod-auth-1.3.0.0</tt> and is now
--   maintained separately. Versions of this module prior to
--   <tt>yesod-auth-1.3</tt> used a relatively weak hashing algorithm (a
--   single round of SHA1) which does not provide adequate protection
--   against an attacker who discovers the hashed passwords. See:
--   <a>https://github.com/yesodweb/yesod/issues/668</a>.
--   
--   It has now been rewritten to use <a>Crypto.PasswordStore</a>, but this
--   has been done in a way which preserves compatibility both with the API
--   and with databases which have been set up using older versions of this
--   module. There are two levels of database compatibility:
--   
--   <ul>
--   <li>The verification code recognises both the old and new hash
--   formats, so passwords can be verified against database entries which
--   still contain old-style hashes.</li>
--   <li>The function <a>upgradePasswordHash</a> can be used to migrate
--   existing user records to use the new format hash. Unlike freshly
--   created password hashes, entries converted this way must still have
--   the old salt field, since the old hash function remains part of the
--   algorithm needed for verification. (The new hash is layered on top of
--   the old one.)</li>
--   </ul>
--   
--   On the other hand, new passwords set up by <a>setPassword</a> or
--   <a>setPasswordStrength</a> no longer use a separate salt field, so new
--   users of this module need only provide a single password field in the
--   user data, and can ignore the salt.
--   
--   In a system which has been migrated from the old format, passwords
--   which are reset will use the new format and will have an empty salt
--   field. Once all the entries are of this form, it is safe to change the
--   model to remove the salt, and change the <a>HashDBUser</a> instance
--   accordingly.
--   
--   To use this in a Yesod application, the foundation data type must be
--   an instance of YesodPersist, and the username and hashed passwords
--   should be added to the database. The following steps give an outline
--   of what is required.
--   
--   You need a database table to store user records: in a scaffolded site
--   it might look like:
--   
--   <pre>
--   User
--       name Text             -- user name used to uniquely identify users
--       password Text Maybe   -- password hash for HashDB
--       UniqueUser name
--   </pre>
--   
--   Create an instance of <a>HashDBUser</a> for this data type. For
--   historical reasons <a>Yesod.Auth.HashDB</a> exports some names which
--   are quite likely to clash with your own, so it is a good idea to
--   import just the ones you need:
--   
--   <pre>
--   import Yesod.Auth.HashDB (HashDBUser(..))
--   ....
--   instance HashDBUser User where
--       userPasswordHash = userPassword
--       setPasswordHash h u = u { userPassword = Just h }
--   </pre>
--   
--   In the YesodAuth instance declaration for your app, include
--   <a>authHashDB</a> like so:
--   
--   <pre>
--   import Yesod.Auth.HashDB (authHashDB)
--   ....
--   instance YesodAuth App where
--       ....
--       authPlugins _ = [ authHashDB (Just . UniqueUser), .... ]
--       getAuthId creds = ... -- Perhaps modify scaffolding: see below
--   </pre>
--   
--   The argument to <a>authHashDB</a> is a function which takes a
--   <a>Text</a> and produces a <a>Maybe</a> containing a <a>Unique</a>
--   value to look up in the User table. The example <tt>(Just .
--   UniqueUser)</tt> shown here works for the model outlined above.
--   
--   In the scaffolding, the definition of <tt>getAuthId</tt> contains code
--   to add a user who is not already in the database. Depending on how
--   users are administered, this may not make sense when using HashDB, so
--   consider whether it should be removed.
--   
--   For a real application, the developer should provide some sort of of
--   administrative interface for setting passwords; it needs to call
--   <a>setPassword</a> and save the result in the database. However, if
--   you need to initialise the database by hand, you can generate the
--   correct password hash as follows:
--   
--   <pre>
--   ghci -XOverloadedStrings
--   &gt; import Crypto.PasswordStore
--   &gt; makePassword "MyPassword" 17
--   </pre>
--   
--   where "17" is the default strength parameter (<a>defaultStrength</a>)
--   used in this module.
--   
--   <h2>Custom Login Form</h2>
--   
--   Instead of using the built-in HTML form, a custom one can be supplied
--   by using <a>authHashDBWithForm</a> instead of <a>authHashDB</a>.
--   
--   The custom form needs to be given as a function returning a Widget,
--   since it has to build in the supplied "action" URL, and it must
--   provide two text fields called "username" and "password". For example,
--   the following modification of the outline code given above would
--   replace the default form with a very minimal one which has no labels
--   and a simple layout.
--   
--   <pre>
--   instance YesodAuth App where
--       ....
--       authPlugins _ = [ authHashDBWithForm myform (Just . UniqueUser), .... ]
--   
--   myform :: Route App -&gt; Widget
--   myform action = $(whamletFile "templates/loginform.hamlet")
--   </pre>
--   
--   where templates/loginform.hamlet contains
--   
--   <pre>
--   &lt;form method="post" action="@{action}"&gt;
--       &lt;input name="username"&gt;
--       &lt;input type="password" name="password"&gt;
--       &lt;input type="submit" value="Login"&gt;
--   </pre>
module Yesod.Auth.HashDB

-- | The type representing user information stored in the database should
--   be an instance of this class. It just provides the getters and setters
--   used by the functions in this module.
class HashDBUser user where userPasswordSalt _ = Just "" setPasswordHash = setSaltAndPasswordHash "" setUserHashAndSalt = error "Define setSaltAndPasswordHash to get old-database compatibility" setSaltAndPasswordHash = setUserHashAndSalt

-- | Retrieve password hash from user data
userPasswordHash :: HashDBUser user => 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.

-- | <i>Deprecated: Compatibility with old data containing a separate salt
--   field will be removed eventually</i>
userPasswordSalt :: HashDBUser user => user -> Maybe Text

-- | Callback for <a>setPassword</a> and <a>upgradePasswordHash</a>.
--   Produces a version of the user data with the hash set to the new
--   value.
--   
--   This is the method which you should define for new applications, which
--   do not require compatibility with databases containing hashes written
--   by previous versions of this module. If you do need compatibility,
--   define <a>setSaltAndPasswordHash</a> instead.
setPasswordHash :: HashDBUser user => Text -> user -> user

-- | <i>Deprecated: Please use setSaltAndPasswordHash instead</i>
setUserHashAndSalt :: HashDBUser user => Text -> Text -> user -> user

-- | Callback used in <a>upgradePasswordHash</a> when compatibility is
--   needed with old-style hashes (including ones already upgraded using
--   <a>upgradePasswordHash</a>). This is not required for new
--   applications, which do not have a separate salt field in user data:
--   please define <a>setPasswordHash</a> instead.
--   
--   The default implementation produces a runtime error, and will only be
--   called if a non-empty salt value needs to be set for compatibility
--   with an old database.

-- | <i>Deprecated: Compatibility with old data containing a separate salt
--   field will be removed eventually</i>
setSaltAndPasswordHash :: HashDBUser user => Text -> Text -> user -> user

-- | Unique keys besides the Key

-- | Default strength used for passwords (see <a>Crypto.PasswordStore</a>
--   for details).
defaultStrength :: Int

-- | Set password for user, using the given strength setting. Use this
--   function, or <a>setPassword</a>, to produce a user record containing
--   the hashed password. Unlike previous versions of this module, no
--   separate salt field is required for new passwords (but it may still be
--   required for compatibility while old password hashes remain in the
--   database).
--   
--   This function does not change the database; the calling application is
--   responsible for saving the data which is returned.
setPasswordStrength :: (MonadIO m, HashDBUser user) => Int -> Text -> user -> m user

-- | As <a>setPasswordStrength</a>, but using the <a>defaultStrength</a>
setPassword :: (MonadIO m, HashDBUser user) => Text -> user -> m user

-- | 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 <a>upgradePasswordHash</a>, 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
--   methods:
--   
--   <ul>
--   <li>Just False - the user has a password set up, but the given one
--   does not match it</li>
--   <li>Nothing - the user does not have a password (the hash is
--   Nothing)</li>
--   </ul>
--   
--   Since 1.4.1
validatePass :: HashDBUser u => u -> Text -> Maybe Bool

-- | Upgrade existing user credentials to a stronger hash. The existing
--   hash may have been produced either by previous versions of this
--   module, which used a weak algorithm, or from a weaker setting in the
--   current algorithm. Use this function to produce an updated user record
--   to store in the database.
--   
--   To allow transitional use, starting from hashes produced by older
--   versions of this module, and upgrading them to the new format, we have
--   to use the hash alone, without knowledge of the user's plaintext
--   password. In this case, we apply the new algorithm to the old hash,
--   resulting in both hash functions, old and new, being used one on top
--   of the other; this situation is recognised by the hash having the new
--   format while the separate salt field is non-empty.
--   
--   Returns Nothing if the user has no password (ie if
--   <a>userPasswordHash</a> u is <a>Nothing</a> and/or
--   <a>userPasswordSalt</a> u is <a>Nothing</a>).
upgradePasswordHash :: (MonadIO m, HashDBUser user) => Int -> user -> m (Maybe user)

-- | 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 <a>validatePass</a> to do the work.
validateUser :: HashDBPersist site user => Unique user -> Text -> HandlerT site IO Bool

-- | Prompt for username and password, validate that against a database
--   which holds the username and a hash of the password
authHashDB :: HashDBPersist site user => (Text -> Maybe (Unique user)) -> AuthPlugin site

-- | Like <a>authHashDB</a>, but with an extra parameter to supply a custom
--   HTML form.
--   
--   The custom form should be specified as a function which takes a route
--   to use as the form action, and returns a Widget containing the form.
--   The form must use the supplied route as its action URL, and, when
--   submitted, it must send two text fields called "username" and
--   "password".
--   
--   Please see the example in the documentation at the head of this
--   module.
--   
--   Since 1.3.2
authHashDBWithForm :: HashDBPersist site user => (Route site -> WidgetT site IO ()) -> (Text -> Maybe (Unique user)) -> AuthPlugin site

-- | A drop in for the getAuthId method of your YesodAuth instance which
--   can be used if authHashDB is the only plugin in use.

-- | <i>Deprecated: If this is a problem, please discuss at
--   <a>https://github.com/paul-rouse/yesod-auth-hashdb/issues/5</a></i>
getAuthIdHashDB :: HashDBPersist site user => (AuthRoute -> Route site) -> (Text -> Maybe (Unique user)) -> Creds site -> HandlerT site IO (Maybe (AuthId site))

-- | <i>Deprecated: The predefined User data type will be removed soon -
--   please define your own database table and accompanying instance of
--   HashDBUser</i>
type User = UserGeneric SqlBackend

-- | Generate data base instances for a valid user
data UserGeneric backend

-- | <i>Deprecated: The predefined User data type will be removed soon -
--   please define your own database table and accompanying instance of
--   HashDBUser</i>
User :: !Text -> !Text -> !Text -> UserGeneric backend
[userUsername] :: UserGeneric backend -> !Text
[userPassword] :: UserGeneric backend -> !Text
[userSalt] :: UserGeneric backend -> !Text
type UserId = Key User

-- | An <a>EntityField</a> is parameterised by the Haskell record it
--   belongs to and the additional type of that field

-- | <i>Deprecated: The predefined User data type will be removed soon -
--   please define your own database table and accompanying instance of
--   HashDBUser</i>
migrateUsers :: Migration
instance Database.Persist.Class.PersistStore.PersistStore backend => Database.Persist.Class.PersistField.PersistField (Yesod.Auth.HashDB.UserGeneric backend)
instance Database.Persist.Class.PersistStore.PersistStore backend => Database.Persist.Sql.Class.PersistFieldSql (Yesod.Auth.HashDB.UserGeneric backend)
instance Database.Persist.Class.PersistStore.PersistStore backend => Database.Persist.Class.PersistEntity.PersistEntity (Yesod.Auth.HashDB.UserGeneric backend)
instance GHC.Show.Show (Database.Persist.Class.PersistStore.BackendKey backend) => GHC.Show.Show (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance GHC.Read.Read (Database.Persist.Class.PersistStore.BackendKey backend) => GHC.Read.Read (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance GHC.Classes.Eq (Database.Persist.Class.PersistStore.BackendKey backend) => GHC.Classes.Eq (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance GHC.Classes.Ord (Database.Persist.Class.PersistStore.BackendKey backend) => GHC.Classes.Ord (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance Web.HttpApiData.Internal.ToHttpApiData (Database.Persist.Class.PersistStore.BackendKey backend) => Web.HttpApiData.Internal.ToHttpApiData (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance Web.HttpApiData.Internal.FromHttpApiData (Database.Persist.Class.PersistStore.BackendKey backend) => Web.HttpApiData.Internal.FromHttpApiData (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance Web.PathPieces.PathPiece (Database.Persist.Class.PersistStore.BackendKey backend) => Web.PathPieces.PathPiece (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance Database.Persist.Class.PersistField.PersistField (Database.Persist.Class.PersistStore.BackendKey backend) => Database.Persist.Class.PersistField.PersistField (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance Database.Persist.Sql.Class.PersistFieldSql (Database.Persist.Class.PersistStore.BackendKey backend) => Database.Persist.Sql.Class.PersistFieldSql (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance Data.Aeson.Types.Class.ToJSON (Database.Persist.Class.PersistStore.BackendKey backend) => Data.Aeson.Types.Class.ToJSON (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance Data.Aeson.Types.Class.FromJSON (Database.Persist.Class.PersistStore.BackendKey backend) => Data.Aeson.Types.Class.FromJSON (Database.Persist.Class.PersistEntity.Key (Yesod.Auth.HashDB.UserGeneric backend))
instance Database.Persist.Class.PersistStore.PersistStore backend => Database.Persist.Class.PersistStore.ToBackendKey backend (Yesod.Auth.HashDB.UserGeneric backend)
instance Yesod.Auth.HashDB.HashDBUser (Yesod.Auth.HashDB.UserGeneric backend)
