Skip to content

Commit fc1272d

Browse files
authored
agent: createConnection to allow setting linkEntityId, return key; allow to use existing connId for getConnShortLinkAsync (#1750)
1 parent 1e0093b commit fc1272d

3 files changed

Lines changed: 69 additions & 59 deletions

File tree

src/Simplex/Messaging/Agent.hs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -354,9 +354,9 @@ setConnShortLinkAsync :: AgentClient -> ACorrId -> ConnId -> UserConnLinkData 'C
354354
setConnShortLinkAsync c = withAgentEnv c .:: setConnShortLinkAsync' c
355355
{-# INLINE setConnShortLinkAsync #-}
356356

357-
-- | Get and verify data from short link (LGET/LKEY command) asynchronously, synchronous response is new connection id
358-
getConnShortLinkAsync :: AgentClient -> UserId -> ACorrId -> ConnShortLink 'CMContact -> AE ConnId
359-
getConnShortLinkAsync c = withAgentEnv c .:. getConnShortLinkAsync' c
357+
-- | Get and verify data from short link (LGET/LKEY command) asynchronously, synchronous response is new/passed connection id
358+
getConnShortLinkAsync :: AgentClient -> UserId -> ACorrId -> Maybe ConnId -> ConnShortLink 'CMContact -> AE ConnId
359+
getConnShortLinkAsync c = withAgentEnv c .:: getConnShortLinkAsync' c
360360
{-# INLINE getConnShortLinkAsync #-}
361361

362362
-- | Join SMP agent connection (JOIN command) asynchronously, synchronous response is new connection id.
@@ -396,8 +396,8 @@ deleteConnectionsAsync c waitDelivery = withAgentEnv c . deleteConnectionsAsync'
396396
{-# INLINE deleteConnectionsAsync #-}
397397

398398
-- | Create SMP agent connection (NEW command)
399-
createConnection :: ConnectionModeI c => AgentClient -> NetworkRequestMode -> UserId -> Bool -> Bool -> SConnectionMode c -> Maybe (UserConnLinkData c) -> Maybe CRClientData -> CR.InitialKeys -> SubscriptionMode -> AE (ConnId, (CreatedConnLink c, Maybe ClientServiceId))
400-
createConnection c nm userId enableNtfs checkNotices = withAgentEnv c .::. newConn c nm userId enableNtfs checkNotices
399+
createConnection :: ConnectionModeI c => AgentClient -> NetworkRequestMode -> UserId -> Maybe ByteString -> Bool -> Bool -> SConnectionMode c -> Maybe (UserConnLinkData c) -> Maybe CRClientData -> CR.InitialKeys -> SubscriptionMode -> AE (ConnId, (Maybe C.KeyPairEd25519, CreatedConnLink c, Maybe ClientServiceId))
400+
createConnection c nm userId linkEntityId enableNtfs checkNotices = withAgentEnv c .::. newConn c nm userId linkEntityId enableNtfs checkNotices
401401
{-# INLINE createConnection #-}
402402

403403
-- | Prepare connection link for contact mode (no network call).
@@ -908,13 +908,13 @@ switchConnectionAsync' c corrId connId =
908908
connectionStats c $ DuplexConnection cData rqs' sqs
909909
_ -> throwE $ CMD PROHIBITED "switchConnectionAsync: not duplex"
910910

911-
newConn :: ConnectionModeI c => AgentClient -> NetworkRequestMode -> UserId -> Bool -> Bool -> SConnectionMode c -> Maybe (UserConnLinkData c) -> Maybe CRClientData -> CR.InitialKeys -> SubscriptionMode -> AM (ConnId, (CreatedConnLink c, Maybe ClientServiceId))
912-
newConn c nm userId enableNtfs checkNotices cMode linkData_ clientData pqInitKeys subMode = do
911+
newConn :: ConnectionModeI c => AgentClient -> NetworkRequestMode -> UserId -> Maybe ByteString -> Bool -> Bool -> SConnectionMode c -> Maybe (UserConnLinkData c) -> Maybe CRClientData -> CR.InitialKeys -> SubscriptionMode -> AM (ConnId, (Maybe C.KeyPairEd25519, CreatedConnLink c, Maybe ClientServiceId))
912+
newConn c nm userId linkEntityId enableNtfs checkNotices cMode linkData_ clientData pqInitKeys subMode = do
913913
srv <- getSMPServer c userId
914914
when (checkNotices && connMode cMode == CMContact) $ checkClientNotices c srv
915915
connId <- newConnNoQueues c userId enableNtfs cMode (CR.connPQEncryption pqInitKeys)
916916
(connId,)
917-
<$> newRcvConnSrv c nm userId connId enableNtfs cMode linkData_ clientData pqInitKeys subMode srv
917+
<$> newRcvConnSrv c nm userId linkEntityId connId enableNtfs cMode linkData_ clientData pqInitKeys subMode srv
918918
`catchE` \e -> withStore' c (`deleteConnRecord` connId) >> throwE e
919919

920920
-- | Prepare connection link for contact mode (no network, no database).
@@ -1001,14 +1001,22 @@ setConnShortLinkAsync' c corrId connId userLinkData clientData =
10011001
_ -> throwE $ CMD PROHIBITED "setConnShortLinkAsync: invalid connection or mode"
10021002
enqueueCommand c corrId connId (Just srv) $ AClientCommand $ LSET userLinkData clientData
10031003

1004-
getConnShortLinkAsync' :: AgentClient -> UserId -> ACorrId -> ConnShortLink 'CMContact -> AM ConnId
1005-
getConnShortLinkAsync' c userId corrId shortLink@(CSLContact _ _ srv _) = do
1006-
g <- asks random
1007-
connId <- withStore c $ \db -> do
1008-
-- server is created so the command is processed in server queue,
1009-
-- not blocking other "no server" commands
1010-
void $ createServer db srv
1011-
prepareNewConn db g
1004+
getConnShortLinkAsync' :: AgentClient -> UserId -> ACorrId -> Maybe ConnId -> ConnShortLink 'CMContact -> AM ConnId
1005+
getConnShortLinkAsync' c userId corrId connId_ shortLink@(CSLContact _ _ srv _) = do
1006+
connId <- case connId_ of
1007+
Just existingConnId -> do
1008+
-- connId and srv can be unrelated: connId is used as "mailbox" for LDATA delivery,
1009+
-- while srv is the short link's server for the LGET request.
1010+
-- E.g., owner's relay connection (connId, on server A) fetches relay's group link data (srv = server B).
1011+
-- This works because enqueueCommand stores (connId, srv) independently in the commands table,
1012+
-- the network request targets srv, and event delivery uses connId via corrId correlation.
1013+
withStore' c $ \db -> void $ createServer db srv
1014+
pure existingConnId
1015+
Nothing -> do
1016+
g <- asks random
1017+
withStore c $ \db -> do
1018+
void $ createServer db srv
1019+
prepareNewConn db g
10121020
enqueueCommand c corrId connId (Just srv) $ AClientCommand $ LGET shortLink
10131021
pure connId
10141022
where
@@ -1131,23 +1139,23 @@ changeConnectionUser' c oldUserId connId newUserId = do
11311139
where
11321140
updateConn = withStore' c $ \db -> setConnUserId db oldUserId connId newUserId
11331141

1134-
newRcvConnSrv :: forall c. ConnectionModeI c => AgentClient -> NetworkRequestMode -> UserId -> ConnId -> Bool -> SConnectionMode c -> Maybe (UserConnLinkData c) -> Maybe CRClientData -> CR.InitialKeys -> SubscriptionMode -> SMPServerWithAuth -> AM (CreatedConnLink c, Maybe ClientServiceId)
1135-
newRcvConnSrv c nm userId connId enableNtfs cMode userLinkData_ clientData pqInitKeys subMode srvWithAuth@(ProtoServerWithAuth srv _) = do
1142+
newRcvConnSrv :: forall c. ConnectionModeI c => AgentClient -> NetworkRequestMode -> UserId -> Maybe ByteString -> ConnId -> Bool -> SConnectionMode c -> Maybe (UserConnLinkData c) -> Maybe CRClientData -> CR.InitialKeys -> SubscriptionMode -> SMPServerWithAuth -> AM (Maybe C.KeyPairEd25519, CreatedConnLink c, Maybe ClientServiceId)
1143+
newRcvConnSrv c nm userId linkEntityId connId enableNtfs cMode userLinkData_ clientData pqInitKeys subMode srvWithAuth@(ProtoServerWithAuth srv _) = do
11361144
case (cMode, pqInitKeys) of
11371145
(SCMContact, CR.IKUsePQ) -> throwE $ CMD PROHIBITED "newRcvConnSrv"
11381146
_ -> pure ()
11391147
e2eKeys <- atomically . C.generateKeyPair =<< asks random
11401148
case userLinkData_ of
11411149
Just d -> do
1142-
(nonce, qUri, cReq, qd) <- prepareLinkData d $ fst e2eKeys
1150+
(sigKeys, nonce, qUri, cReq, qd) <- prepareLinkData linkEntityId d $ fst e2eKeys
11431151
(rq, qUri') <- createRcvQueue c nm userId connId srvWithAuth enableNtfs subMode (Just nonce) qd e2eKeys
11441152
ccLink <- connReqWithShortLink qUri cReq qUri' (shortLink rq)
1145-
pure (ccLink, clientServiceId rq)
1153+
pure (Just sigKeys, ccLink, clientServiceId rq)
11461154
Nothing -> do
11471155
let qd = case cMode of SCMContact -> CQRContact Nothing; SCMInvitation -> CQRMessaging Nothing
11481156
(rq, qUri) <- createRcvQueue c nm userId connId srvWithAuth enableNtfs subMode Nothing qd e2eKeys
11491157
cReq <- createConnReq qUri
1150-
pure (CCLink cReq Nothing, clientServiceId rq)
1158+
pure (Nothing, CCLink cReq Nothing, clientServiceId rq)
11511159
where
11521160
createConnReq :: SMPQueueUri -> AM (ConnectionRequestUri c)
11531161
createConnReq qUri = do
@@ -1161,8 +1169,8 @@ newRcvConnSrv c nm userId connId enableNtfs cMode userLinkData_ clientData pqIni
11611169
(pk1, pk2, pKem, e2eRcvParams) <- liftIO $ CR.generateRcvE2EParams g (maxVersion e2eEncryptVRange) pqEnc
11621170
withStore' c $ \db -> createRatchetX3dhKeys db connId pk1 pk2 pKem
11631171
pure $ CRInvitationUri crData $ toVersionRangeT e2eRcvParams e2eEncryptVRange
1164-
prepareLinkData :: UserConnLinkData c -> C.PublicKeyX25519 -> AM (C.CbNonce, SMPQueueUri, ConnectionRequestUri c, ClntQueueReqData)
1165-
prepareLinkData userLinkData e2eDhKey = do
1172+
prepareLinkData :: Maybe ByteString -> UserConnLinkData c -> C.PublicKeyX25519 -> AM (C.KeyPairEd25519, C.CbNonce, SMPQueueUri, ConnectionRequestUri c, ClntQueueReqData)
1173+
prepareLinkData linkEntityId_ userLinkData e2eDhKey = do
11661174
g <- asks random
11671175
nonce@(C.CbNonce corrId) <- atomically $ C.randomCbNonce g
11681176
sigKeys@(_, privSigKey) <- atomically $ C.generateKeyPair @'C.Ed25519 g
@@ -1172,14 +1180,14 @@ newRcvConnSrv c nm userId connId enableNtfs cMode userLinkData_ clientData pqIni
11721180
qm = case cMode of SCMContact -> QMContact; SCMInvitation -> QMMessaging
11731181
qUri = SMPQueueUri vr $ SMPQueueAddress srv sndId e2eDhKey (Just qm)
11741182
connReq <- createConnReq qUri
1175-
let (linkKey, linkData) = SL.encodeSignLinkData sigKeys smpAgentVRange connReq Nothing userLinkData
1183+
let (linkKey, linkData) = SL.encodeSignLinkData sigKeys smpAgentVRange connReq linkEntityId_ userLinkData
11761184
qd <- case cMode of
11771185
SCMContact -> encryptContactLinkData g privSigKey linkKey sndId linkData
11781186
SCMInvitation -> do
11791187
let k = SL.invShortLinkKdf linkKey
11801188
srvData <- liftError id $ SL.encryptLinkData g k linkData
11811189
pure $ CQRMessaging $ Just CQRData {linkKey, privSigKey, srvReq = (sndId, srvData)}
1182-
pure (nonce, qUri, connReq, qd)
1190+
pure (sigKeys, nonce, qUri, connReq, qd)
11831191
connReqWithShortLink :: SMPQueueUri -> ConnectionRequestUri c -> SMPQueueUri -> Maybe ShortLinkCreds -> AM (CreatedConnLink c)
11841192
connReqWithShortLink qUri cReq qUri' shortLink = case shortLink of
11851193
Just ShortLinkCreds {shortLinkId, shortLinkKey}
@@ -1341,7 +1349,9 @@ joinConnSrv c nm userId connId enableNtfs cReqUri@CRContactUri {} cInfo pqSup su
13411349
SomeConn cType conn <- withStore c (`getConn` connId)
13421350
let pqInitKeys = CR.joinContactInitialKeys (v >= pqdrSMPAgentVersion) pqSup
13431351
(CCLink cReq _, service) <- case conn of
1344-
NewConnection _ -> newRcvConnSrv c NRMBackground userId connId enableNtfs SCMInvitation Nothing Nothing pqInitKeys subMode srv
1352+
NewConnection _ -> do
1353+
(_, ccLink, service) <- newRcvConnSrv c NRMBackground userId Nothing connId enableNtfs SCMInvitation Nothing Nothing pqInitKeys subMode srv
1354+
pure (ccLink, service)
13451355
RcvConnection _ rq -> mkJoinInvitation rq pqInitKeys
13461356
_ -> throwE $ CMD PROHIBITED $ "joinConnSrv: bad connection " <> show cType
13471357
void $ sendInvitation c nm userId connId qInfo vrsn cReq cInfo
@@ -1788,7 +1798,7 @@ runCommandProcessing c@AgentClient {subQ} connId server_ Worker {doWork} = do
17881798
NEW enableNtfs (ACM cMode) pqEnc subMode -> noServer $ do
17891799
triedHosts <- newTVarIO S.empty
17901800
tryCommand . withNextSrv c userId storageSrvs triedHosts [] $ \srv -> do
1791-
(CCLink cReq _, service) <- newRcvConnSrv c NRMBackground userId connId enableNtfs cMode Nothing Nothing pqEnc subMode srv
1801+
(_, CCLink cReq _, service) <- newRcvConnSrv c NRMBackground userId Nothing connId enableNtfs cMode Nothing Nothing pqEnc subMode srv
17921802
notify $ INV (ACR cMode cReq) service
17931803
LSET userLinkData clientData ->
17941804
withServer' . tryCommand $ do

0 commit comments

Comments
 (0)