SimpleX-Chat/specification/Simplex/Messaging/Protocol.idr

298 lines
11 KiB
Idris
Raw Normal View History

2020-05-08 10:17:20 +01:00
module Simplex.Messaging.Protocol
2020-05-07 13:43:09 +01:00
%access public export
2020-05-07 13:43:09 +01:00
data Participant = Recipient | Sender | Broker
2020-05-07 17:58:42 +01:00
data Client : Participant -> Type where
CRecipient : Client Recipient
CSender : Client Sender
2020-05-07 17:19:17 +01:00
Key : Type
Key = String
2020-05-07 17:58:42 +01:00
PrivateKey : Type
PrivateKey = String
-- Data structures for participants to store and pass connection information
data Conn : Type where -- connection info shared between a client and broker
MkConn : (id : String) -- connection ID to identify it with the broker
-> (key : Key) -- public key for broker to verify commands
-> Conn
2020-05-07 13:43:09 +01:00
record ClientConn where
constructor MkClientConn
2020-05-07 17:58:42 +01:00
conn : Conn -- same info that broker has for this client
label : String -- label for the client to identify connection
broker : String -- broker URI
brokerPrivateKey : PrivateKey -- private key to sign commands to broker
2020-05-07 13:43:09 +01:00
2020-05-07 17:19:17 +01:00
newClientConn : ClientConn
2020-05-07 17:58:42 +01:00
newClientConn = MkClientConn (MkConn "" "") "" "" ""
2020-05-07 17:19:17 +01:00
2020-05-07 17:58:42 +01:00
record RcpConn where -- recipient connection data
constructor MkRcpConn
clientConn : ClientConn
senderPrivateKey : PrivateKey -- private key to decrypt sender messages
2020-05-07 13:43:09 +01:00
2020-05-07 17:58:42 +01:00
newRcpConn : RcpConn
newRcpConn = MkRcpConn newClientConn ""
2020-05-07 17:19:17 +01:00
2020-05-07 17:58:42 +01:00
record Invitation where -- out of band message to sender inviting to connect
constructor MkInvitation
conn : Conn
broker : String
senderKey : Key -- public key for sender to encrypt messages
newInvitation : Invitation
newInvitation = MkInvitation (MkConn "" "") "" ""
record SndConn where -- sender connection data
constructor MkSndConn
clientConn : ClientConn
senderKey : Key -- public key for sender to encrypt messages
2020-05-07 13:43:09 +01:00
2020-05-07 17:58:42 +01:00
newSndConn : SndConn
newSndConn = MkSndConn newClientConn ""
2020-05-07 17:19:17 +01:00
2020-05-07 17:58:42 +01:00
-- connection states for all participants
2020-05-07 17:19:17 +01:00
data ConnectionState = -- connection states for all participants
New -- (participants: all) connection created (or received from sender)
| Pending -- (recipient) sent to sender out-of-band
| Confirmed -- (recipient) confirmed by sender with the broker
| Secured -- (all) secured with the broker
| Disabled -- (broker, recipient) disabled with the broker by recipient
| Drained -- (broker, recipient) drained (no messages)
| Null -- (all) not available or removed from the broker
-- broker connection states
data BrokerCS : ConnectionState -> Type where
BNew : BrokerCS New
BSecured : BrokerCS Secured
BDisabled : BrokerCS Disabled
BDrained : BrokerCS Drained
BNull : BrokerCS Null
-- sender connection states
data SenderCS : ConnectionState -> Type where
SNew : SenderCS New
SConfirmed : SenderCS Confirmed
SSecured : SenderCS Secured
SNull : SenderCS Null
2020-05-07 18:45:19 +01:00
-- allowed participant connection states
data HasState : (p : Participant) -> (s : ConnectionState) -> Type where
BHasState : {auto prf : BrokerCS s} -> HasState Broker s
RHasState : HasState Recipient s
SHasState : {auto prf : SenderCS s} -> HasState Sender s
2020-05-07 17:19:17 +01:00
-- established connection states (used by broker and recipient)
2020-05-08 10:12:51 +01:00
data EstablishedState : ConnectionState -> Type where
ESecured : EstablishedState Secured
EDisabled : EstablishedState Disabled
EDrained : EstablishedState Drained
2020-05-07 17:19:17 +01:00
2020-05-07 18:05:05 +01:00
-- dependent types to represent connections for all participants
2020-05-07 17:58:42 +01:00
2020-05-08 10:12:51 +01:00
data BrokerConn : (state : ConnectionState)
-> {auto prf : HasState Broker state}
-> Type where
2020-05-07 17:19:17 +01:00
BCNew : (recipient : Conn) -> (senderId : String) -> BrokerConn New
MkBrkConn : (state : ConnectionState)
-> (recipient : Conn)
-> (sender : Conn)
2020-05-08 10:12:51 +01:00
-> {auto prf : HasState Broker state}
-> {auto prf : EstablishedState state}
2020-05-07 17:19:17 +01:00
-> BrokerConn state
-- 3 constructors below are equivalent to MkBrkConn with some state
BCSecured : (recipient : Conn) -> (sender : Conn) -> BrokerConn Secured
BCDisabled : (recipient : Conn) -> (sender : Conn) -> BrokerConn Disabled
BCDrained : (recipient : Conn) -> (sender : Conn) -> BrokerConn Drained
2020-05-07 13:43:09 +01:00
--
2020-05-07 17:19:17 +01:00
BCNull : (id : String) -> BrokerConn Null
-- good broker connection sample
goodBrkConn : BrokerConn Secured
goodBrkConn = MkBrkConn Secured (MkConn "1" "1") (MkConn "2" "2")
-- bad broker connection sample - does not type check
-- badBrkConn : BrokerConn Null
-- badBrkConn = BCEstablished Null (MkConn "1" "1") (MkConn "2" "2")
data RecipientConn : (state : ConnectionState) -> Type where
2020-05-07 17:58:42 +01:00
RCNew : (conn : RcpConn) -> (sender : Invitation) -> RecipientConn New
RCPending : (conn : RcpConn) -> (sender : Invitation) -> RecipientConn Pending
RCConfirmed : (conn : RcpConn) -> (sender : Conn) -> RecipientConn Confirmed
MkRecipientConn : (state : ConnectionState)
-> (conn : RcpConn)
2020-05-08 10:12:51 +01:00
-> {auto prf : EstablishedState state}
2020-05-07 17:58:42 +01:00
-> RecipientConn state
2020-05-07 17:19:17 +01:00
-- 3 constructors below are equivalent to MkRcpConn with some state
2020-05-07 17:58:42 +01:00
RCSecured : (conn : RcpConn) -> RecipientConn Secured
RCDisabled : (conn : RcpConn) -> RecipientConn Disabled
RCDrained : (conn : RcpConn) -> RecipientConn Drained
2020-05-07 13:43:09 +01:00
--
2020-05-07 17:58:42 +01:00
RCNull : (conn : RcpConn) -> RecipientConn Null
2020-05-07 17:19:17 +01:00
-- recipient connection sample
goodRcpConn : RecipientConn Secured
2020-05-07 17:58:42 +01:00
goodRcpConn = MkRecipientConn Secured (record
{ clientConn = record
{ conn = MkConn "1" "1"
, label = "label"
, broker = "broker"
, brokerPrivateKey = "2" }
newClientConn
, senderPrivateKey = "3" }
newRcpConn)
2020-05-07 17:19:17 +01:00
2020-05-08 10:12:51 +01:00
data SenderConn : (state : ConnectionState)
-> {auto prf : HasState Sender state}
-> Type where
2020-05-07 17:58:42 +01:00
SCNew : (conn : Invitation) -> SenderConn New
SCConfirmed : (conn : SndConn) -> SenderConn Confirmed
SCSecured : (conn : SndConn) -> SenderConn Secured
SCNull : (conn : SndConn) -> SenderConn Null
2020-05-07 17:19:17 +01:00
-- sender connection sample
goodSndConn : SenderConn Secured
goodSndConn = SCSecured (record
2020-05-07 17:58:42 +01:00
{ clientConn = record
{ conn = MkConn "1" "1"
, label = "label"
, broker = "broker"
, brokerPrivateKey = "2" }
newClientConn
, senderKey = "3" }
newSndConn)
2020-05-07 13:43:09 +01:00
2020-05-08 10:03:47 +01:00
-- protocol commands that participants send in relation to specific connection
data Result : (a : Type) -> Type where
OK : a -> Result a
Deny : Result a -- access restriction, not some arbitrary error
Err : String -> Result a -- another error
record BrkCreateConnRes where
constructor MkBrkCreateConnRes
connId : String
senderConnId : String
Message : Type
Message = String
2020-05-08 10:03:47 +01:00
-- operator to define connection state change based on the result
infixl 7 <==>, <==|
2020-05-08 10:03:47 +01:00
prefix 8 @@@
prefix 6 ///, >>>
data RBConnState : Type where
(<==>) : (recipient : ConnectionState)
2020-05-08 13:20:49 +01:00
-> (broker : (ConnectionState, Nat)) -- number of messages in connection
-> {auto prf : (\(s, _) => HasState Broker s) broker}
-> RBConnState
2020-05-07 18:45:19 +01:00
data AllConnState : Type where
(<==|) : (rcpBrk : RBConnState)
-> (sender : ConnectionState)
-> {auto prf : HasState Sender sender}
-> AllConnState
(///) : AllConnState
-> (AllConnState -> Result a -> AllConnState)
(///) s' = \s, x => case x of
OK _ => s'
Deny => s
Err _ => s
(>>>) : AllConnState
-> (AllConnState -> Result a -> AllConnState)
(>>>) s = \_, _ => s
2020-05-07 18:45:19 +01:00
data Command : (ty : Type)
-> (from : Participant)
-> (to : Participant)
-> (state : AllConnState)
-> ((state : AllConnState) -> Result ty -> AllConnState)
2020-05-07 18:45:19 +01:00
-> Type where
CreateConn : (recipientBrokerKey : Key)
-> {auto prf : HasState Sender s}
-> Command BrkCreateConnRes
Recipient Broker
2020-05-08 13:20:49 +01:00
(Null <==> (Null, 0) <==| s)
(>>> New <==> (New, 0) <==| s)
Subscribe : Command () Recipient Broker state (>>> state) -- to improve
SendInvite : Invitation
-> {auto prf : HasState Broker s}
-> Command () Recipient Sender
2020-05-08 13:20:49 +01:00
(New <==> (s, n) <==| Null)
(>>> Pending <==> (s, n) <==| New)
ConfirmConn : (senderBrokerKey : Key)
-> Command () Sender Broker
2020-05-08 13:20:49 +01:00
(s <==> (New, n) <==| New)
(>>> s <==> (New, 1 + n) <==| Confirmed)
PushConfirm : {auto prf : HasState Sender s}
-> Command () Broker Recipient
2020-05-08 13:20:49 +01:00
(Pending <==> (New, 1 + n) <==| s)
(>>> Confirmed <==> (New, n) <==| s)
SecureConn : (senderBrokerKey : Key)
-> {auto prf : HasState Sender s}
-> Command () Recipient Broker
2020-05-08 13:20:49 +01:00
(Confirmed <==> (New, n) <==| s)
(>>> Secured <==> (Secured, n) <==| s)
SendWelcome : {auto prf : HasState Broker bs}
-> Command () Sender Broker
2020-05-08 13:20:49 +01:00
(rs <==> (Secured, n) <==| Confirmed)
(>>> rs <==> (Secured, 1 + n) <==| Secured)
PushWelcome : {auto prf : HasState Sender s}
-> Command () Broker Recipient
2020-05-08 13:20:49 +01:00
(Secured <==> (Secured, 1 + n) <==| s)
(>>> Secured <==> (Secured, n) <==| s)
SendMsg : Message
-> Command () Sender Broker
2020-05-08 13:20:49 +01:00
(rs <==> (Secured, n) <==| Secured)
(>>> rs <==> (Secured, 1 + n) <==| Secured)
PushMsg : {auto prf : HasState Sender s}
-> Command () Broker Recipient
2020-05-08 13:33:54 +01:00
(Secured <==> (Secured, n) <==| s)
(>>> Secured <==> (Secured, n) <==| s)
DeleteMsg : {auto prf : HasState Sender s}
-> Command () Recipient Broker
2020-05-08 13:20:49 +01:00
(Secured <==> (Secured, 1 + n) <==| s)
(>>> Secured <==> (Secured, n) <==| s)
2020-05-08 13:33:54 +01:00
Pure : (res : Result a) -> Command a from to state state_fn
(>>=) : Command a from1 to1 state1 state2_fn
-> ((res : Result a) -> Command b from2 to2 (state2_fn state1 res) state3_fn)
-> Command b from1 to2 state1 state3_fn
2020-05-08 13:33:54 +01:00
infix 5 &>
(&>) : (p : Participant)
-> Command a from1 to1 state1 state2_fn
-> {auto prf : p = from1}
-> Command a from1 to1 state1 state2_fn
(&>) _ c = c