login via HashDB
This commit is contained in:
parent
5718401d50
commit
72586a6dc7
@ -4,12 +4,17 @@ import Database.Persist.Sql (ConnectionPool, runSqlPool)
|
|||||||
import Import.NoFoundation
|
import Import.NoFoundation
|
||||||
import Text.Hamlet (hamletFile)
|
import Text.Hamlet (hamletFile)
|
||||||
import Yesod.Auth.BrowserId (authBrowserId)
|
import Yesod.Auth.BrowserId (authBrowserId)
|
||||||
|
import Yesod.Auth.HashDB (HashDBUser(..),authHashDB)
|
||||||
import Yesod.Auth.Message (AuthMessage (InvalidLogin))
|
import Yesod.Auth.Message (AuthMessage (InvalidLogin))
|
||||||
import qualified Yesod.Core.Unsafe as Unsafe
|
import qualified Yesod.Core.Unsafe as Unsafe
|
||||||
import Yesod.Core.Types (Logger)
|
import Yesod.Core.Types (Logger)
|
||||||
import Yesod.Default.Util (addStaticContentExternal)
|
import Yesod.Default.Util (addStaticContentExternal)
|
||||||
import Yesod.Fay
|
import Yesod.Fay
|
||||||
|
|
||||||
|
instance HashDBUser User where
|
||||||
|
userPasswordHash = userPassword
|
||||||
|
setPasswordHash h u = u { userPassword = Just h }
|
||||||
|
|
||||||
-- | The foundation datatype for your application. This can be a good place to
|
-- | The foundation datatype for your application. This can be a good place to
|
||||||
-- keep settings and values requiring initialization before your application
|
-- keep settings and values requiring initialization before your application
|
||||||
-- starts running, such as database connections. Every handler will have
|
-- starts running, such as database connections. Every handler will have
|
||||||
@ -195,7 +200,8 @@ instance YesodAuth App where
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- You can add other plugins like BrowserID, email or OAuth here
|
-- You can add other plugins like BrowserID, email or OAuth here
|
||||||
authPlugins _ = [authBrowserId def]
|
authPlugins _ = [authBrowserId def,
|
||||||
|
authHashDB (Just . UniqueUser)]
|
||||||
|
|
||||||
authHttpManager = getHttpManager
|
authHttpManager = getHttpManager
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@ import Text.Regex.TDFA
|
|||||||
import Data.Conduit.Binary
|
import Data.Conduit.Binary
|
||||||
import qualified Data.ByteString as S
|
import qualified Data.ByteString as S
|
||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
|
import Crypto.PasswordStore
|
||||||
|
import Yesod.Auth.HashDB (defaultStrength)
|
||||||
|
|
||||||
getYourAccountR :: Handler Html
|
getYourAccountR :: Handler Html
|
||||||
getYourAccountR = do
|
getYourAccountR = do
|
||||||
@ -26,17 +28,18 @@ postYourAccountR = do
|
|||||||
let accountData = case result of
|
let accountData = case result of
|
||||||
FormSuccess res -> Just res
|
FormSuccess res -> Just res
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
Just (name, localId, sshPubKey, avatarFile) = accountData
|
Just (name, localId, mPassword, sshPubKey, avatarFile) = accountData
|
||||||
userId <- requireAuthId
|
userId <- requireAuthId
|
||||||
updateUserAccount userId name localId sshPubKey avatarFile
|
updateUserAccount userId name localId mPassword sshPubKey avatarFile
|
||||||
defaultLayout $ do
|
defaultLayout $ do
|
||||||
setTitle "Your account"
|
setTitle "Your account"
|
||||||
$(widgetFile "your-account")
|
$(widgetFile "your-account")
|
||||||
|
|
||||||
yourAccountForm :: Maybe Text -> Maybe Text -> Maybe Text -> Form (Maybe Text, Maybe Text, Maybe Text, Maybe FileInfo)
|
yourAccountForm :: Maybe Text -> Maybe Text -> Maybe Text -> Form (Maybe Text, Maybe Text, Maybe Text, Maybe Text, Maybe FileInfo)
|
||||||
yourAccountForm maybeName maybeLocalId maybeSshPubKey = renderBootstrap3 BootstrapBasicForm $ (,,,)
|
yourAccountForm maybeName maybeLocalId maybeSshPubKey = renderBootstrap3 BootstrapBasicForm $ (,,,,)
|
||||||
<$> aopt textField (bfs MsgAccountName) (Just maybeName)
|
<$> aopt textField (bfs MsgAccountName) (Just maybeName)
|
||||||
<*> aopt textField (bfs MsgId) (Just maybeLocalId)
|
<*> aopt textField (bfs MsgId) (Just maybeLocalId)
|
||||||
|
<*> aopt passwordConfirmField (bfs MsgPassword) Nothing
|
||||||
<*> aopt textField (bfs MsgSshPubKey) (Just maybeSshPubKey)
|
<*> aopt textField (bfs MsgSshPubKey) (Just maybeSshPubKey)
|
||||||
<*> fileAFormOpt (bfs MsgAvatar)
|
<*> fileAFormOpt (bfs MsgAvatar)
|
||||||
|
|
||||||
@ -54,12 +57,18 @@ isLocalIdAcceptable :: Text -> Bool
|
|||||||
isLocalIdAcceptable localId =
|
isLocalIdAcceptable localId =
|
||||||
match localIdRegexp (unpack localId) && not (localId `elem` unwantedLocalIds)
|
match localIdRegexp (unpack localId) && not (localId `elem` unwantedLocalIds)
|
||||||
|
|
||||||
updateUserAccount :: Key User -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe FileInfo -> Handler ()
|
updateUserAccount :: Key User -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe Text -> Maybe FileInfo -> Handler ()
|
||||||
updateUserAccount userId name maybeLocalId maybeSshPubKey maybeAvatarFile = do
|
updateUserAccount userId name maybeLocalId maybePassword maybeSshPubKey maybeAvatarFile = do
|
||||||
updateJustName userId name
|
updateJustName userId name
|
||||||
updateAvatar userId maybeAvatarFile
|
updateAvatar userId maybeAvatarFile
|
||||||
updateLocalIdAndPubKey userId maybeLocalId maybeSshPubKey
|
updateLocalIdAndPubKey userId maybeLocalId maybeSshPubKey
|
||||||
|
updatePassword userId maybePassword
|
||||||
|
|
||||||
|
updatePassword :: Key User -> Maybe Text -> Handler ()
|
||||||
|
updatePassword _ Nothing = return ()
|
||||||
|
updatePassword userId (Just password) = do
|
||||||
|
encodedPassword <- liftIO $ makePassword (encodeUtf8 password) defaultStrength
|
||||||
|
runDB $ update userId [UserPassword =. Just (decodeUtf8 encodedPassword)]
|
||||||
|
|
||||||
updateAvatar :: Key User -> Maybe FileInfo -> Handler ()
|
updateAvatar :: Key User -> Maybe FileInfo -> Handler ()
|
||||||
updateAvatar _ Nothing = return ()
|
updateAvatar _ Nothing = return ()
|
||||||
@ -114,3 +123,21 @@ getAvatarR userId = do
|
|||||||
sendResponse (typePng, toContent avatarBytes)
|
sendResponse (typePng, toContent avatarBytes)
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
sendFile typeSvg "static/images/male-avatar.svg"
|
sendFile typeSvg "static/images/male-avatar.svg"
|
||||||
|
|
||||||
|
passwordConfirmField :: Field Handler Text
|
||||||
|
passwordConfirmField = Field
|
||||||
|
{ fieldParse = \rawVals _fileVals ->
|
||||||
|
case rawVals of
|
||||||
|
[a, b]
|
||||||
|
| a == b -> return $ Right $ Just a
|
||||||
|
| otherwise -> return $ Left "Passwords don't match"
|
||||||
|
[] -> return $ Right Nothing
|
||||||
|
_ -> return $ Left "You must enter two values"
|
||||||
|
, fieldView = \idAttr nameAttr otherAttrs eResult isReq ->
|
||||||
|
[whamlet|
|
||||||
|
<input id=#{idAttr} name=#{nameAttr} *{otherAttrs} type=password>
|
||||||
|
<div>confirm:
|
||||||
|
<input id=#{idAttr}-confirm name=#{nameAttr} *{otherAttrs} type=password>
|
||||||
|
|]
|
||||||
|
, fieldEnctype = UrlEncoded
|
||||||
|
}
|
||||||
|
@ -127,6 +127,8 @@ library
|
|||||||
, conduit-extra
|
, conduit-extra
|
||||||
, resourcet
|
, resourcet
|
||||||
, yesod-newsfeed
|
, yesod-newsfeed
|
||||||
|
, yesod-auth-hashdb
|
||||||
|
, pwstore-fast
|
||||||
|
|
||||||
executable gonito
|
executable gonito
|
||||||
if flag(library-only)
|
if flag(library-only)
|
||||||
|
@ -25,3 +25,4 @@ CommentText: Write a comment
|
|||||||
Send: Send
|
Send: Send
|
||||||
Avatar: avatar
|
Avatar: avatar
|
||||||
About: about
|
About: about
|
||||||
|
Password: password
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item"><b>Name</b> is your human-readable name (to be shown on the leaderboard).
|
<li class="list-group-item"><b>Name</b> is your human-readable name (to be shown on the leaderboard).
|
||||||
<li class="list-group-item"><b>ID</b> is used in the URLs for your repos (must be composed of lower-case letters, digits or hyphyns, must start with a lower-case letter).
|
<li class="list-group-item"><b>ID</b> is used in the URLs for your repos (must be composed of lower-case letters, digits or hyphyns, must start with a lower-case letter).
|
||||||
|
<li class="list-group-item"><b>Password</b> is needed when Persona is closed.
|
||||||
<li class="list-group-item"><b>SSH public key</b> is needed if you want to access repos hosted on Gonito.net (usually it is <tt>.ssh/id_rsa.pub</tt> in your home directory after you generated private/public key pair).
|
<li class="list-group-item"><b>SSH public key</b> is needed if you want to access repos hosted on Gonito.net (usually it is <tt>.ssh/id_rsa.pub</tt> in your home directory after you generated private/public key pair).
|
||||||
<li class="list-group-item">ID cannot be changed once it is set up.
|
<li class="list-group-item">ID cannot be changed once it is set up.
|
||||||
<li class="list-group-item">You don't need to specify your ID and SSH public key, if you don't use private repos hosted on Gonito.net.
|
<li class="list-group-item">You don't need to specify your ID and SSH public key, if you don't use private repos hosted on Gonito.net.
|
Loading…
Reference in New Issue
Block a user