From 2d2f069694bc5aa73e0cefddd69a2404852f83b3 Mon Sep 17 00:00:00 2001 From: "Evgeny @ SimpleX Chat" <259188159+evgeny-simplex@users.noreply.github.com> Date: Sat, 28 Mar 2026 15:57:05 +0000 Subject: [PATCH 1/2] agent: pass key and link ID when preparing group link --- src/Simplex/Messaging/Agent.hs | 19 ++++++++++--------- tests/AgentTests/FunctionalAPITests.hs | 5 +++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Simplex/Messaging/Agent.hs b/src/Simplex/Messaging/Agent.hs index e8eb22fcf3..fae1b2acb1 100644 --- a/src/Simplex/Messaging/Agent.hs +++ b/src/Simplex/Messaging/Agent.hs @@ -401,10 +401,11 @@ createConnection c nm userId enableNtfs checkNotices = withAgentEnv c .::. newCo {-# INLINE createConnection #-} -- | Prepare connection link for contact mode (no network call). --- Returns root key pair (for signing OwnerAuth), the created link, and internal params. +-- Caller provides root signing key pair and link entity ID. +-- Returns the created link and internal params. -- The link address is fully determined at this point. -prepareConnectionLink :: AgentClient -> UserId -> Maybe ByteString -> Bool -> Maybe CRClientData -> AE (C.KeyPairEd25519, CreatedConnLink 'CMContact, PreparedLinkParams) -prepareConnectionLink c userId linkEntityId checkNotices = withAgentEnv c . prepareConnectionLink' c userId linkEntityId checkNotices +prepareConnectionLink :: AgentClient -> UserId -> C.KeyPairEd25519 -> ByteString -> Bool -> Maybe CRClientData -> AE (CreatedConnLink 'CMContact, PreparedLinkParams) +prepareConnectionLink c userId rootKey linkEntityId checkNotices = withAgentEnv c . prepareConnectionLink' c userId rootKey linkEntityId checkNotices {-# INLINE prepareConnectionLink #-} -- | Create connection for prepared link (single network call). @@ -918,23 +919,23 @@ newConn c nm userId enableNtfs checkNotices cMode linkData_ clientData pqInitKey `catchE` \e -> withStore' c (`deleteConnRecord` connId) >> throwE e -- | Prepare connection link for contact mode (no network, no database). --- Generates all cryptographic material and returns the link that will be created. -prepareConnectionLink' :: AgentClient -> UserId -> Maybe ByteString -> Bool -> Maybe CRClientData -> AM (C.KeyPairEd25519, CreatedConnLink 'CMContact, PreparedLinkParams) -prepareConnectionLink' c userId linkEntityId checkNotices clientData = do +-- Caller provides root signing key pair and link entity ID. +prepareConnectionLink' :: AgentClient -> UserId -> C.KeyPairEd25519 -> ByteString -> Bool -> Maybe CRClientData -> AM (CreatedConnLink 'CMContact, PreparedLinkParams) +prepareConnectionLink' c userId rootKey linkEntityId checkNotices clientData = do g <- asks random plpSrvWithAuth@(ProtoServerWithAuth srv _) <- getSMPServer c userId when checkNotices $ checkClientNotices c plpSrvWithAuth AgentConfig {smpClientVRange, smpAgentVRange} <- asks config plpNonce@(C.CbNonce corrId) <- atomically $ C.randomCbNonce g - sigKeys@(_, plpRootPrivKey) <- atomically $ C.generateKeyPair g + let (_, plpRootPrivKey) = rootKey plpQueueE2EKeys@(e2ePubKey, _) <- atomically $ C.generateKeyPair g let sndId = SMP.EntityId $ B.take 24 $ C.sha3_384 corrId qUri = SMPQueueUri smpClientVRange $ SMPQueueAddress srv sndId e2ePubKey (Just QMContact) connReq = CRContactUri $ ConnReqUriData SSSimplex smpAgentVRange [qUri] clientData - (plpLinkKey, plpSignedFixedData) = SL.encodeSignFixedData sigKeys smpAgentVRange connReq linkEntityId + (plpLinkKey, plpSignedFixedData) = SL.encodeSignFixedData rootKey smpAgentVRange connReq (Just linkEntityId) ccLink = CCLink connReq $ Just $ CSLContact SLSServer CCTContact srv plpLinkKey params = PreparedLinkParams {plpNonce, plpQueueE2EKeys, plpLinkKey, plpRootPrivKey, plpSignedFixedData, plpSrvWithAuth} - pure (sigKeys, ccLink, params) + pure (ccLink, params) -- | Create connection for prepared link (single network call). createConnectionForLink' :: AgentClient -> NetworkRequestMode -> UserId -> Bool -> CreatedConnLink 'CMContact -> PreparedLinkParams -> UserConnLinkData 'CMContact -> CR.InitialKeys -> SubscriptionMode -> AM ConnId diff --git a/tests/AgentTests/FunctionalAPITests.hs b/tests/AgentTests/FunctionalAPITests.hs index b87ebcfada..4ee838b14b 100644 --- a/tests/AgentTests/FunctionalAPITests.hs +++ b/tests/AgentTests/FunctionalAPITests.hs @@ -1653,10 +1653,11 @@ testPrepareCreateConnectionLink ps = withSmpServer ps $ withAgentClients2 $ \a b userCtData = UserContactData {direct = True, owners = [], relays = [], userData} userLinkData = UserContactLinkData userCtData g <- C.newRandom + rootKey <- atomically $ C.generateKeyPair g linkEntId <- atomically $ C.randomBytes 32 g runRight $ do - ((_rootPubKey, _rootPrivKey), ccLink@(CCLink connReq (Just shortLink)), preparedParams) <- - A.prepareConnectionLink a 1 (Just linkEntId) True Nothing + (ccLink@(CCLink connReq (Just shortLink)), preparedParams) <- + A.prepareConnectionLink a 1 rootKey linkEntId True Nothing liftIO $ strDecode (strEncode shortLink) `shouldBe` Right shortLink _ <- A.createConnectionForLink a NRMInteractive 1 True ccLink preparedParams userLinkData CR.IKPQOn SMSubscribe (FixedLinkData {linkConnReq = connReq', linkEntityId}, ContactLinkData _ userCtData') <- getConnShortLink b 1 shortLink From 7a01f7ce09382bea60d368f4834f0fd9fcb5036f Mon Sep 17 00:00:00 2001 From: "Evgeny @ SimpleX Chat" <259188159+evgeny-simplex@users.noreply.github.com> Date: Sat, 28 Mar 2026 16:11:37 +0000 Subject: [PATCH 2/2] binding --- src/Simplex/Messaging/Agent.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Simplex/Messaging/Agent.hs b/src/Simplex/Messaging/Agent.hs index fae1b2acb1..a3f8e0ae85 100644 --- a/src/Simplex/Messaging/Agent.hs +++ b/src/Simplex/Messaging/Agent.hs @@ -921,13 +921,12 @@ newConn c nm userId enableNtfs checkNotices cMode linkData_ clientData pqInitKey -- | Prepare connection link for contact mode (no network, no database). -- Caller provides root signing key pair and link entity ID. prepareConnectionLink' :: AgentClient -> UserId -> C.KeyPairEd25519 -> ByteString -> Bool -> Maybe CRClientData -> AM (CreatedConnLink 'CMContact, PreparedLinkParams) -prepareConnectionLink' c userId rootKey linkEntityId checkNotices clientData = do +prepareConnectionLink' c userId rootKey@(_, plpRootPrivKey) linkEntityId checkNotices clientData = do g <- asks random plpSrvWithAuth@(ProtoServerWithAuth srv _) <- getSMPServer c userId when checkNotices $ checkClientNotices c plpSrvWithAuth AgentConfig {smpClientVRange, smpAgentVRange} <- asks config plpNonce@(C.CbNonce corrId) <- atomically $ C.randomCbNonce g - let (_, plpRootPrivKey) = rootKey plpQueueE2EKeys@(e2ePubKey, _) <- atomically $ C.generateKeyPair g let sndId = SMP.EntityId $ B.take 24 $ C.sha3_384 corrId qUri = SMPQueueUri smpClientVRange $ SMPQueueAddress srv sndId e2ePubKey (Just QMContact)