DNSManager messages: still WIP.

beta
Philippe Pittoli 2023-06-17 16:04:26 +02:00
parent 6fb46022fe
commit 7f50ad1ffe
2 changed files with 113 additions and 357 deletions

View File

@ -0,0 +1,21 @@
module App.MaintenanceSubject where
import Data.Codec.Argonaut as CA
import Data.Maybe (Maybe(..))
data MaintenanceSubject
= Verbosity
-- | Codec for just encoding a single value of type `MaintenanceSubject`
codec :: CA.JsonCodec MaintenanceSubject
codec =
CA.prismaticCodec "MaintenanceSubject" from to CA.string
where
from :: String -> Maybe MaintenanceSubject
from = case _ of
"verbosity" -> Just None
_ -> Nothing
to :: MaintenanceSubject -> String
to = case _ of
Verbosity -> "verbosity"

View File

@ -22,16 +22,14 @@ import Data.Bifunctor (lmap)
import App.IPC as IPC
type Password = String
{- UserID should be in a separate module with a dedicated codec. -}
type UserID = Int -- UserID is either a login or an uid number
{- 7 -}
-- data MaintenanceSubject = Verbosity
-- type Maintenance = { subject :: MaintenanceSubject, value :: Maybe Int }
-- codecMaintenance = CA.object "Maintenance" (CAR.record { subject: CA.string, value: CA.int })
data MaintenanceSubject = Verbosity
type Maintenance = { subject :: MaintenanceSubject, value :: Maybe Int }
codecMaintenance = CA.object "Maintenance" (CAR.record { subject: CA.string, value: CA.int })
{- 0 -}
type Login = { token :: String }
@ -66,359 +64,113 @@ codecDeleteRR = CA.object "DeleteRR" (CAR.record { domain: CA.string, rrid: CA.i
{- 0 -}
type Login = { login :: String, password :: String }
codecLogin ∷ CA.JsonCodec Login
codecLogin = CA.object "Login" (CAR.record { login: CA.string, password: CA.string })
{- 1 -}
type Register = { login :: String
, password :: Password
, email :: Maybe Email.Email
{-, profile :: Maybe Hash(String, JSON::Any) -} }
codecRegister ∷ CA.JsonCodec Register
codecRegister
= CA.object "Register" (CAR.record
{ login: CA.string
, password: CA.string
, email: CAR.optional Email.codec })
{- 2 -}
type ValidateUser = { user :: UserID, activation_key :: String }
codecValidateUser ∷ CA.JsonCodec ValidateUser
codecValidateUser
= CA.object "ValidateUser" (CAR.record
{ user: CA.int
, activation_key: CA.string })
{- NOTE: "user" attribute for both PasswordRecovery and AskPasswordRecovery could be UserID,
but they'll be used as login since the user has to type it. -}
{- 3 -}
type AskPasswordRecovery = { user :: String }
codecAskPasswordRecovery ∷ CA.JsonCodec AskPasswordRecovery
codecAskPasswordRecovery = CA.object "AskPasswordRecovery" (CAR.record { user: CA.string })
{- 4 -}
type PasswordRecovery = { user :: String
, password_renew_key :: String
, new_password :: Password }
codecPasswordRecovery ∷ CA.JsonCodec PasswordRecovery
codecPasswordRecovery
= CA.object "PasswordRecovery" (CAR.record
{ user: CA.string
, password_renew_key: CA.string
, new_password: CA.string })
{- 5 -}
-- I'll split a message in two: either get a user by UID or by name.
-- TODO: change it for an Either Int String type.
type GetUserByUID = { user :: Int }
type GetUserByName = { user :: String }
codecGetUserByUID ∷ CA.JsonCodec GetUserByUID
codecGetUserByUID = CA.object "GetUserByUID" (CAR.record { user: CA.int })
codecGetUserByName ∷ CA.JsonCodec GetUserByName
codecGetUserByName = CA.object "GetUserByName" (CAR.record { user: CA.string })
{- 6 -}
type ModUser = { user :: Maybe UserID
, admin :: Maybe Boolean
, password :: Maybe Password
, email :: Maybe Email.Email }
codecModUser ∷ CA.JsonCodec ModUser
codecModUser
= CA.object "ModUser" (CAR.record
{ user: CAR.optional CA.int
, admin: CAR.optional CA.boolean
, password: CAR.optional CA.string
, email: CAR.optional Email.codec })
{- 7 -}
{- type EditProfileEntries = { user :: Maybe UserID
, new_profile_entries :: Hash(String, JSON::Any) } -}
{- 8 -}
type DeleteUser = { user :: Maybe UserID }
codecDeleteUser ∷ CA.JsonCodec DeleteUser
codecDeleteUser = CA.object "DeleteUser" (CAR.record { user: CAR.optional CA.int })
{- 9 -}
type AddUser = { login :: String
, password :: Password
, admin :: Boolean
, email :: Maybe Email.Email
{-, profile :: Maybe Hash(String, JSON::Any) -} }
codecAddUser ∷ CA.JsonCodec AddUser
codecAddUser
= CA.object "AddUser" (CAR.record
{ login: CA.string
, password: CA.string
, admin: CA.boolean
, email: CAR.optional Email.codec
{-, profile :: Maybe Hash(String, JSON::Any) -} })
{- 10 -}
type CheckPermission = { user :: Maybe UserID, service :: String, resource :: String }
codecCheckPermission ∷ CA.JsonCodec CheckPermission
codecCheckPermission
= CA.object "CheckPermission" (CAR.record
{ user: CAR.optional CA.int
, service: CA.string
, resource: CA.string })
{- 11 -}
type SetPermission = { user :: UserID
, service :: String
, resource :: String
, permission :: PermissionLevel.PermissionLevel }
codecSetPermission ∷ CA.JsonCodec SetPermission
codecSetPermission
= CA.object "SetPermission" (CAR.record
{ user: CA.int
, service: CA.string
, resource: CA.string
, permission: PermissionLevel.codec })
{- 12 -}
type SearchUser = { regex :: Maybe String, offset :: Maybe Int }
codecSearchUser ∷ CA.JsonCodec SearchUser
codecSearchUser
= CA.object "SearchUser" (CAR.record
{ regex: CAR.optional CA.string
, offset: CAR.optional CA.int })
{-
RESPONSES
-}
-- TODO: note to myself: messages seem chaotic. Could be simpler. Should be simpler.
-- TODO: Zone actually is a complex data structure.
type DNSZone = String
{- 0 -}
type Error = { reason :: Maybe String }
-- type Error = { reason :: String | Array(String) }
type Error = { reason :: String }
codecGotError ∷ CA.JsonCodec Error
codecGotError = CA.object "Error" (CAR.record { reason: CAR.optional CA.string })
codecGotError = CA.object "Error" (CAR.record { reason: CA.string })
{- 1 -}
type Logged = { uid :: Int, token :: String }
codecGotToken ∷ CA.JsonCodec Logged
codecGotToken = CA.object "Logged" (CAR.record { "uid": CA.int, "token": CA.string })
type Success = { }
codecSuccess ∷ CA.JsonCodec Success
codecSuccess = CA.object "Success" (CAR.record { })
{- 2 -}
type User = { user :: UserPublic.UserPublic }
codecGotUser ∷ CA.JsonCodec User
codecGotUser = CA.object "User" (CAR.record { user: UserPublic.codec })
type ErrorInvalidToken = { }
codecErrorInvalidToken ∷ CA.JsonCodec ErrorInvalidToken
codecErrorInvalidToken = CA.object "ErrorInvalidToken" (CAR.record { })
{- 3 -}
type UserAdded = { user :: UserPublic.UserPublic }
codecGotUserAdded ∷ CA.JsonCodec UserAdded
codecGotUserAdded = CA.object "UserAdded" (CAR.record { user: UserPublic.codec })
type DomainAlreadyExists = { }
codecDomainAlreadyExists ∷ CA.JsonCodec DomainAlreadyExists
codecDomainAlreadyExists = CA.object "DomainAlreadyExists" (CAR.record { })
{- 4 -}
type UserEdited = { uid :: Int }
codecGotUserEdited ∷ CA.JsonCodec UserEdited
codecGotUserEdited = CA.object "UserEdited" (CAR.record { "uid": CA.int })
{- 10 -}
-- For now, Error is just an alias on String.
-- type InvalidZone = { errors : Array(Storage::Zone::Error) }
type InvalidZone = { errors :: Array String }
codecInvalidZone ∷ CA.JsonCodec InvalidZone
codecInvalidZone = CA.object "InvalidZone" (CAR.record { errors: CA.array CA.string })
{- 5 -}
type UserValidated = { user :: UserPublic.UserPublic }
codecGotUserValidated ∷ CA.JsonCodec UserValidated
codecGotUserValidated = CA.object "UserValidated" (CAR.record { user: UserPublic.codec })
{- 11 -}
type DomainChanged = { }
codecDomainChanged ∷ CA.JsonCodec DomainChanged
codecDomainChanged = CA.object "DomainChanged" (CAR.record { })
{- 6 -}
type UsersList = { users :: Array UserPublic.UserPublic }
codecGotUsersList ∷ CA.JsonCodec UsersList
codecGotUsersList = CA.object "UsersList" (CAR.record { users: CA.array UserPublic.codec })
{- 12 -}
-- TODO
type Zone = { zone :: DNSZone }
codecZone ∷ CA.JsonCodec Zone
codecZone = CA.object "Zone" (CAR.record { zone: CA.string })
{- 7 -}
type PermissionCheck
= { user :: Int
, service :: String
, resource :: String
, permission :: PermissionLevel.PermissionLevel }
codecGotPermissionCheck :: CA.JsonCodec PermissionCheck
codecGotPermissionCheck
= CA.object "PermissionCheck" (CAR.record
{ user: CA.int
, service: CA.string
, resource: CA.string
, permission: PermissionLevel.codec })
{- 13 -}
type UnknownZone = { }
codecUnknownZone ∷ CA.JsonCodec UnknownZone
codecUnknownZone = CA.object "UnknownZone" (CAR.record { })
{- 8 -}
type PermissionSet
= { user :: Int
, service :: String
, resource :: String
, permission :: PermissionLevel.PermissionLevel }
codecGotPermissionSet :: CA.JsonCodec PermissionSet
codecGotPermissionSet
= CA.object "PermissionSet" (CAR.record
{ user: CA.int
, service: CA.string
, resource: CA.string
, permission: PermissionLevel.codec })
{- 14 -}
type DomainList = { domains :: Array String }
codecDomainList ∷ CA.JsonCodec DomainList
codecDomainList = CA.object "DomainList" (CAR.record { domains: CA.array CA.string })
{- 9 -}
type PasswordRecoverySent = { user :: UserPublic.UserPublic }
codecGotPasswordRecoverySent ∷ CA.JsonCodec PasswordRecoverySent
codecGotPasswordRecoverySent
= CA.object "PasswordRecoverySent" (CAR.record { user: UserPublic.codec })
{- 50 -}
type UnknownUser = { }
codecUnknownUser ∷ CA.JsonCodec UnknownUser
codecUnknownUser = CA.object "UnknownUser" (CAR.record { })
{- 10 -}
type PasswordRecovered = { }
codecGotPasswordRecovered ∷ CA.JsonCodec PasswordRecovered
codecGotPasswordRecovered = CA.object "PasswordRecovered" (CAR.record { })
{- 51 -}
type NoOwnership = { }
codecNoOwnership ∷ CA.JsonCodec NoOwnership
codecNoOwnership = CA.object "NoOwnership" (CAR.record { })
{- 11 -}
type MatchingUsers = { users :: Array UserPublic.UserPublic }
codecGotMatchingUsers ∷ CA.JsonCodec MatchingUsers
codecGotMatchingUsers = CA.object "MatchingUsers" (CAR.record { users: CA.array UserPublic.codec })
{- 12 -}
type UserDeleted = { uid :: Int }
codecGotUserDeleted ∷ CA.JsonCodec UserDeleted
codecGotUserDeleted = CA.object "UserDeleted" (CAR.record { uid: CA.int })
{- 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.
data RequestMessage
= MkLogin Login -- 0
| MkRegister Register -- 1
| MkValidateUser ValidateUser -- 2
| MkAskPasswordRecovery AskPasswordRecovery -- 3
| MkPasswordRecovery PasswordRecovery -- 4
| MkGetUserByUID GetUserByUID -- 5
| MkGetUserByName GetUserByName -- 5 (bis)
| MkModUser ModUser -- 6
--| MkEditProfileContent EditProfileContent -- 7
| MkDeleteUser DeleteUser -- 8
| MkAddUser AddUser -- 9
| MkCheckPermission CheckPermission -- 10
| MkSetPermission SetPermission -- 11
| MkSearchUser SearchUser -- 12
= MkLogin Login -- 0
| MkMaintenance Maintenance -- 7
| MkNewDomain NewDomain -- 9
| MkAddOrUpdateZone AddOrUpdateZone -- 10
| MkDeleteZone DeleteZone -- 11
| MkGetZone GetZone -- 12
| MkUserDomains UserDomains -- 13
| MkAddRR AddRR -- 14
| MkUpdateRR UpdateRR -- 15
| MkDeleteRR DeleteRR -- 16
-- All possible answers from the authentication daemon (authd).
data AnswerMessage
= GotError Error -- 0
| GotToken Logged -- 1
| GotUser User -- 2
| GotUserAdded UserAdded -- 3
| GotUserEdited UserEdited -- 4
| GotUserValidated UserValidated -- 5
| GotUsersList UsersList -- 6
| GotPermissionCheck PermissionCheck -- 7
| GotPermissionSet PermissionSet -- 8
| GotPasswordRecoverySent PasswordRecoverySent -- 9
| GotPasswordRecovered PasswordRecovered -- 10
| GotMatchingUsers MatchingUsers -- 11
| GotUserDeleted UserDeleted -- 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
= MkError Error -- 0
| MkSuccess Success -- 1
| MkErrorInvalidToken ErrorInvalidToken -- 2
| MkDomainAlreadyExists DomainAlreadyExists -- 3
| MkInvalidZone InvalidZone -- 10
| MkDomainChanged DomainChanged -- 11
| MkZone Zone -- 12
| MkUnknownZone UnknownZone -- 13
| MkDomainList DomainList -- 14
| MkUnknownUser UnknownUser -- 50
| MkNoOwnership NoOwnership -- 51
encode ∷ RequestMessage -> Tuple UInt String
encode m = case m of
(MkLogin request) -> get_tuple 0 codecLogin request
(MkRegister request) -> get_tuple 1 codecRegister request
(MkValidateUser request) -> get_tuple 2 codecValidateUser request
(MkAskPasswordRecovery request) -> get_tuple 3 codecAskPasswordRecovery request
(MkPasswordRecovery request) -> get_tuple 4 codecPasswordRecovery request
-- Both messages are actually a single message type, so they have the same number.
-- TODO: change the message codec for an Either Int String.
(MkGetUserByUID request) -> get_tuple 5 codecGetUserByUID request
(MkGetUserByName request) -> get_tuple 5 codecGetUserByName request
(MkModUser request) -> get_tuple 6 codecModUser request
-- 7 MkEditProfileContent
(MkDeleteUser request) -> get_tuple 8 codecDeleteUser request
(MkAddUser request) -> get_tuple 9 codecAddUser request
(MkCheckPermission request) -> get_tuple 10 codecCheckPermission request
(MkSetPermission request) -> get_tuple 11 codecSetPermission request
(MkSearchUser request) -> get_tuple 12 codecSearchUser request
(MkLogin request) -> get_tuple 0 codecLogin request
(MkMaintenance request) -> get_tuple 7 codecMaintenance request
(MkNewDomain request) -> get_tuple 9 codecNewDomain request
(MkAddOrUpdateZone request) -> get_tuple 10 codecAddOrUpdateZone request
(MkDeleteZone request) -> get_tuple 11 codecDeleteZone request
(MkGetZone request) -> get_tuple 12 codecGetZone request
(MkUserDomains request) -> get_tuple 13 codecUserDomains request
(MkAddRR request) -> get_tuple 14 codecAddRR request
(MkUpdateRR request) -> get_tuple 15 codecUpdateRR request
(MkDeleteRR request) -> get_tuple 16 codecDeleteRR request
where
get_tuple :: forall a. Int -> CA.JsonCodec a -> a -> Tuple UInt String
get_tuple num codec request = Tuple (fromInt num) (J.stringify $ CA.encode codec request)
@ -431,34 +183,17 @@ data DecodeError
decode :: Int -> String -> Either DecodeError AnswerMessage
decode number string
= case number of
0 -> error_management codecGotError GotError
1 -> error_management codecGotToken GotToken
2 -> error_management codecGotUser GotUser
3 -> error_management codecGotUserAdded GotUserAdded
4 -> error_management codecGotUserEdited GotUserEdited
5 -> error_management codecGotUserValidated GotUserValidated
6 -> error_management codecGotUsersList GotUsersList
7 -> error_management codecGotPermissionCheck GotPermissionCheck
8 -> error_management codecGotPermissionSet GotPermissionSet
9 -> error_management codecGotPasswordRecoverySent GotPasswordRecoverySent
10 -> error_management codecGotPasswordRecovered GotPasswordRecovered
11 -> error_management codecGotMatchingUsers GotMatchingUsers
12 -> error_management codecGotUserDeleted GotUserDeleted
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
0 -> error_management codecError MkError
1 -> error_management codecSuccess MkSuccess
2 -> error_management codecErrorInvalidToken MkErrorInvalidToken
3 -> error_management codecDomainAlreadyExists MkDomainAlreadyExists
10 -> error_management codecInvalidZone MkInvalidZone
11 -> error_management codecDomainChanged MkDomainChanged
12 -> error_management codecZone MkZone
13 -> error_management codecUnknownZone MkUnknownZone
14 -> error_management codecDomainList MkDomainList
50 -> error_management codecUnknownUser MkUnknownUser
51 -> error_management codecNoOwnership MkNoOwnership
_ -> Left UnknownNumber
where
-- Signature is required since the compiler's guess is wrong.