mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-04-02 22:26:00 +00:00
* SMP proxy: low level client and server implementation * SMP proxy: server implementation (#1098) * wip * PRXY command * progress * SMP Proxy: client-level implementation (#1101) * buildable * encode messages * update pkey * fix queue types * wrap SEND in proxy lookup * WIP proxy client * WIP * post-rebase fixes * encode something with something * cleanup * update * fix nonce/corrId in batchingTests * WIP: dig into createSMPProxySession * agent * test progress * pass the test * parameterize transport handle with transport peer to include server certificate (#1100) * parameterize transport handle with transport peer to include server certificate * include server certificate into THandle * load server chain and sign key * fix key type * fix for 8.10 --------- Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com> Co-authored-by: IC Rainbow <aenor.realm@gmail.com> * cleanup * add 2-server test * remove subsumed test * checkCredentials for BrokerMsg * skip batching tests * remove userId param * remove agent changes --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com> --------- Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com> * remove unused type * icrease test timeout * reduce transport block * envelope sizes * don't fork unless have proxied commands to process --------- Co-authored-by: Alexander Bondarenko <486682+dpwiz@users.noreply.github.com> Co-authored-by: IC Rainbow <aenor.realm@gmail.com>
138 lines
6.8 KiB
Haskell
138 lines
6.8 KiB
Haskell
{-# LANGUAGE DataKinds #-}
|
|
{-# LANGUAGE DuplicateRecordFields #-}
|
|
{-# LANGUAGE GADTs #-}
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# LANGUAGE RankNTypes #-}
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
{-# LANGUAGE TupleSections #-}
|
|
{-# LANGUAGE TypeApplications #-}
|
|
|
|
module SMPProxyTests where
|
|
|
|
import AgentTests.FunctionalAPITests (runRight_)
|
|
import Data.ByteString.Char8 (ByteString)
|
|
import SMPAgentClient (testSMPServer, testSMPServer2)
|
|
import SMPClient
|
|
import qualified SMPClient as SMP
|
|
import ServerTests (decryptMsgV3, sendRecv)
|
|
import Simplex.Messaging.Client
|
|
import qualified Simplex.Messaging.Crypto as C
|
|
import Simplex.Messaging.Protocol
|
|
import Simplex.Messaging.Server.Env.STM (ServerConfig (..))
|
|
import Simplex.Messaging.Transport
|
|
import Simplex.Messaging.Version (mkVersionRange)
|
|
import Test.Hspec
|
|
import UnliftIO
|
|
|
|
smpProxyTests :: Spec
|
|
smpProxyTests = do
|
|
describe "server configuration" $ do
|
|
it "refuses proxy handshake unless enabled" testNoProxy
|
|
it "checks basic auth in proxy requests" testProxyAuth
|
|
describe "proxy requests" $ do
|
|
describe "bad relay URIs" $ do
|
|
xit "host not resolved" todo
|
|
xit "when SMP port blackholed" todo
|
|
xit "no SMP service at host/port" todo
|
|
xit "bad SMP fingerprint" todo
|
|
xit "batching proxy requests" todo
|
|
describe "forwarding requests" $ do
|
|
describe "deliver message via SMP proxy" $ do
|
|
it "same server" $
|
|
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ -> do
|
|
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
|
|
let relayServ = proxyServ
|
|
deliverMessageViaProxy proxyServ relayServ C.SEd448 "hello 1" "hello 2"
|
|
it "different servers" $
|
|
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ ->
|
|
withSmpServerConfigOn (transport @TLS) cfgV7 testPort2 $ \_ -> do
|
|
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
|
|
let relayServ = SMPServer SMP.testHost SMP.testPort2 SMP.testKeyHash
|
|
deliverMessageViaProxy proxyServ relayServ C.SEd448 "hello 1" "hello 2"
|
|
xit "max message size, Ed448 keys" $
|
|
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ ->
|
|
withSmpServerConfigOn (transport @TLS) cfgV7 testPort2 $ \_ -> do
|
|
g <- C.newRandom
|
|
msg <- atomically $ C.randomBytes maxMessageLength g
|
|
msg' <- atomically $ C.randomBytes maxMessageLength g
|
|
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
|
|
let relayServ = SMPServer SMP.testHost SMP.testPort2 SMP.testKeyHash
|
|
deliverMessageViaProxy proxyServ relayServ C.SEd448 msg msg'
|
|
it "max message size, Ed25519 keys" $
|
|
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ ->
|
|
withSmpServerConfigOn (transport @TLS) cfgV7 testPort2 $ \_ -> do
|
|
g <- C.newRandom
|
|
msg <- atomically $ C.randomBytes maxMessageLength g
|
|
msg' <- atomically $ C.randomBytes maxMessageLength g
|
|
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
|
|
let relayServ = SMPServer SMP.testHost SMP.testPort2 SMP.testKeyHash
|
|
deliverMessageViaProxy proxyServ relayServ C.SEd25519 msg msg'
|
|
it "max message size, X25519 keys" $
|
|
withSmpServerConfigOn (transport @TLS) proxyCfg testPort $ \_ ->
|
|
withSmpServerConfigOn (transport @TLS) cfgV7 testPort2 $ \_ -> do
|
|
g <- C.newRandom
|
|
msg <- atomically $ C.randomBytes maxMessageLength g
|
|
msg' <- atomically $ C.randomBytes maxMessageLength g
|
|
let proxyServ = SMPServer SMP.testHost SMP.testPort SMP.testKeyHash
|
|
let relayServ = SMPServer SMP.testHost SMP.testPort2 SMP.testKeyHash
|
|
deliverMessageViaProxy proxyServ relayServ C.SX25519 msg msg'
|
|
xit "sender-proxy-relay-recipient works" todo
|
|
xit "similar timing for proxied and direct sends" todo
|
|
|
|
deliverMessageViaProxy :: (C.AlgorithmI a, C.AuthAlgorithm a) => SMPServer -> SMPServer -> C.SAlgorithm a -> ByteString -> ByteString -> IO ()
|
|
deliverMessageViaProxy proxyServ relayServ alg msg msg' = do
|
|
g <- C.newRandom
|
|
-- set up proxy
|
|
Right pc <- getProtocolClient g (1, proxyServ, Nothing) defaultSMPClientConfig {serverVRange = mkVersionRange batchCmdsSMPVersion sendingProxySMPVersion} Nothing (\_ -> pure ())
|
|
THAuthClient {} <- maybe (fail "getProtocolClient returned no thAuth") pure $ thAuth $ thParams pc
|
|
-- set up relay
|
|
msgQ <- newTBQueueIO 4
|
|
Right rc <- getProtocolClient g (2, relayServ, Nothing) defaultSMPClientConfig {serverVRange = mkVersionRange batchCmdsSMPVersion authCmdsSMPVersion} (Just msgQ) (\_ -> pure ())
|
|
runRight_ $ do
|
|
-- prepare receiving queue
|
|
(rPub, rPriv) <- atomically $ C.generateAuthKeyPair alg g
|
|
(rdhPub, rdhPriv :: C.PrivateKeyX25519) <- atomically $ C.generateKeyPair g
|
|
QIK {rcvId, sndId, rcvPublicDhKey = srvDh} <- createSMPQueue rc (rPub, rPriv) rdhPub (Just "correct") SMSubscribe
|
|
let dec = decryptMsgV3 $ C.dh' srvDh rdhPriv
|
|
-- get proxy session
|
|
(sessId, v, relayKey) <- createSMPProxySession pc relayServ (Just "correct")
|
|
-- send via proxy to unsecured queue
|
|
proxySMPMessage pc sessId v relayKey Nothing sndId noMsgFlags msg
|
|
-- receive 1
|
|
(_tSess, _v, _sid, _ety, MSG RcvMessage {msgId, msgBody = EncRcvMsgBody encBody}) <- atomically $ readTBQueue msgQ
|
|
liftIO $ dec msgId encBody `shouldBe` Right msg
|
|
ackSMPMessage rc rPriv rcvId msgId
|
|
-- secure queue
|
|
(sPub, sPriv) <- atomically $ C.generateAuthKeyPair alg g
|
|
secureSMPQueue rc rPriv rcvId sPub
|
|
-- send via proxy to secured queue
|
|
proxySMPMessage pc sessId v relayKey (Just sPriv) sndId noMsgFlags msg'
|
|
-- receive 2
|
|
(_tSess, _v, _sid, _ety, MSG RcvMessage {msgId = msgId', msgBody = EncRcvMsgBody encBody'}) <- atomically $ readTBQueue msgQ
|
|
liftIO $ dec msgId' encBody' `shouldBe` Right msg'
|
|
ackSMPMessage rc rPriv rcvId msgId'
|
|
|
|
proxyVRange :: VersionRangeSMP
|
|
proxyVRange = mkVersionRange batchCmdsSMPVersion sendingProxySMPVersion
|
|
|
|
testNoProxy :: IO ()
|
|
testNoProxy = do
|
|
withSmpServerConfigOn (transport @TLS) cfg testPort2 $ \_ -> do
|
|
testSMPClient_ "127.0.0.1" testPort2 proxyVRange $ \(th :: THandleSMP TLS 'TClient) -> do
|
|
(_, _, (_corrId, _entityId, reply)) <- sendRecv th (Nothing, "0", "", PRXY testSMPServer Nothing)
|
|
reply `shouldBe` Right (ERR AUTH)
|
|
|
|
testProxyAuth :: IO ()
|
|
testProxyAuth = do
|
|
withSmpServerConfigOn (transport @TLS) proxyCfgAuth testPort $ \_ -> do
|
|
testSMPClient_ "127.0.0.1" testPort proxyVRange $ \(th :: THandleSMP TLS 'TClient) -> do
|
|
(_, _s, (_corrId, _entityId, reply)) <- sendRecv th (Nothing, "0", "", PRXY testSMPServer2 $ Just "wrong")
|
|
reply `shouldBe` Right (ERR AUTH)
|
|
where
|
|
proxyCfgAuth = proxyCfg {newQueueBasicAuth = Just "correct"}
|
|
|
|
todo :: IO ()
|
|
todo = do
|
|
fail "TODO"
|