mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-08-29 07:48:25 +00:00
agent: binary protocol encoding for connection request (#1503)
* agent: binary protocol encoding for connection request * enable tests * test
This commit is contained in:
@@ -690,19 +690,23 @@ instance Eq AConnectionMode where
|
||||
|
||||
cmInvitation :: AConnectionMode
|
||||
cmInvitation = ACM SCMInvitation
|
||||
{-# INLINE cmInvitation #-}
|
||||
|
||||
cmContact :: AConnectionMode
|
||||
cmContact = ACM SCMContact
|
||||
{-# INLINE cmContact #-}
|
||||
|
||||
deriving instance Show AConnectionMode
|
||||
|
||||
connMode :: SConnectionMode m -> ConnectionMode
|
||||
connMode SCMInvitation = CMInvitation
|
||||
connMode SCMContact = CMContact
|
||||
{-# INLINE connMode #-}
|
||||
|
||||
connMode' :: ConnectionMode -> AConnectionMode
|
||||
connMode' CMInvitation = cmInvitation
|
||||
connMode' CMContact = cmContact
|
||||
{-# INLINE connMode' #-}
|
||||
|
||||
class ConnectionModeI (m :: ConnectionMode) where sConnectionMode :: SConnectionMode m
|
||||
|
||||
@@ -1054,10 +1058,27 @@ instance ConnectionModeI m => StrEncoding (ConnectionRequestUri m) where
|
||||
<> maybe [] (\cd -> [("data", encodeUtf8 cd)]) crClientData
|
||||
strP = connReqUriP' (Just SSSimplex)
|
||||
|
||||
-- TODO [short links] do not use StrEncoding instance
|
||||
instance ConnectionModeI m => Encoding (ConnectionRequestUri m) where
|
||||
smpEncode = smpEncode . Large . strEncode
|
||||
smpP = strDecode . unLarge <$?> smpP
|
||||
smpEncode = \case
|
||||
CRInvitationUri crData e2eParams -> smpEncode (CMInvitation, crData, e2eParams)
|
||||
CRContactUri crData -> smpEncode (CMContact, crData)
|
||||
smpP = (\(ACR _ cr) -> checkConnMode cr) <$?> smpP
|
||||
{-# INLINE smpP #-}
|
||||
|
||||
instance Encoding AConnectionRequestUri where
|
||||
smpEncode (ACR _ cr) = smpEncode cr
|
||||
{-# INLINE smpEncode #-}
|
||||
smpP =
|
||||
smpP >>= \case
|
||||
CMInvitation -> ACR SCMInvitation <$> (CRInvitationUri <$> smpP <*> smpP)
|
||||
CMContact -> ACR SCMContact . CRContactUri <$> smpP
|
||||
|
||||
instance Encoding ConnReqUriData where
|
||||
smpEncode ConnReqUriData {crAgentVRange, crSmpQueues, crClientData} =
|
||||
smpEncode (crAgentVRange, crSmpQueues, Large . encodeUtf8 <$> crClientData)
|
||||
smpP = do
|
||||
(crAgentVRange, crSmpQueues, clientData) <- smpP
|
||||
pure ConnReqUriData {crScheme = SSSimplex, crAgentVRange, crSmpQueues, crClientData = safeDecodeUtf8 . unLarge <$> clientData}
|
||||
|
||||
connReqUriP' :: forall m. ConnectionModeI m => Maybe ServiceScheme -> Parser (ConnectionRequestUri m)
|
||||
connReqUriP' overrideScheme = do
|
||||
@@ -1122,6 +1143,16 @@ instance StrEncoding AConnectionMode where
|
||||
strEncode (ACM cMode) = strEncode $ connMode cMode
|
||||
strP = connMode' <$> strP
|
||||
|
||||
instance Encoding ConnectionMode where
|
||||
smpEncode = \case
|
||||
CMInvitation -> "I"
|
||||
CMContact -> "C"
|
||||
smpP =
|
||||
A.anyChar >>= \case
|
||||
'I' -> pure CMInvitation
|
||||
'C' -> pure CMContact
|
||||
_ -> fail "bad connection mode"
|
||||
|
||||
connModeT :: Text -> Maybe ConnectionMode
|
||||
connModeT = \case
|
||||
"INV" -> Just CMInvitation
|
||||
@@ -1170,7 +1201,7 @@ data SMPQueueInfo = SMPQueueInfo {clientVersion :: VersionSMPC, queueAddress ::
|
||||
|
||||
instance Encoding SMPQueueInfo where
|
||||
smpEncode (SMPQueueInfo clientVersion SMPQueueAddress {smpServer, senderId, dhPublicKey, queueMode})
|
||||
| clientVersion >= shortLinksSMPClientVersion = addrEnc <> smpEncode queueMode
|
||||
| clientVersion >= shortLinksSMPClientVersion = addrEnc <> maybe "" smpEncode queueMode
|
||||
| clientVersion >= sndAuthKeySMPClientVersion && sndSecure = addrEnc <> smpEncode sndSecure
|
||||
| clientVersion > initialSMPClientVersion = addrEnc
|
||||
| otherwise = smpEncode clientVersion <> legacyEncodeServer smpServer <> smpEncode (senderId, dhPublicKey)
|
||||
@@ -1181,7 +1212,7 @@ instance Encoding SMPQueueInfo where
|
||||
clientVersion <- smpP
|
||||
smpServer <- if clientVersion > initialSMPClientVersion then smpP else updateSMPServerHosts <$> legacyServerP
|
||||
(senderId, dhPublicKey) <- smpP
|
||||
queueMode <- smpP <|> optional ((\ss -> if ss then QMMessaging else QMContact) <$> smpP)
|
||||
queueMode <- queueModeP
|
||||
pure $ SMPQueueInfo clientVersion SMPQueueAddress {smpServer, senderId, dhPublicKey, queueMode}
|
||||
|
||||
-- This instance seems contrived and there was a temptation to split a common part of both types.
|
||||
@@ -1276,7 +1307,7 @@ instance Encoding SMPQueueUri where
|
||||
smpEncode (SMPQueueUri clientVRange@(VersionRange minV maxV) SMPQueueAddress {smpServer, senderId, dhPublicKey, queueMode})
|
||||
-- The condition is for minVersion as earlier clients won't be able to support it.
|
||||
-- The alternative would be to encode both queueMode and sndSecure
|
||||
| minV >= shortLinksSMPClientVersion = addrEnc <> smpEncode queueMode
|
||||
| minV >= shortLinksSMPClientVersion = addrEnc <> maybe "" smpEncode queueMode
|
||||
-- Earlier versions won't be able to ignore sndSecure, so we don't include it when it is False
|
||||
| minV >= sndAuthKeySMPClientVersion || (maxV >= sndAuthKeySMPClientVersion && sndSecure) = addrEnc <> smpEncode sndSecure
|
||||
| otherwise = addrEnc
|
||||
@@ -1285,9 +1316,12 @@ instance Encoding SMPQueueUri where
|
||||
sndSecure = senderCanSecure queueMode
|
||||
smpP = do
|
||||
(clientVRange, smpServer, senderId, dhPublicKey) <- smpP
|
||||
queueMode <- smpP <|> optional ((\ss -> if ss then QMMessaging else QMContact) <$> smpP)
|
||||
queueMode <- queueModeP
|
||||
pure $ SMPQueueUri clientVRange SMPQueueAddress {smpServer, senderId, dhPublicKey, queueMode}
|
||||
|
||||
queueModeP :: Parser (Maybe QueueMode)
|
||||
queueModeP = Just <$> smpP <|> optional ((\case True -> QMMessaging; _ -> QMContact) <$> smpP)
|
||||
|
||||
data ConnectionRequestUri (m :: ConnectionMode) where
|
||||
CRInvitationUri :: ConnReqUriData -> RcvE2ERatchetParamsUri 'C.X448 -> ConnectionRequestUri CMInvitation
|
||||
-- contact connection request does NOT contain E2E encryption parameters for double ratchet -
|
||||
@@ -1374,6 +1408,12 @@ sameConnReqContact (CRContactUri ConnReqUriData {crSmpQueues = qs}) (CRContactUr
|
||||
where
|
||||
same (q, q') = sameQAddress (qAddress q) (qAddress q')
|
||||
|
||||
checkConnMode :: forall t m m'. (ConnectionModeI m, ConnectionModeI m') => t m' -> Either String (t m)
|
||||
checkConnMode c = case testEquality (sConnectionMode @m) (sConnectionMode @m') of
|
||||
Just Refl -> Right c
|
||||
Nothing -> Left "bad connection mode"
|
||||
{-# INLINE checkConnMode #-}
|
||||
|
||||
data ConnReqUriData = ConnReqUriData
|
||||
{ crScheme :: ServiceScheme,
|
||||
crAgentVRange :: VersionRangeSMPA,
|
||||
|
||||
@@ -306,11 +306,13 @@ instance (RatchetKEMStateI s, AlgorithmI a) => StrEncoding (E2ERatchetParamsUri
|
||||
| otherwise = case kem of
|
||||
RKParamsProposed k -> [("kem_key", strEncode k)]
|
||||
RKParamsAccepted ct k -> [("kem_ct", strEncode ct), ("kem_key", strEncode k)]
|
||||
strP = toParamsURI <$?> strP
|
||||
where
|
||||
toParamsURI = \case
|
||||
AE2ERatchetParamsUri _ (E2ERatchetParamsUri vr k1 k2 Nothing) -> Right $ E2ERatchetParamsUri vr k1 k2 Nothing
|
||||
AE2ERatchetParamsUri _ ps -> checkRatchetKEMState ps
|
||||
strP = toE2ERatchetParamsUri <$?> strP
|
||||
{-# INLINE strP #-}
|
||||
|
||||
toE2ERatchetParamsUri :: RatchetKEMStateI s => AE2ERatchetParamsUri a -> Either String (E2ERatchetParamsUri s a)
|
||||
toE2ERatchetParamsUri = \case
|
||||
AE2ERatchetParamsUri _ (E2ERatchetParamsUri vr k1 k2 Nothing) -> Right $ E2ERatchetParamsUri vr k1 k2 Nothing
|
||||
AE2ERatchetParamsUri _ ps -> checkRatchetKEMState ps
|
||||
|
||||
instance AlgorithmI a => StrEncoding (AE2ERatchetParamsUri a) where
|
||||
strEncode (AE2ERatchetParamsUri _ ps) = strEncode ps
|
||||
@@ -340,6 +342,33 @@ instance StrEncoding AnyE2ERatchetParamsUri where
|
||||
Nothing -> ARKP SRKSProposed $ RKParamsProposed k
|
||||
Just ct -> ARKP SRKSAccepted $ RKParamsAccepted ct k
|
||||
|
||||
instance (RatchetKEMStateI s, AlgorithmI a) => Encoding (E2ERatchetParamsUri s a) where
|
||||
smpEncode (E2ERatchetParamsUri vr k1 k2 kem_) = smpEncode (vr, k1, k2, kem_)
|
||||
{-# INLINE smpEncode #-}
|
||||
smpP = toE2ERatchetParamsUri <$?> smpP
|
||||
{-# INLINE smpP #-}
|
||||
|
||||
instance AlgorithmI a => Encoding (AE2ERatchetParamsUri a) where
|
||||
smpEncode (AE2ERatchetParamsUri _ ps) = smpEncode ps
|
||||
{-# INLINE smpEncode #-}
|
||||
smpP = (\(AnyE2ERatchetParamsUri s _ ps) -> AE2ERatchetParamsUri s <$> checkAlgorithm ps) <$?> smpP
|
||||
{-# INLINE smpP #-}
|
||||
|
||||
instance Encoding AnyE2ERatchetParamsUri where
|
||||
smpEncode (AnyE2ERatchetParamsUri _ _ ps) = smpEncode ps
|
||||
{-# INLINE smpEncode #-}
|
||||
smpP = do
|
||||
vr <- smpP @VersionRangeE2E
|
||||
APublicDhKey a k1 <- smpP
|
||||
APublicDhKey a' k2 <- smpP
|
||||
case testEquality a a' of
|
||||
Nothing -> fail "bad e2e params: different key algorithms"
|
||||
Just Refl ->
|
||||
let result = \case
|
||||
Just (ARKP s kem) -> AnyE2ERatchetParamsUri s a $ E2ERatchetParamsUri vr k1 k2 (Just kem)
|
||||
Nothing -> AnyE2ERatchetParamsUri SRKSProposed a $ E2ERatchetParamsUri vr k1 k2 Nothing
|
||||
in result <$> smpP
|
||||
|
||||
type RcvE2ERatchetParams a = E2ERatchetParams 'RKSProposed a
|
||||
|
||||
type SndE2ERatchetParams a = AE2ERatchetParams a
|
||||
|
||||
Reference in New Issue
Block a user