From c029b715fbb1b8a532df2254e2408a49f1b93376 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Thu, 8 Feb 2024 19:57:45 +0000 Subject: [PATCH] fix/add tests, add version config to "small" agent --- rfcs/2024-02-03-deniability.md | 3 +- src/Simplex/Messaging/Agent/Env/SQLite.hs | 4 +- src/Simplex/Messaging/Notifications/Server.hs | 3 +- .../Messaging/Notifications/Server/Env.hs | 2 + .../Messaging/Notifications/Server/Main.hs | 2 + tests/AgentTests.hs | 2 +- tests/AgentTests/FunctionalAPITests.hs | 7 +++- tests/AgentTests/NotificationTests.hs | 40 +++++++++---------- tests/NtfClient.hs | 13 +++++- 9 files changed, 47 insertions(+), 29 deletions(-) diff --git a/rfcs/2024-02-03-deniability.md b/rfcs/2024-02-03-deniability.md index 76d844514..31fe18949 100644 --- a/rfcs/2024-02-03-deniability.md +++ b/rfcs/2024-02-03-deniability.md @@ -48,5 +48,4 @@ As this new scheme breaks backward compatibility, as the new scheme requires add 2. Add support for handshake and version negotiation to XFTP - 5.5.4 or 5.6. 3. Upgrade clients to drop support of SMP earlier than v4 (batching) and also drop support of old double ratchet protocol and old handshake - 5.6. 4. Upgrade servers to offer SMP v7 with support for new authorization - by the time 5.6 is released. -5. Upgrade clients to use SMP v7 / new authorization - 5.6.2 or 5.7. -6. Upgrade clients to require support for new authorization scheme - 5.7 +5. Upgrade clients to require server support for SMP v7 / new authorization scheme and start using it - 5.7 or 5.8. At this point the old version of the servers will not be supported, as maintaining this backward compatibility would substantially increase the complexity and logic of the client - at the point of generating the key we do not even know which server version will be used. diff --git a/src/Simplex/Messaging/Agent/Env/SQLite.hs b/src/Simplex/Messaging/Agent/Env/SQLite.hs index 558791e43..2d1821b85 100644 --- a/src/Simplex/Messaging/Agent/Env/SQLite.hs +++ b/src/Simplex/Messaging/Agent/Env/SQLite.hs @@ -84,7 +84,6 @@ data InitialAgentServers = InitialAgentServers data AgentConfig = AgentConfig { tcpPort :: ServiceName, cmdAuthAlg :: C.AuthAlg, - cmdAuthAlgV6 :: C.AuthAlg, connIdBytes :: Int, tbqSize :: Natural, smpCfg :: ProtocolClientConfig, @@ -149,8 +148,9 @@ defaultAgentConfig :: AgentConfig defaultAgentConfig = AgentConfig { tcpPort = "5224", + -- while the current client version supports X25519, it can only be enabled once support for SMP v6 is dropped, + -- and all servers are required to support v7 to be compatible. cmdAuthAlg = C.AuthAlg C.SEd448, - cmdAuthAlgV6 = C.AuthAlg C.SEd448, connIdBytes = 12, tbqSize = 64, smpCfg = defaultSMPClientConfig {defaultTransport = (show defaultSMPPort, transport @TLS)}, diff --git a/src/Simplex/Messaging/Notifications/Server.hs b/src/Simplex/Messaging/Notifications/Server.hs index 8215c08a6..26c935f1c 100644 --- a/src/Simplex/Messaging/Notifications/Server.hs +++ b/src/Simplex/Messaging/Notifications/Server.hs @@ -88,7 +88,8 @@ ntfServer cfg@NtfServerConfig {transports, transportConfig = tCfg} started = do runClient _ h = do kh <- asks serverIdentity ks <- atomically . C.generateKeyPair =<< asks random - liftIO (runExceptT $ ntfServerHandshake h ks kh supportedNTFServerVRange) >>= \case + NtfServerConfig {ntfServerVRange} <- asks config + liftIO (runExceptT $ ntfServerHandshake h ks kh ntfServerVRange) >>= \case Right th -> runNtfClientTransport th Left _ -> pure () diff --git a/src/Simplex/Messaging/Notifications/Server/Env.hs b/src/Simplex/Messaging/Notifications/Server/Env.hs index 02529f13c..5dc580245 100644 --- a/src/Simplex/Messaging/Notifications/Server/Env.hs +++ b/src/Simplex/Messaging/Notifications/Server/Env.hs @@ -35,6 +35,7 @@ import Simplex.Messaging.TMap (TMap) import qualified Simplex.Messaging.TMap as TM import Simplex.Messaging.Transport (ATransport) import Simplex.Messaging.Transport.Server (TransportServerConfig, loadFingerprint, loadTLSServerParams) +import Simplex.Messaging.Version (VersionRange) import System.IO (IOMode (..)) import System.Mem.Weak (Weak) import UnliftIO.STM @@ -60,6 +61,7 @@ data NtfServerConfig = NtfServerConfig logStatsStartTime :: Int64, serverStatsLogFile :: FilePath, serverStatsBackupFile :: Maybe FilePath, + ntfServerVRange :: VersionRange, transportConfig :: TransportServerConfig } diff --git a/src/Simplex/Messaging/Notifications/Server/Main.hs b/src/Simplex/Messaging/Notifications/Server/Main.hs index 40ec392f2..f3b73f8f4 100644 --- a/src/Simplex/Messaging/Notifications/Server/Main.hs +++ b/src/Simplex/Messaging/Notifications/Server/Main.hs @@ -19,6 +19,7 @@ import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Notifications.Server (runNtfServer) import Simplex.Messaging.Notifications.Server.Env (NtfServerConfig (..), defaultInactiveClientExpiration) import Simplex.Messaging.Notifications.Server.Push.APNS (defaultAPNSPushClientConfig) +import Simplex.Messaging.Notifications.Transport (supportedNTFServerVRange) import Simplex.Messaging.Protocol (ProtoServerWithAuth (..), pattern NtfServer) import Simplex.Messaging.Server.CLI import Simplex.Messaging.Server.Expiration @@ -135,6 +136,7 @@ ntfServerCLI cfgPath logPath = logStatsStartTime = 0, -- seconds from 00:00 UTC serverStatsLogFile = combine logPath "ntf-server-stats.daily.log", serverStatsBackupFile = logStats $> combine logPath "ntf-server-stats.log", + ntfServerVRange = supportedNTFServerVRange, transportConfig = defaultTransportServerConfig { logTLSErrors = fromMaybe False $ iniOnOff "TRANSPORT" "log_tls_errors" ini diff --git a/tests/AgentTests.hs b/tests/AgentTests.hs index 664ab4866..589683a78 100644 --- a/tests/AgentTests.hs +++ b/tests/AgentTests.hs @@ -41,7 +41,7 @@ agentTests (ATransport t) = do describe "Connection request" connectionRequestTests describe "Double ratchet tests" doubleRatchetTests describe "Functional API" $ functionalAPITests (ATransport t) - fdescribe "Notification tests" $ notificationTests (ATransport t) + describe "Notification tests" $ notificationTests (ATransport t) describe "SQLite store" storeTests describe "Migration tests" migrationTests describe "SMP agent protocol syntax" $ syntaxTests t diff --git a/tests/AgentTests/FunctionalAPITests.hs b/tests/AgentTests/FunctionalAPITests.hs index 768af0ae8..b4884a406 100644 --- a/tests/AgentTests/FunctionalAPITests.hs +++ b/tests/AgentTests/FunctionalAPITests.hs @@ -61,6 +61,7 @@ import Simplex.Messaging.Agent.Store.SQLite.Common (withTransaction') import Simplex.Messaging.Client (NetworkConfig (..), ProtocolClientConfig (..), TransportSessionMode (TSMEntity, TSMUser), defaultSMPClientConfig) import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Encoding.String +import Simplex.Messaging.Notifications.Transport (authEncryptCmdsNTFVersion) import Simplex.Messaging.Protocol (BasicAuth, ErrorType (..), MsgBody, ProtocolServer (..), SubscriptionMode (..), supportedSMPClientVRange) import qualified Simplex.Messaging.Protocol as SMP import Simplex.Messaging.Server.Env.STM (ServerConfig (..)) @@ -134,6 +135,9 @@ smpCfgV4 = (smpCfg agentCfg) {serverVRange = mkVersionRange 4 4} smpCfgV7 :: ProtocolClientConfig smpCfgV7 = (smpCfg agentCfg) {serverVRange = mkVersionRange 4 authEncryptCmdsSMPVersion} +ntfCfgV2 :: ProtocolClientConfig +ntfCfgV2 = (smpCfg agentCfg) {serverVRange = mkVersionRange 1 authEncryptCmdsNTFVersion} + agentCfgVPrev :: AgentConfig agentCfgVPrev = agentCfg @@ -147,7 +151,8 @@ agentCfgV7 :: AgentConfig agentCfgV7 = agentCfg { cmdAuthAlg = C.AuthAlg C.SX25519, - smpCfg = smpCfgV7 + smpCfg = smpCfgV7, + ntfCfg = ntfCfgV2 } agentCfgV1 :: AgentConfig diff --git a/tests/AgentTests/NotificationTests.hs b/tests/AgentTests/NotificationTests.hs index 16182470d..1ccfb9a69 100644 --- a/tests/AgentTests/NotificationTests.hs +++ b/tests/AgentTests/NotificationTests.hs @@ -26,10 +26,10 @@ import Data.ByteString.Char8 (ByteString) import Data.Text.Encoding (encodeUtf8) import NtfClient import SMPAgentClient (agentCfg, initAgentServers, initAgentServers2, testDB, testDB2, testDB3, testNtfServer2) -import SMPClient (cfg, testPort, testPort2, testStoreLogFile2, withSmpServer, withSmpServerConfigOn, withSmpServerStoreLogOn) +import SMPClient (cfg, cfgV7, testPort, testPort2, testStoreLogFile2, withSmpServer, withSmpServerConfigOn, withSmpServerStoreLogOn) import Simplex.Messaging.Agent import Simplex.Messaging.Agent.Client (withStore') -import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, InitialAgentServers) +import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, Env (..), InitialAgentServers) import Simplex.Messaging.Agent.Protocol import Simplex.Messaging.Agent.Store.SQLite (getSavedNtfToken) import qualified Simplex.Messaging.Crypto as C @@ -73,12 +73,10 @@ notificationTests t = do withAPNSMockServer $ \apns -> testNtfTokenChangeServers t apns describe "Managing notification subscriptions" $ do - fdescribe "should create notification subscription for existing connection" $ + describe "should create notification subscription for existing connection" $ testNtfMatrix t testNotificationSubscriptionExistingConnection - it "should create notification subscription for new connection" $ - withSmpServer t $ - withAPNSMockServer $ \apns -> - withNtfServer t $ testNotificationSubscriptionNewConnection apns + describe "should create notification subscription for new connection" $ + testNtfMatrix t testNotificationSubscriptionNewConnection it "should change notifications mode" $ withSmpServer t $ withAPNSMockServer $ \apns -> @@ -117,11 +115,17 @@ notificationTests t = do testNtfMatrix :: ATransport -> (APNSMockServer -> AgentClient -> AgentClient -> IO ()) -> Spec testNtfMatrix t runTest = do - -- it "v7 clients, v7 smp, v2 ntf server" $ runNtfTest cfg ntfServerCfg agentCfgV7 agentCfgV7 runTest - it "v6 clients, v6 smp, v1 ntf server" $ runNtfTestCfg t cfg ntfServerCfg agentCfg agentCfg runTest - -- it "v7 clients, v6 smp, v1 ntf server" $ runNtfTestCfg t cfg ntfServerCfg agentCfgV7 agentCfgV7 runTest - -- it "v7 to current" $ withSmpServerV7 t $ runTestCfg2 agentCfgV7 agentCfg 3 runTest - -- it "current to v7" $ withSmpServerV7 t $ runTestCfg2 agentCfg agentCfgV7 3 runTest + it "new servers: SMP v7, NTF v2; new clients: v7/v2" $ runNtfTestCfg t cfgV7 ntfServerCfgV2 agentCfgV7 agentCfgV7 runTest + it "new servers: SMP v7, NTF v2; old clients: v6/v1" $ runNtfTestCfg t cfgV7 ntfServerCfgV2 agentCfg agentCfg runTest + it "old servers: SMP v6, NTF v1; old clients: v6/v1" $ runNtfTestCfg t cfg ntfServerCfg agentCfg agentCfg runTest + -- this case will cannot be supported - see RFC + xit "servers: SMP v6, NTF v1; clients: v7/v2 (not supported)" $ runNtfTestCfg t cfg ntfServerCfg agentCfgV7 agentCfgV7 runTest + -- servers can be migrated in any order + it "servers: new SMP v7, old NTF v1; old clients: v6/v1" $ runNtfTestCfg t cfgV7 ntfServerCfg agentCfg agentCfg runTest + it "servers: old SMP v6, new NTF v2; old clients: v6/v1" $ runNtfTestCfg t cfg ntfServerCfgV2 agentCfg agentCfg runTest + -- clients can be partially migrated + it "servers: new SMP v7, old NTF v2; clients: new/old" $ runNtfTestCfg t cfgV7 ntfServerCfgV2 agentCfgV7 agentCfg runTest + it "servers: new SMP v7, old NTF v2; clients: old/new" $ runNtfTestCfg t cfgV7 ntfServerCfgV2 agentCfg agentCfgV7 runTest runNtfTestCfg :: ATransport -> ServerConfig -> NtfServerConfig -> AgentConfig -> AgentConfig -> (APNSMockServer -> AgentClient -> AgentClient -> IO ()) -> IO () runNtfTestCfg t smpCfg ntfCfg aCfg bCfg runTest = @@ -309,7 +313,7 @@ testNtfTokenChangeServers t APNSMockServer {apnsQ} = checkNtfToken a tkn >>= \r -> liftIO $ r `shouldBe` NTActive testNotificationSubscriptionExistingConnection :: APNSMockServer -> AgentClient -> AgentClient -> IO () -testNotificationSubscriptionExistingConnection APNSMockServer {apnsQ} alice bob = do +testNotificationSubscriptionExistingConnection APNSMockServer {apnsQ} alice@AgentClient {agentEnv = Env {config = aliceCfg}} bob = do (bobId, aliceId, nonce, message) <- runRight $ do -- establish connection (bobId, qInfo) <- createConnection alice 1 True SCMInvitation Nothing SMSubscribe @@ -341,7 +345,7 @@ testNotificationSubscriptionExistingConnection APNSMockServer {apnsQ} alice bob Left (CMD PROHIBITED) <- runExceptT $ getNotificationMessage alice nonce message -- aliceNtf client doesn't have subscription and is allowed to get notification message - aliceNtf <- getSMPAgentClient' 3 agentCfg initAgentServers testDB + aliceNtf <- getSMPAgentClient' 3 aliceCfg initAgentServers testDB runRight_ $ do (_, [SMPMsgMeta {msgFlags = MsgFlags True}]) <- getNotificationMessage aliceNtf nonce message pure () @@ -362,10 +366,8 @@ testNotificationSubscriptionExistingConnection APNSMockServer {apnsQ} alice bob baseId = 3 msgId = subtract baseId -testNotificationSubscriptionNewConnection :: APNSMockServer -> IO () -testNotificationSubscriptionNewConnection APNSMockServer {apnsQ} = do - alice <- getSMPAgentClient' 1 agentCfg initAgentServers testDB - bob <- getSMPAgentClient' 2 agentCfg initAgentServers testDB2 +testNotificationSubscriptionNewConnection :: APNSMockServer -> AgentClient -> AgentClient -> IO () +testNotificationSubscriptionNewConnection APNSMockServer {apnsQ} alice bob = runRight_ $ do -- alice registers notification token DeviceToken {} <- registerTestToken alice "abcd" NMInstant apnsQ @@ -401,8 +403,6 @@ testNotificationSubscriptionNewConnection APNSMockServer {apnsQ} = do ackMessage bob aliceId (baseId + 2) Nothing -- no unexpected notifications should follow noNotification apnsQ - disconnectAgentClient alice - disconnectAgentClient bob where baseId = 3 msgId = subtract baseId diff --git a/tests/NtfClient.hs b/tests/NtfClient.hs index f9091f627..7a6dcfe01 100644 --- a/tests/NtfClient.hs +++ b/tests/NtfClient.hs @@ -30,8 +30,8 @@ import qualified Network.HTTP.Types as N import qualified Network.HTTP2.Server as H import Network.Socket import SMPClient (serverBracket) -import Simplex.Messaging.Client (chooseTransportHost, defaultNetworkConfig) -import Simplex.Messaging.Client.Agent (defaultSMPClientAgentConfig) +import Simplex.Messaging.Client (ProtocolClientConfig (..), chooseTransportHost, defaultNetworkConfig) +import Simplex.Messaging.Client.Agent (SMPClientAgentConfig (..), defaultSMPClientAgentConfig) import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Encoding import Simplex.Messaging.Notifications.Server (runNtfServerBlocking) @@ -45,6 +45,7 @@ import Simplex.Messaging.Transport.Client import Simplex.Messaging.Transport.HTTP2 (HTTP2Body (..), http2TLSParams) import Simplex.Messaging.Transport.HTTP2.Server import Simplex.Messaging.Transport.Server +import Simplex.Messaging.Version (mkVersionRange) import Test.Hspec import UnliftIO.Async import UnliftIO.Concurrent @@ -106,9 +107,17 @@ ntfServerCfg = logStatsStartTime = 0, serverStatsLogFile = "tests/ntf-server-stats.daily.log", serverStatsBackupFile = Nothing, + ntfServerVRange = supportedNTFServerVRange, transportConfig = defaultTransportServerConfig } +ntfServerCfgV2 :: NtfServerConfig +ntfServerCfgV2 = + ntfServerCfg + { ntfServerVRange = mkVersionRange 1 authEncryptCmdsNTFVersion, + smpAgentCfg = defaultSMPClientAgentConfig {smpCfg = (smpCfg defaultSMPClientAgentConfig) {serverVRange = mkVersionRange 4 authEncryptCmdsSMPVersion}} + } + withNtfServerStoreLog :: ATransport -> (ThreadId -> IO a) -> IO a withNtfServerStoreLog t = withNtfServerCfg ntfServerCfg {storeLogFile = Just ntfTestStoreLogFile, transports = [(ntfTestPort, t)]}