Some form validations.
This commit is contained in:
parent
065bc7a716
commit
648fca9352
@ -2,11 +2,12 @@
|
||||
-- | TODO: token validation.
|
||||
module App.AuthenticationInterface where
|
||||
|
||||
import Prelude (Unit, bind, discard, pure, ($), (<<<), (<>), (>), (==))
|
||||
import Prelude (Unit, bind, discard, pure, ($), (<<<), (<>), (>), (==), map, show)
|
||||
|
||||
import Data.Array as A
|
||||
import Data.ArrayBuffer.Types (ArrayBuffer)
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.Maybe (Maybe(..), maybe)
|
||||
import Data.Either (Either(..))
|
||||
import Data.Tuple (Tuple(..))
|
||||
import Effect.Aff.Class (class MonadAff)
|
||||
import Halogen as H
|
||||
@ -18,14 +19,23 @@ import Web.Event.Event (Event)
|
||||
|
||||
import Bulma as Bulma
|
||||
|
||||
import App.Email as Email
|
||||
import App.LogMessage
|
||||
import App.Messages.AuthenticationDaemon as AuthD
|
||||
|
||||
import App.Validation.Login as L
|
||||
import App.Validation.Email as E
|
||||
import App.Validation.Password as P
|
||||
|
||||
type Login = String
|
||||
type Email = String
|
||||
type Password = String
|
||||
type PasswordRecoveryToken = String
|
||||
|
||||
data Error
|
||||
= Login (Array L.Error)
|
||||
| Email (Array E.Error)
|
||||
| Password (Array P.Error)
|
||||
|
||||
-- | The component can inform the parent (`App.Container`) that the authentication is complete,
|
||||
-- | and share both the uid and token. The token is useful to authenticate the user to the
|
||||
-- | dnsmanager daemon.
|
||||
@ -38,6 +48,7 @@ data Output
|
||||
| AuthenticateToAuthd (Tuple Login Password)
|
||||
| Log LogMessage
|
||||
| PasswordRecovery Login PasswordRecoveryToken Password
|
||||
| AskPasswordRecovery (Either Email Login)
|
||||
|
||||
-- | The component's parent provides received messages.
|
||||
-- |
|
||||
@ -82,9 +93,19 @@ type State =
|
||||
{ authenticationForm :: StateAuthenticationForm
|
||||
, passwordRecoveryForm :: StatePasswordRecoveryForm
|
||||
, newPasswordForm :: StateNewPasswordForm
|
||||
, errors :: Array Error
|
||||
, wsUp :: Boolean
|
||||
}
|
||||
|
||||
initialState :: Input -> State
|
||||
initialState _ =
|
||||
{ authenticationForm: { login: "", pass: "" }
|
||||
, passwordRecoveryForm: { login: "", email: "" }
|
||||
, newPasswordForm: { login: "", token: "", password: "", confirmation: "" }
|
||||
, wsUp: true
|
||||
, errors: []
|
||||
}
|
||||
|
||||
component :: forall m. MonadAff m => H.Component Query Input Output m
|
||||
component =
|
||||
H.mkComponent
|
||||
@ -96,25 +117,66 @@ component =
|
||||
}
|
||||
}
|
||||
|
||||
initialState :: Input -> State
|
||||
initialState _ =
|
||||
{ authenticationForm: { login: "", pass: "" }
|
||||
, passwordRecoveryForm: { login: "", email: "" }
|
||||
, newPasswordForm: { login: "", token: "", password: "", confirmation: "" }
|
||||
, wsUp: true
|
||||
}
|
||||
|
||||
render :: forall m. State -> H.ComponentHTML Action () m
|
||||
render { wsUp, authenticationForm, passwordRecoveryForm, newPasswordForm} =
|
||||
render { wsUp, authenticationForm, passwordRecoveryForm, newPasswordForm, errors } =
|
||||
Bulma.section_small
|
||||
[ case wsUp of
|
||||
false -> Bulma.p "You are disconnected."
|
||||
true -> Bulma.columns_ [ b auth_form, b passrecovery_form, b newpass_form ]
|
||||
true ->
|
||||
if A.length errors > 0
|
||||
then HH.div_ [ Bulma.box [ HH.text (A.fold $ map show_error errors) ]
|
||||
, Bulma.columns_ [ b auth_form, b passrecovery_form, b newpass_form ]
|
||||
]
|
||||
else Bulma.columns_ [ b auth_form, b passrecovery_form, b newpass_form ]
|
||||
]
|
||||
|
||||
where
|
||||
b e = Bulma.column_ [ Bulma.box e ]
|
||||
|
||||
show_error :: Error -> String
|
||||
show_error = case _ of
|
||||
Login arr -> "Error with the Login: " <> (A.fold $ map show_error_login arr)
|
||||
Email arr -> "Error with the Email: " <> (A.fold $ map show_error_email arr)
|
||||
Password arr -> "Error with the Password: " <> (A.fold $ map show_error_password arr)
|
||||
|
||||
show_error_login :: L.Error -> String
|
||||
show_error_login = case _ of
|
||||
L.ParsingError {error, position} ->
|
||||
"position " <> show position <> " " <> maybe "" string_error_login error
|
||||
|
||||
string_error_login :: L.LoginParsingError -> String
|
||||
string_error_login = case _ of
|
||||
L.CannotParse -> "cannot parse the login"
|
||||
L.CannotEntirelyParse -> "cannot entirely parse the login"
|
||||
L.Size min max n -> "login size should be between "
|
||||
<> show min <> " and " <> show max
|
||||
<> " (currently: " <> show n <> ")"
|
||||
show_error_email :: E.Error -> String
|
||||
show_error_email = case _ of
|
||||
E.ParsingError {error, position} ->
|
||||
"position " <> show position <> " " <> maybe "" string_error_email error
|
||||
|
||||
string_error_email :: E.EmailParsingError -> String
|
||||
string_error_email = case _ of
|
||||
E.CannotParse -> "cannot parse the email"
|
||||
E.CannotEntirelyParse -> "cannot entirely parse the email"
|
||||
E.Size min max n -> "email size should be between "
|
||||
<> show min <> " and " <> show max
|
||||
<> " (currently: " <> show n <> ")"
|
||||
|
||||
show_error_password :: P.Error -> String
|
||||
show_error_password = case _ of
|
||||
P.ParsingError {error, position} ->
|
||||
"position " <> show position <> " " <> maybe "" string_error_password error
|
||||
|
||||
string_error_password :: P.PasswordParsingError -> String
|
||||
string_error_password = case _ of
|
||||
P.CannotParse -> "cannot parse the password"
|
||||
P.CannotEntirelyParse -> "cannot entirely parse the password"
|
||||
P.Size min max n -> "password size should be between "
|
||||
<> show min <> " and " <> show max
|
||||
<> " (currently: " <> show n <> ")"
|
||||
|
||||
auth_form = [ Bulma.h3 "Authentication" , render_auth_form ]
|
||||
passrecovery_form = [ Bulma.h3 "Password Recovery", render_password_recovery_form ]
|
||||
newpass_form = [ Bulma.h3 "New password", render_new_password_form ]
|
||||
@ -207,31 +269,23 @@ handleAction = case _ of
|
||||
H.liftEffect $ Event.preventDefault ev
|
||||
|
||||
{ authenticationForm } <- H.get
|
||||
let { login, pass } = authenticationForm
|
||||
|
||||
case authenticationForm.login, authenticationForm.pass of
|
||||
case login, pass of
|
||||
"" , _ ->
|
||||
H.raise $ Log $ UnableToSend "Write your login!"
|
||||
|
||||
_ , "" ->
|
||||
H.raise $ Log $ UnableToSend "Write your password!"
|
||||
|
||||
login, pass -> do
|
||||
H.raise $ AuthenticateToAuthd (Tuple login pass)
|
||||
_, _ -> do
|
||||
case L.login login, P.password pass of
|
||||
Left errors, _ -> H.modify_ _ { errors = [ Login errors ] }
|
||||
_, Left errors -> H.modify_ _ { errors = [ Password errors ] }
|
||||
_, _ -> do H.modify_ _ { errors = [] }
|
||||
H.raise $ AuthenticateToAuthd (Tuple login pass)
|
||||
H.raise $ Log $ SystemLog $ "authenticate (login: " <> login <> ")"
|
||||
|
||||
-- TODO: verify the login?
|
||||
NewPasswordAttempt ev -> do
|
||||
H.liftEffect $ Event.preventDefault ev
|
||||
|
||||
{ newPasswordForm } <- H.get
|
||||
let { login, token, password, confirmation} = newPasswordForm
|
||||
|
||||
if A.any (_ == "") [ login, token, password, confirmation ]
|
||||
then H.raise $ Log $ ErrorLog "All entries are required!"
|
||||
else if password == confirmation
|
||||
then H.raise $ PasswordRecovery login token password
|
||||
else H.raise $ Log $ UnableToSend "Confirmation differs from password!"
|
||||
|
||||
PasswordRecoveryAttempt ev -> do
|
||||
H.liftEffect $ Event.preventDefault ev
|
||||
|
||||
@ -242,10 +296,32 @@ handleAction = case _ of
|
||||
case login, email of
|
||||
"", "" -> H.raise $ Log $ UnableToSend "Write your login or your email!"
|
||||
_, _ -> do
|
||||
message <- H.liftEffect $ AuthD.serialize $
|
||||
AuthD.MkAskPasswordRecovery { user: (Just login), email: Just (Email.Email email) }
|
||||
H.raise $ MessageToSend message
|
||||
H.raise $ Log $ SystemLog "password recovery"
|
||||
if email == ""
|
||||
then case L.login login of
|
||||
Left errors -> H.modify_ _ { errors = [ Login errors ] }
|
||||
_ -> do H.modify_ _ { errors = [] }
|
||||
H.raise $ AskPasswordRecovery (Right login)
|
||||
else case E.email email of
|
||||
Left errors -> H.modify_ _ { errors = [ Email errors ] }
|
||||
_ -> do H.modify_ _ { errors = [] }
|
||||
H.raise $ AskPasswordRecovery (Left email)
|
||||
|
||||
-- TODO: verify the login?
|
||||
NewPasswordAttempt ev -> do
|
||||
H.liftEffect $ Event.preventDefault ev
|
||||
|
||||
{ newPasswordForm } <- H.get
|
||||
let { login, token, password, confirmation} = newPasswordForm
|
||||
|
||||
if A.any (_ == "") [ login, token, password, confirmation ]
|
||||
then H.raise $ Log $ ErrorLog "All entries are required!"
|
||||
else if password == confirmation
|
||||
then case L.login login of
|
||||
Left errors -> H.modify_ _ { errors = [ Login errors ] }
|
||||
Right _ -> do H.modify_ _ { errors = [] }
|
||||
H.raise $ PasswordRecovery login token password
|
||||
else H.raise $ Log $ UnableToSend "Confirmation differs from password!"
|
||||
|
||||
handleQuery :: forall a m. MonadAff m => Query a -> H.HalogenM State Action () Output m (Maybe a)
|
||||
handleQuery = case _ of
|
||||
|
@ -77,6 +77,8 @@ import Web.HTML (window) as HTML
|
||||
import Web.HTML.Window (sessionStorage) as Window
|
||||
import Web.Storage.Storage as Storage
|
||||
|
||||
import App.Email as Email
|
||||
|
||||
import App.LogMessage (LogMessage(..))
|
||||
|
||||
import App.Pages
|
||||
@ -341,6 +343,15 @@ handleAction = case _ of
|
||||
|
||||
AuthenticationInterfaceEvent ev -> case ev of
|
||||
AI.MessageToSend message -> H.tell _ws_auth unit (WS.ToSend message)
|
||||
AI.AskPasswordRecovery e -> case e of
|
||||
Left email -> do
|
||||
message <- H.liftEffect $ AuthD.serialize $
|
||||
AuthD.MkAskPasswordRecovery { user: Nothing, email: Just (Email.Email email) }
|
||||
H.tell _ws_auth unit (WS.ToSend message)
|
||||
Right login -> do
|
||||
message <- H.liftEffect $ AuthD.serialize $
|
||||
AuthD.MkAskPasswordRecovery { user: (Just login), email: Nothing }
|
||||
H.tell _ws_auth unit (WS.ToSend message)
|
||||
AI.PasswordRecovery login token pass -> do
|
||||
message <- H.liftEffect $ AuthD.serialize $ AuthD.MkPasswordRecovery
|
||||
{ user: login
|
||||
|
@ -71,6 +71,13 @@ type State =
|
||||
, wsUp :: Boolean
|
||||
}
|
||||
|
||||
initialState :: Input -> State
|
||||
initialState _ =
|
||||
{ registrationForm: { login: "", email: "", pass: "" }
|
||||
, errors: []
|
||||
, wsUp: true
|
||||
}
|
||||
|
||||
component :: forall m. MonadAff m => H.Component Query Input Output m
|
||||
component =
|
||||
H.mkComponent
|
||||
@ -82,13 +89,6 @@ component =
|
||||
}
|
||||
}
|
||||
|
||||
initialState :: Input -> State
|
||||
initialState _ =
|
||||
{ registrationForm: { login: "", email: "", pass: "" }
|
||||
, errors: []
|
||||
, wsUp: true
|
||||
}
|
||||
|
||||
render :: forall m. State -> H.ComponentHTML Action () m
|
||||
render { wsUp, registrationForm }
|
||||
= Bulma.section_small
|
||||
|
@ -117,9 +117,8 @@ render { modal, wsUp, newPasswordForm } =
|
||||
]
|
||||
|
||||
render_delete_account_modal = Bulma.modal "Delete your account"
|
||||
-- TODO: body content
|
||||
[ Bulma.p "Wait, this is serious"
|
||||
, Bulma.strong "⚠ You won't be able to recover."
|
||||
[ Bulma.p "Your account and domains will be removed."
|
||||
, Bulma.strong "⚠ You won't be able to recover your data."
|
||||
]
|
||||
[ Bulma.alert_btn "GO AHEAD LOL" DeleteAccount
|
||||
, Bulma.cancel_button CancelModal
|
||||
|
@ -21,7 +21,7 @@ data Error
|
||||
= ParsingError (G.Error PasswordParsingError)
|
||||
|
||||
min_password_size :: Int
|
||||
min_password_size = 1
|
||||
min_password_size = 2
|
||||
max_password_size :: Int
|
||||
max_password_size = 100
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user