Updated Authentication Daemon messages API (reponses).

master
Philippe Pittoli 2023-06-14 03:23:23 +02:00
parent c8c52ea408
commit fba25826de
2 changed files with 199 additions and 89 deletions

View File

@ -15,7 +15,6 @@ import Data.Tuple (Tuple(..))
import Data.ArrayBuffer.Types (ArrayBuffer) import Data.ArrayBuffer.Types (ArrayBuffer)
import App.Email as Email import App.Email as Email
import App.Phone as Phone
import App.UserPublic as UserPublic import App.UserPublic as UserPublic
import App.PermissionLevel as PermissionLevel import App.PermissionLevel as PermissionLevel
@ -27,32 +26,10 @@ import App.IPC as IPC
{- TODO: {- TODO:
For a few messages, user can be designated by a string (login) or a number (its UID). For a few messages, user can be designated by a string (login) or a number (its UID).
This was simplified by using the login for each. This was simplified by using the uid for each.
Maybe this could be changed in the future to match the actual possibilities of the API. Maybe this could be changed in the future to match the actual possibilities of the API.
Possible requests:
- 15 type EditProfileContent = { token :: Maybe String, shared_key :: Maybe String, user :: Int | String | Nil, new_profile :: Hash(String, JSON::Any) }
-- Deletion can be triggered by either an admin or the user.
-} -}
-- Basic message types.
-- TODO: note to myself: messages seem chaotic. Could be simpler. Should be simpler.
type Error = { reason :: Maybe String }
type Token = { uid :: Int, token :: String }
type User = { user :: UserPublic.UserPublic }
type UserAdded = { user :: UserPublic.UserPublic }
type UserEdited = { uid :: Int }
type UserValidated = { user :: UserPublic.UserPublic }
type UsersList = { users :: Array UserPublic.UserPublic }
type PermissionCheck = { user :: Int, service :: String, resource :: String, permission :: PermissionLevel.PermissionLevel }
type PermissionSet = { user :: Int, service :: String, resource :: String, permission :: PermissionLevel.PermissionLevel }
type PasswordRecoverySent = { user :: UserPublic.UserPublic }
type PasswordRecovered = { user :: UserPublic.UserPublic }
type Contacts = { user :: Int, email :: Maybe Email.Email, phone :: Maybe Phone.Phone }
type MatchingUsers = { users :: Array UserPublic.UserPublic }
type Password = String type Password = String
{- UserID should be in a separate module with a dedicated codec. -} {- UserID should be in a separate module with a dedicated codec. -}
@ -185,42 +162,167 @@ codecSearchUser
{ regex: CAR.optional CA.string { regex: CAR.optional CA.string
, offset: CAR.optional CA.int }) , offset: CAR.optional CA.int })
-- Related JSON codecs.
{-
RESPONSES
-}
-- TODO: note to myself: messages seem chaotic. Could be simpler. Should be simpler.
{- 0 -}
type Error = { reason :: Maybe String }
codecGotError ∷ CA.JsonCodec Error codecGotError ∷ CA.JsonCodec Error
codecGotError = CA.object "Error" (CAR.record { reason: CAR.optional CA.string }) codecGotError = CA.object "Error" (CAR.record { reason: CAR.optional CA.string })
codecGotToken ∷ CA.JsonCodec Token
codecGotToken = CA.object "Token" (CAR.record { "uid": CA.int, "token": CA.string }) {- 1 -}
codecGotPasswordRecoverySent ∷ CA.JsonCodec PasswordRecoverySent type Logged = { uid :: Int, token :: String }
codecGotPasswordRecoverySent = CA.object "PasswordRecoverySent" (CAR.record { user: UserPublic.codec }) codecGotToken ∷ CA.JsonCodec Logged
codecGotToken = CA.object "Logged" (CAR.record { "uid": CA.int, "token": CA.string })
{- 2 -}
type User = { user :: UserPublic.UserPublic }
codecGotUser ∷ CA.JsonCodec User codecGotUser ∷ CA.JsonCodec User
codecGotUser = CA.object "User" (CAR.record { user: UserPublic.codec }) codecGotUser = CA.object "User" (CAR.record { user: UserPublic.codec })
{- 3 -}
type UserAdded = { user :: UserPublic.UserPublic }
codecGotUserAdded ∷ CA.JsonCodec UserAdded codecGotUserAdded ∷ CA.JsonCodec UserAdded
codecGotUserAdded = CA.object "UserAdded" (CAR.record { user: UserPublic.codec }) codecGotUserAdded = CA.object "UserAdded" (CAR.record { user: UserPublic.codec })
{- 4 -}
type UserEdited = { uid :: Int }
codecGotUserEdited ∷ CA.JsonCodec UserEdited codecGotUserEdited ∷ CA.JsonCodec UserEdited
codecGotUserEdited = CA.object "UserEdited" (CAR.record { "uid": CA.int }) codecGotUserEdited = CA.object "UserEdited" (CAR.record { "uid": CA.int })
{- 5 -}
type UserValidated = { user :: UserPublic.UserPublic }
codecGotUserValidated ∷ CA.JsonCodec UserValidated codecGotUserValidated ∷ CA.JsonCodec UserValidated
codecGotUserValidated = CA.object "UserValidated" (CAR.record { user: UserPublic.codec }) codecGotUserValidated = CA.object "UserValidated" (CAR.record { user: UserPublic.codec })
codecGotPasswordRecovered ∷ CA.JsonCodec PasswordRecovered
codecGotPasswordRecovered = CA.object "PasswordRecovered" (CAR.record { user: UserPublic.codec }) {- 6 -}
type UsersList = { users :: Array UserPublic.UserPublic }
codecGotUsersList ∷ CA.JsonCodec UsersList codecGotUsersList ∷ CA.JsonCodec UsersList
codecGotUsersList = CA.object "UsersList" (CAR.record { users: CA.array UserPublic.codec }) codecGotUsersList = CA.object "UsersList" (CAR.record { users: CA.array UserPublic.codec })
{- 7 -}
type PermissionCheck
= { user :: Int
, service :: String
, resource :: String
, permission :: PermissionLevel.PermissionLevel }
codecGotPermissionCheck :: CA.JsonCodec PermissionCheck codecGotPermissionCheck :: CA.JsonCodec PermissionCheck
codecGotPermissionCheck = CA.object "PermissionCheck" (CAR.record { user: CA.int codecGotPermissionCheck
, service: CA.string = CA.object "PermissionCheck" (CAR.record
, resource: CA.string { user: CA.int
, permission: PermissionLevel.codec }) , service: CA.string
, resource: CA.string
, permission: PermissionLevel.codec })
{- 8 -}
type PermissionSet
= { user :: Int
, service :: String
, resource :: String
, permission :: PermissionLevel.PermissionLevel }
codecGotPermissionSet :: CA.JsonCodec PermissionSet codecGotPermissionSet :: CA.JsonCodec PermissionSet
codecGotPermissionSet = CA.object "PermissionSet" (CAR.record { user: CA.int codecGotPermissionSet
, service: CA.string = CA.object "PermissionSet" (CAR.record
, resource: CA.string { user: CA.int
, permission: PermissionLevel.codec }) , service: CA.string
codecGotContacts ∷ CA.JsonCodec Contacts , resource: CA.string
codecGotContacts = CA.object "Contacts" (CAR.record { user: CA.int , permission: PermissionLevel.codec })
, email: CAR.optional Email.codec
, phone: CAR.optional Phone.codec }) {- 9 -}
type PasswordRecoverySent = { user :: UserPublic.UserPublic }
codecGotPasswordRecoverySent ∷ CA.JsonCodec PasswordRecoverySent
codecGotPasswordRecoverySent
= CA.object "PasswordRecoverySent" (CAR.record { user: UserPublic.codec })
{- 10 -}
type PasswordRecovered = { }
codecGotPasswordRecovered ∷ CA.JsonCodec PasswordRecovered
codecGotPasswordRecovered = CA.object "PasswordRecovered" (CAR.record { })
{- 11 -}
type MatchingUsers = { users :: Array UserPublic.UserPublic }
codecGotMatchingUsers ∷ CA.JsonCodec MatchingUsers codecGotMatchingUsers ∷ CA.JsonCodec MatchingUsers
codecGotMatchingUsers = CA.object "MatchingUsers" (CAR.record { users: CA.array UserPublic.codec }) codecGotMatchingUsers = CA.object "MatchingUsers" (CAR.record { users: CA.array UserPublic.codec })
{- 20 -}
type ErrorMustBeAuthenticated = {}
codecGotErrorMustBeAuthenticated :: CA.JsonCodec ErrorMustBeAuthenticated
codecGotErrorMustBeAuthenticated = CA.object "ErrorMustBeAuthenticated" (CAR.record {})
{- 21 -}
type ErrorAlreadyUsedLogin = {}
codecGotErrorAlreadyUsedLogin :: CA.JsonCodec ErrorAlreadyUsedLogin
codecGotErrorAlreadyUsedLogin = CA.object "ErrorAlreadyUsedLogin" (CAR.record {})
{- 22 -}
type ErrorMailRequired = {}
codecGotErrorMailRequired :: CA.JsonCodec ErrorMailRequired
codecGotErrorMailRequired = CA.object "ErrorMailRequired" (CAR.record {})
{- 23 -}
type ErrorUserNotFound = {}
codecGotErrorUserNotFound :: CA.JsonCodec ErrorUserNotFound
codecGotErrorUserNotFound = CA.object "ErrorUserNotFound" (CAR.record {})
{- 24 -}
type ErrorPasswordTooShort = {}
codecGotErrorPasswordTooShort :: CA.JsonCodec ErrorPasswordTooShort
codecGotErrorPasswordTooShort = CA.object "ErrorPasswordTooShort" (CAR.record {})
{- 25 -}
type ErrorInvalidCredentials = {}
codecGotErrorInvalidCredentials :: CA.JsonCodec ErrorInvalidCredentials
codecGotErrorInvalidCredentials = CA.object "ErrorInvalidCredentials" (CAR.record {})
{- 26 -}
type ErrorRegistrationsClosed = {}
codecGotErrorRegistrationsClosed :: CA.JsonCodec ErrorRegistrationsClosed
codecGotErrorRegistrationsClosed = CA.object "ErrorRegistrationsClosed" (CAR.record {})
{- 27 -}
type ErrorInvalidLoginFormat = {}
codecGotErrorInvalidLoginFormat :: CA.JsonCodec ErrorInvalidLoginFormat
codecGotErrorInvalidLoginFormat = CA.object "ErrorInvalidLoginFormat" (CAR.record {})
{- 28 -}
type ErrorInvalidEmailFormat = {}
codecGotErrorInvalidEmailFormat :: CA.JsonCodec ErrorInvalidEmailFormat
codecGotErrorInvalidEmailFormat = CA.object "ErrorInvalidEmailFormat" (CAR.record {})
{- 29 -}
type ErrorAlreadyUsersInDB = {}
codecGotErrorAlreadyUsersInDB :: CA.JsonCodec ErrorAlreadyUsersInDB
codecGotErrorAlreadyUsersInDB = CA.object "ErrorAlreadyUsersInDB" (CAR.record {})
{- 30 -}
type ErrorReadOnlyProfileKeys = { read_only_keys :: Array String }
codecGotErrorReadOnlyProfileKeys :: CA.JsonCodec ErrorReadOnlyProfileKeys
codecGotErrorReadOnlyProfileKeys
= CA.object "ErrorReadOnlyProfileKeys" (CAR.record { read_only_keys: CA.array CA.string })
{- 31 -}
type ErrorInvalidActivationKey = {}
codecGotErrorInvalidActivationKey :: CA.JsonCodec ErrorInvalidActivationKey
codecGotErrorInvalidActivationKey = CA.object "ErrorInvalidActivationKey" (CAR.record {})
{- 32 -}
type ErrorUserAlreadyValidated = {}
codecGotErrorUserAlreadyValidated :: CA.JsonCodec ErrorUserAlreadyValidated
codecGotErrorUserAlreadyValidated = CA.object "ErrorUserAlreadyValidated" (CAR.record {})
{- 33 -}
type ErrorCannotContactUser = {}
codecGotErrorCannotContactUser :: CA.JsonCodec ErrorCannotContactUser
codecGotErrorCannotContactUser = CA.object "ErrorCannotContactUser" (CAR.record {})
{- 34 -}
type ErrorInvalidRenewKey = {}
codecGotErrorInvalidRenewKey :: CA.JsonCodec ErrorInvalidRenewKey
codecGotErrorInvalidRenewKey = CA.object "ErrorInvalidRenewKey" (CAR.record {})
-- All possible requests. -- All possible requests.
data RequestMessage data RequestMessage
= MkLogin Login -- 0 = MkLogin Login -- 0
@ -240,19 +342,33 @@ data RequestMessage
-- All possible answers from the authentication daemon (authd). -- All possible answers from the authentication daemon (authd).
data AnswerMessage data AnswerMessage
= GotError Error -- 0 = GotError Error -- 0
| GotToken Token -- 1 | GotToken Logged -- 1
| GotUser User -- 2 | GotUser User -- 2
| GotUserAdded UserAdded -- 3 | GotUserAdded UserAdded -- 3
| GotUserEdited UserEdited -- 4 | GotUserEdited UserEdited -- 4
| GotUserValidated UserValidated -- 5 | GotUserValidated UserValidated -- 5
| GotUsersList UsersList -- 6 | GotUsersList UsersList -- 6
| GotPermissionCheck PermissionCheck -- 7 | GotPermissionCheck PermissionCheck -- 7
| GotPermissionSet PermissionSet -- 8 | GotPermissionSet PermissionSet -- 8
| GotPasswordRecoverySent PasswordRecoverySent -- 9 | GotPasswordRecoverySent PasswordRecoverySent -- 9
| GotPasswordRecovered PasswordRecovered -- 10 | GotPasswordRecovered PasswordRecovered -- 10
| GotMatchingUsers MatchingUsers -- 11 | GotMatchingUsers MatchingUsers -- 11
| GotContacts Contacts -- 12 | GotErrorMustBeAuthenticated ErrorMustBeAuthenticated -- 20
| GotErrorAlreadyUsedLogin ErrorAlreadyUsedLogin -- 21
| GotErrorMailRequired ErrorMailRequired -- 22
| GotErrorUserNotFound ErrorUserNotFound -- 23
| GotErrorPasswordTooShort ErrorPasswordTooShort -- 24
| GotErrorInvalidCredentials ErrorInvalidCredentials -- 25
| GotErrorRegistrationsClosed ErrorRegistrationsClosed -- 26
| GotErrorInvalidLoginFormat ErrorInvalidLoginFormat -- 27
| GotErrorInvalidEmailFormat ErrorInvalidEmailFormat -- 28
| GotErrorAlreadyUsersInDB ErrorAlreadyUsersInDB -- 29
| GotErrorReadOnlyProfileKeys ErrorReadOnlyProfileKeys -- 30
| GotErrorInvalidActivationKey ErrorInvalidActivationKey -- 31
| GotErrorUserAlreadyValidated ErrorUserAlreadyValidated -- 32
| GotErrorCannotContactUser ErrorCannotContactUser -- 33
| GotErrorInvalidRenewKey ErrorInvalidRenewKey -- 34
encode ∷ RequestMessage -> Tuple UInt String encode ∷ RequestMessage -> Tuple UInt String
encode m = case m of encode m = case m of
@ -284,19 +400,33 @@ data DecodeError
decode :: Int -> String -> Either DecodeError AnswerMessage decode :: Int -> String -> Either DecodeError AnswerMessage
decode number string decode number string
= case number of = case number of
0 -> error_management codecGotError GotError 0 -> error_management codecGotError GotError
1 -> error_management codecGotToken GotToken 1 -> error_management codecGotToken GotToken
2 -> error_management codecGotUser GotUser 2 -> error_management codecGotUser GotUser
3 -> error_management codecGotUserAdded GotUserAdded 3 -> error_management codecGotUserAdded GotUserAdded
4 -> error_management codecGotUserEdited GotUserEdited 4 -> error_management codecGotUserEdited GotUserEdited
5 -> error_management codecGotUserValidated GotUserValidated 5 -> error_management codecGotUserValidated GotUserValidated
6 -> error_management codecGotUsersList GotUsersList 6 -> error_management codecGotUsersList GotUsersList
7 -> error_management codecGotPermissionCheck GotPermissionCheck 7 -> error_management codecGotPermissionCheck GotPermissionCheck
8 -> error_management codecGotPermissionSet GotPermissionSet 8 -> error_management codecGotPermissionSet GotPermissionSet
9 -> error_management codecGotPasswordRecoverySent GotPasswordRecoverySent 9 -> error_management codecGotPasswordRecoverySent GotPasswordRecoverySent
10 -> error_management codecGotPasswordRecovered GotPasswordRecovered 10 -> error_management codecGotPasswordRecovered GotPasswordRecovered
11 -> error_management codecGotMatchingUsers GotMatchingUsers 11 -> error_management codecGotMatchingUsers GotMatchingUsers
12 -> error_management codecGotContacts GotContacts 20 -> error_management codecGotErrorMustBeAuthenticated GotErrorMustBeAuthenticated
21 -> error_management codecGotErrorAlreadyUsedLogin GotErrorAlreadyUsedLogin
22 -> error_management codecGotErrorMailRequired GotErrorMailRequired
23 -> error_management codecGotErrorUserNotFound GotErrorUserNotFound
24 -> error_management codecGotErrorPasswordTooShort GotErrorPasswordTooShort
25 -> error_management codecGotErrorInvalidCredentials GotErrorInvalidCredentials
26 -> error_management codecGotErrorRegistrationsClosed GotErrorRegistrationsClosed
27 -> error_management codecGotErrorInvalidLoginFormat GotErrorInvalidLoginFormat
28 -> error_management codecGotErrorInvalidEmailFormat GotErrorInvalidEmailFormat
29 -> error_management codecGotErrorAlreadyUsersInDB GotErrorAlreadyUsersInDB
30 -> error_management codecGotErrorReadOnlyProfileKeys GotErrorReadOnlyProfileKeys
31 -> error_management codecGotErrorInvalidActivationKey GotErrorInvalidActivationKey
32 -> error_management codecGotErrorUserAlreadyValidated GotErrorUserAlreadyValidated
33 -> error_management codecGotErrorCannotContactUser GotErrorCannotContactUser
34 -> error_management codecGotErrorInvalidRenewKey GotErrorInvalidRenewKey
_ -> Left UnknownNumber _ -> Left UnknownNumber
where where
-- Signature is required since the compiler's guess is wrong. -- Signature is required since the compiler's guess is wrong.

View File

@ -1,20 +0,0 @@
-- | TODO: Phone module should include at least some sort of smart
-- | constructors, rejecting invalid phone numbers.
module App.Phone where
import Prelude
import Data.Codec.Argonaut (JsonCodec)
import Data.Codec.Argonaut as CA
import Data.Newtype (class Newtype)
import Data.Profunctor (wrapIso)
newtype Phone = Phone String
derive instance newtypePhone :: Newtype Phone _
derive instance eqPhone :: Eq Phone
derive instance ordPhone :: Ord Phone
-- | Phone.codec can be used to parse and encode phone numbers.
codec :: JsonCodec Phone
codec = wrapIso Phone CA.string