mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
core (pq): cross-version tests (#3885)
* core (pq): cross-version tests * next (fails) * enable all tests * fix versions * update simplexmq * tests --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
+1
-1
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/simplexmq.git
|
||||
tag: dab55e0a9b03577f643af7922afa061801d82ed5
|
||||
tag: 851ed2d02e2a78c15893ad8bc9c5a4d917eb6a35
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"https://github.com/simplex-chat/simplexmq.git"."dab55e0a9b03577f643af7922afa061801d82ed5" = "0dzqsvzxby83nla0rpx3xzj2y18lvmgs5ldjv5i1yp52npc88s1m";
|
||||
"https://github.com/simplex-chat/simplexmq.git"."851ed2d02e2a78c15893ad8bc9c5a4d917eb6a35" = "0rm13iknnqhdb42nmyjc2wj85z23p337bp026ihnychax5s1216j";
|
||||
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
|
||||
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
|
||||
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
|
||||
|
||||
+29
-5
@@ -28,6 +28,7 @@ import Simplex.Chat
|
||||
import Simplex.Chat.Controller (ChatCommand (..), ChatConfig (..), ChatController (..), ChatDatabase (..), ChatLogLevel (..))
|
||||
import Simplex.Chat.Core
|
||||
import Simplex.Chat.Options
|
||||
import Simplex.Chat.Protocol (currentChatVersion, pqEncryptionCompressionVersion)
|
||||
import Simplex.Chat.Store
|
||||
import Simplex.Chat.Store.Profiles
|
||||
import Simplex.Chat.Terminal
|
||||
@@ -37,12 +38,13 @@ import Simplex.FileTransfer.Description (kb, mb)
|
||||
import Simplex.FileTransfer.Server (runXFTPServerBlocking)
|
||||
import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..), defaultFileExpiration)
|
||||
import Simplex.Messaging.Agent.Env.SQLite
|
||||
import Simplex.Messaging.Agent.Protocol (supportedSMPAgentVRange, pattern VersionSMPA)
|
||||
import Simplex.Messaging.Agent.Protocol (currentSMPAgentVersion, duplexHandshakeSMPAgentVersion, pqdrSMPAgentVersion, supportedSMPAgentVRange)
|
||||
import Simplex.Messaging.Agent.RetryInterval
|
||||
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..))
|
||||
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
|
||||
import Simplex.Messaging.Client (ProtocolClientConfig (..), defaultNetworkConfig)
|
||||
import Simplex.Messaging.Crypto.Ratchet (supportedE2EEncryptVRange, pattern PQSupportOff, pattern VersionE2E)
|
||||
import Simplex.Messaging.Crypto.Ratchet (supportedE2EEncryptVRange, pattern PQSupportOff)
|
||||
import qualified Simplex.Messaging.Crypto.Ratchet as CR
|
||||
import Simplex.Messaging.Server (runSMPServerBlocking)
|
||||
import Simplex.Messaging.Server.Env.STM
|
||||
import Simplex.Messaging.Transport
|
||||
@@ -147,22 +149,38 @@ testAgentCfgVPrev =
|
||||
smpCfg = (smpCfg testAgentCfg) {serverVRange = prevRange $ serverVRange $ smpCfg testAgentCfg}
|
||||
}
|
||||
|
||||
testAgentCfgVNext :: AgentConfig
|
||||
testAgentCfgVNext =
|
||||
testAgentCfg
|
||||
{ smpClientVRange = nextRange $ smpClientVRange testAgentCfg,
|
||||
smpAgentVRange = \_ -> mkVersionRange duplexHandshakeSMPAgentVersion $ max pqdrSMPAgentVersion currentSMPAgentVersion,
|
||||
e2eEncryptVRange = \_ -> mkVersionRange CR.kdfX3DHE2EEncryptVersion $ max CR.pqRatchetE2EEncryptVersion CR.currentE2EEncryptVersion,
|
||||
smpCfg = (smpCfg testAgentCfg) {serverVRange = nextRange $ serverVRange $ smpCfg testAgentCfg}
|
||||
}
|
||||
|
||||
testAgentCfgV1 :: AgentConfig
|
||||
testAgentCfgV1 =
|
||||
testAgentCfg
|
||||
{ smpClientVRange = v1Range,
|
||||
smpAgentVRange = \_ -> versionToRange (VersionSMPA 2), -- duplexHandshakeSMPAgentVersion,
|
||||
e2eEncryptVRange = \_ -> versionToRange (VersionE2E 2), -- kdfX3DHE2EEncryptVersion,
|
||||
smpAgentVRange = \_ -> versionToRange duplexHandshakeSMPAgentVersion,
|
||||
e2eEncryptVRange = \_ -> versionToRange CR.kdfX3DHE2EEncryptVersion,
|
||||
smpCfg = (smpCfg testAgentCfg) {serverVRange = versionToRange batchCmdsSMPVersion}
|
||||
}
|
||||
|
||||
testCfgVPrev :: ChatConfig
|
||||
testCfgVPrev =
|
||||
testCfg
|
||||
{ chatVRange = prevRange . chatVRange testCfg,
|
||||
{ chatVRange = \_ -> prevRange $ chatVRange testCfg PQSupportOff,
|
||||
agentConfig = testAgentCfgVPrev
|
||||
}
|
||||
|
||||
testCfgVNext :: ChatConfig
|
||||
testCfgVNext =
|
||||
testCfg
|
||||
{ chatVRange = \_ -> mkVersionRange initialChatVersion $ max pqEncryptionCompressionVersion currentChatVersion,
|
||||
agentConfig = testAgentCfgVNext
|
||||
}
|
||||
|
||||
testCfgV1 :: ChatConfig
|
||||
testCfgV1 =
|
||||
testCfg
|
||||
@@ -173,12 +191,18 @@ testCfgV1 =
|
||||
prevRange :: VersionRange v -> VersionRange v
|
||||
prevRange vr = vr {maxVersion = max (minVersion vr) (prevVersion $ maxVersion vr)}
|
||||
|
||||
nextRange :: VersionRange v -> VersionRange v
|
||||
nextRange vr = vr {maxVersion = max (minVersion vr) (nextVersion $ maxVersion vr)}
|
||||
|
||||
v1Range :: VersionRange v
|
||||
v1Range = mkVersionRange (Version 1) (Version 1)
|
||||
|
||||
prevVersion :: Version v -> Version v
|
||||
prevVersion (Version v) = Version (v - 1)
|
||||
|
||||
nextVersion :: Version v -> Version v
|
||||
nextVersion (Version v) = Version (v + 1)
|
||||
|
||||
testCfgCreateGroupDirect :: ChatConfig
|
||||
testCfgCreateGroupDirect =
|
||||
mkCfgCreateGroupDirect testCfg
|
||||
|
||||
@@ -23,9 +23,9 @@ import Simplex.Chat.Controller (ChatConfig (..))
|
||||
import Simplex.Chat.Options (ChatOpts (..))
|
||||
import Simplex.Chat.Protocol (currentChatVersion, pqEncryptionCompressionVersion, supportedChatVRange)
|
||||
import Simplex.Chat.Store (agentStoreFile, chatStoreFile)
|
||||
import Simplex.Chat.Types (VersionRangeChat, authErrDisableCount, sameVerificationCode, verificationCode, pattern VersionChat)
|
||||
import Simplex.Chat.Types (VersionRangeChat, authErrDisableCount, sameVerificationCode, verificationCode, VersionChat, pattern VersionChat)
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Crypto.Ratchet (PQEncryption (..), pattern PQSupportOn, pattern PQSupportOff, pattern PQEncOn, pattern PQEncOff)
|
||||
import Simplex.Messaging.Crypto.Ratchet (PQEncryption (..), pattern PQEncOff, pattern PQEncOn, pattern PQSupportOff, pattern PQSupportOn)
|
||||
import Simplex.Messaging.Util (safeDecodeUtf8)
|
||||
import Simplex.Messaging.Version
|
||||
import System.Directory (copyFile, doesDirectoryExist, doesFileExist)
|
||||
@@ -131,6 +131,8 @@ chatDirectTests = do
|
||||
describe "PQ tests" $ do
|
||||
describe "enable PQ before connection, connect via invitation link" $ pqMatrix2 runTestPQConnectViaLink
|
||||
describe "enable PQ before connection, connect via contact address" $ pqMatrix2 runTestPQConnectViaAddress
|
||||
describe "connect via invitation link with PQ encryption enabled" $ pqVersionTestMatrix2 runTestPQVersionsViaLink
|
||||
describe "connect via contact address with PQ encryption enabled" $ pqVersionTestMatrix2 runTestPQVersionsViaAddress
|
||||
it "should enable PQ after several messages in connection without PQ" testPQEnableContact
|
||||
it "should enable PQ, reduce envelope size and enable compression" testPQEnableContactCompression
|
||||
where
|
||||
@@ -2821,6 +2823,79 @@ runTestPQConnectViaAddress (alice, aPQ) (bob, bPQ) = do
|
||||
pqSend = if pqEnabled then (+#>) else (\#>)
|
||||
e2eeInfo = if pqEnabled then e2eeInfoPQStr else e2eeInfoNoPQStr
|
||||
|
||||
runTestPQVersionsViaLink :: HasCallStack => TestCC -> TestCC -> Bool -> VersionChat -> IO ()
|
||||
runTestPQVersionsViaLink alice bob pqExpected vExpected = do
|
||||
img <- genProfileImgForLink
|
||||
let profileImage = "data:image/png;base64," <> B.unpack img
|
||||
alice `send` ("/set profile image " <> profileImage)
|
||||
_trimmedCmd1 <- getTermLine alice
|
||||
alice <## "profile image updated"
|
||||
bob `send` ("/set profile image " <> profileImage)
|
||||
_trimmedCmd2 <- getTermLine bob
|
||||
bob <## "profile image updated"
|
||||
|
||||
pqOn alice
|
||||
pqOn bob
|
||||
|
||||
connectUsers alice bob
|
||||
|
||||
(alice, "hi", vExpected) `pqSend` (bob, vExpected)
|
||||
(bob, "hey", vExpected) `pqSend` (alice, vExpected)
|
||||
|
||||
alice ##> "/_get chat @2 count=100"
|
||||
ra <- chat <$> getTermLine alice
|
||||
ra `shouldContain` [(0, e2eeInfo)]
|
||||
alice `pqForContact` 2 `shouldReturn` PQEncryption pqExpected
|
||||
|
||||
bob ##> "/_get chat @2 count=100"
|
||||
rb <- chat <$> getTermLine bob
|
||||
rb `shouldContain` [(0, e2eeInfo)]
|
||||
bob `pqForContact` 2 `shouldReturn` PQEncryption pqExpected
|
||||
where
|
||||
pqSend = if pqExpected then (+:#>) else (\:#>)
|
||||
e2eeInfo = if pqExpected then e2eeInfoPQStr else e2eeInfoNoPQStr
|
||||
|
||||
runTestPQVersionsViaAddress :: HasCallStack => TestCC -> TestCC -> Bool -> VersionChat -> IO ()
|
||||
runTestPQVersionsViaAddress alice bob pqExpected vExpected = do
|
||||
img <- genProfileImgForAddress
|
||||
let profileImage = "data:image/png;base64," <> B.unpack img
|
||||
alice `send` ("/set profile image " <> profileImage)
|
||||
_trimmedCmd1 <- getTermLine alice
|
||||
alice <## "profile image updated"
|
||||
bob `send` ("/set profile image " <> profileImage)
|
||||
_trimmedCmd2 <- getTermLine bob
|
||||
bob <## "profile image updated"
|
||||
|
||||
pqOn alice
|
||||
pqOn bob
|
||||
|
||||
alice ##> "/ad"
|
||||
cLink <- getContactLink alice True
|
||||
bob ##> ("/c " <> cLink)
|
||||
alice <#? bob
|
||||
alice @@@ [("<@bob", "")]
|
||||
alice ##> "/ac bob"
|
||||
alice <## "bob (Bob): accepting contact request..."
|
||||
concurrently_
|
||||
(bob <## "alice (Alice): contact is connected")
|
||||
(alice <## "bob (Bob): contact is connected")
|
||||
|
||||
(alice, "hi", vExpected) `pqSend` (bob, vExpected)
|
||||
(bob, "hey", vExpected) `pqSend` (alice, vExpected)
|
||||
|
||||
alice ##> "/_get chat @2 count=100"
|
||||
ra <- chat <$> getTermLine alice
|
||||
ra `shouldContain` [(0, e2eeInfo)]
|
||||
alice `pqForContact` 2 `shouldReturn` PQEncryption pqExpected
|
||||
|
||||
bob ##> "/_get chat @2 count=100"
|
||||
rb <- chat <$> getTermLine bob
|
||||
rb `shouldContain` [(0, e2eeInfo)]
|
||||
bob `pqForContact` 2 `shouldReturn` PQEncryption pqExpected
|
||||
where
|
||||
pqSend = if pqExpected then (+:#>) else (\:#>)
|
||||
e2eeInfo = if pqExpected then e2eeInfoPQStr else e2eeInfoNoPQStr
|
||||
|
||||
testPQEnableContact :: HasCallStack => FilePath -> IO ()
|
||||
testPQEnableContact =
|
||||
testChat2 aliceProfile bobProfile $ \alice bob -> do
|
||||
|
||||
@@ -13,6 +13,7 @@ import Control.Concurrent.Async (concurrently_)
|
||||
import Control.Concurrent.STM
|
||||
import Control.Monad (unless, when)
|
||||
import Control.Monad.Except (runExceptT)
|
||||
import Data.ByteString (ByteString)
|
||||
import qualified Data.ByteString.Base64 as B64
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Data.Char (isDigit)
|
||||
@@ -128,6 +129,23 @@ pqMatrix2 runTest = do
|
||||
where
|
||||
test aPQ bPQ = testChat2 aliceProfile bobProfile $ \a b -> runTest (a, aPQ) (b, bPQ)
|
||||
|
||||
pqVersionTestMatrix2 :: (HasCallStack => TestCC -> TestCC -> Bool -> VersionChat -> IO ()) -> SpecWith FilePath
|
||||
pqVersionTestMatrix2 runTest = do
|
||||
it "current" $ testChat2 aliceProfile bobProfile (runTest' True pqEncryptionCompressionVersion)
|
||||
it "prev" $ testChatCfg2 testCfgVPrev aliceProfile bobProfile (runTest' False (VersionChat 6))
|
||||
it "prev to curr" $ runTestCfg2 testCfg testCfgVPrev (runTest' False (VersionChat 6))
|
||||
it "curr to prev" $ runTestCfg2 testCfgVPrev testCfg (runTest' False (VersionChat 6))
|
||||
it "old (1st supported)" $ testChatCfg2 testCfgV1 aliceProfile bobProfile (runTest' False (VersionChat 1))
|
||||
it "old to curr" $ runTestCfg2 testCfg testCfgV1 (runTest' False (VersionChat 1))
|
||||
it "curr to old" $ runTestCfg2 testCfgV1 testCfg (runTest' False (VersionChat 1))
|
||||
it "next" $ testChatCfg2 testCfgVNext aliceProfile bobProfile (runTest' True pqEncryptionCompressionVersion)
|
||||
it "next to curr" $ runTestCfg2 testCfg testCfgVNext (runTest' True pqEncryptionCompressionVersion)
|
||||
it "curr to next" $ runTestCfg2 testCfgVNext testCfg (runTest' True pqEncryptionCompressionVersion)
|
||||
it "next to prev" $ runTestCfg2 testCfgVPrev testCfgVNext (runTest' False (VersionChat 6))
|
||||
it "prev to next" $ runTestCfg2 testCfgVNext testCfgVPrev (runTest' False (VersionChat 6))
|
||||
where
|
||||
runTest' pqExpected v a b = runTest a b pqExpected v
|
||||
|
||||
withTestChatGroup3Connected :: HasCallStack => FilePath -> String -> (HasCallStack => TestCC -> IO a) -> IO a
|
||||
withTestChatGroup3Connected tmp dbPrefix action = do
|
||||
withTestChat tmp dbPrefix $ \cc -> do
|
||||
@@ -236,7 +254,21 @@ sndRcvImg pqEnc enabled (cc1, msg, v1) (cc2, v2) = do
|
||||
cc2 `pqRcvForContact` 2 `shouldReturn` pqEnc
|
||||
cc2 `pqVerForContact` 2 `shouldReturn` v2
|
||||
where
|
||||
lrgLen = maxEncodedMsgLength PQSupportOff * 3 `div` 4 - 98 -- this is max size for binary image preview given the rest of the message
|
||||
lrgLen = maxEncodedMsgLength PQSupportOff * 3 `div` 4 - 110 -- 98 is ~ max size for binary image preview given the rest of the message
|
||||
|
||||
genProfileImgForLink :: IO ByteString
|
||||
genProfileImgForLink = do
|
||||
g <- C.newRandom
|
||||
atomically $ B64.encode <$> C.randomBytes lrgLen g
|
||||
where
|
||||
lrgLen = maxConnInfoLength PQSupportOff * 3 `div` 4 - 240 -- 214 is the magic number to make tests pass (10737)
|
||||
|
||||
genProfileImgForAddress :: IO ByteString
|
||||
genProfileImgForAddress = do
|
||||
g <- C.newRandom
|
||||
atomically $ B64.encode <$> C.randomBytes lrgLen g
|
||||
where
|
||||
lrgLen = maxConnInfoLength PQSupportOff * 3 `div` 4 - 260 -- 238 is the magic number to make tests pass (10713)
|
||||
|
||||
-- PQ combinators /
|
||||
|
||||
|
||||
Reference in New Issue
Block a user