mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-28 07:34:16 +00:00
core: do not connect to a group whose member is already connected
Connecting to a prepared group whose host or relay member already had a connection created a second one for the same member - UNIQUE constraint failed: connections.group_member_id reachable by connecting again from a second view of the same group. joinContact advances the connection past ConnPrepared only after the agent call returns, so a join that failed is resumed by the ConnPrepared branch above and reaching this one means the join already succeeded; there is no case where connecting again is what the caller wants. Replaces a connect' call the code already questioned. The two tests reach this error only because owner members are now re-used, so they cover both halves: without either change they fail on a constraint instead.
This commit is contained in:
@@ -3771,7 +3771,10 @@ processChatCommand cxt nm = \case
|
||||
Nothing -> connect' groupLinkId Nothing (Just $ Just gInfo)
|
||||
Just conn@Connection {connStatus, xContactId} -> case connStatus of
|
||||
ConnPrepared -> joinPreparedConn' xContactId conn (Just $ Just gInfo)
|
||||
_ -> connect' groupLinkId xContactId (Just $ Just gInfo) -- why not "already connected" for host member?
|
||||
-- the connection is only advanced past ConnPrepared once the join succeeded (see joinContact),
|
||||
-- so retrying a join that failed reuses it above, and reaching here means it already joined -
|
||||
-- connecting again would create a second connection for the same member.
|
||||
_ -> throwCmdError "group is already being joined"
|
||||
Nothing ->
|
||||
withFastStore' (\db -> getConnReqContactXContactId db cxt user cReqHash1 cReqHash2) >>= \case
|
||||
Right ct@Contact {activeConn} -> case groupLinkId of
|
||||
|
||||
@@ -294,6 +294,7 @@ chatGroupTests = do
|
||||
it "subscriber should update profile in channel (signed)" testChannelSubscriberProfileUpdate
|
||||
it "should report relay results when one relay deleted its address" testChannelCreateDeletedRelay
|
||||
it "should deliver support scope messages via relay" testChannelSupportScope
|
||||
it "connecting to channel twice fails" testChannelConnectTwice
|
||||
it "should add relay to existing channel" testChannelAddRelay
|
||||
it "should remove relay from channel" testChannelRemoveRelay
|
||||
it "should remove left relay from channel" testChannelRemoveLeftRelay
|
||||
@@ -8900,6 +8901,21 @@ setupRelay owner relay = do
|
||||
owner <## "ok"
|
||||
pure relaySLink
|
||||
|
||||
testChannelConnectTwice :: HasCallStack => TestParams -> IO ()
|
||||
testChannelConnectTwice ps =
|
||||
withNewTestChat ps "alice" aliceProfile $ \alice ->
|
||||
withNewTestChatOpts ps relayTestOpts "bob" bobProfile $ \bob ->
|
||||
withNewTestChat ps "cath" cathProfile $ \cath -> do
|
||||
(shortLink, fullLink) <- prepareChannel1Relay "team" alice bob
|
||||
memberJoinChannel "team" [bob] [alice] shortLink fullLink cath
|
||||
-- connecting again reuses the owner members the first connection created,
|
||||
-- and is rejected before it can create a second connection to the relay
|
||||
cath ##> "/_connect group #1"
|
||||
cath <## "bad chat command: group is already being joined"
|
||||
alice #> "#team hi"
|
||||
bob <# "#team> hi"
|
||||
cath <# "#team> hi [>>]"
|
||||
|
||||
testChannelMemberSecurityCode :: HasCallStack => TestParams -> IO ()
|
||||
testChannelMemberSecurityCode ps =
|
||||
withNewTestChat ps "alice" aliceProfile $ \alice ->
|
||||
|
||||
@@ -146,6 +146,7 @@ shortLinkTests = do
|
||||
it "prepare business chat using address short link data and connect" testShortLinkAddressPrepareBusiness
|
||||
it "connect to business address with request message" testBusinessAddressRequestMessage
|
||||
it "prepare group using group short link data and connect" testShortLinkPrepareGroup
|
||||
it "prepare group and connect twice" testShortLinkPrepareGroupConnectTwice
|
||||
it "prepare group using group short link data and connect, host rejects" testShortLinkPrepareGroupReject
|
||||
it "connect to group with welcome message via short link" testGroupShortLinkWelcome
|
||||
it "retry connecting to group via short link" testShortLinkGroupRetry
|
||||
@@ -3757,6 +3758,37 @@ testShortLinkPrepareGroup = testChat3 aliceProfile bobProfile cathProfile test
|
||||
bob <## "group link: ok to connect directly"
|
||||
void $ getTermLine bob
|
||||
|
||||
testShortLinkPrepareGroupConnectTwice :: HasCallStack => TestParams -> IO ()
|
||||
testShortLinkPrepareGroupConnectTwice = testChat3 aliceProfile bobProfile cathProfile test
|
||||
where
|
||||
test alice bob cath = do
|
||||
createGroup2 "team" alice cath
|
||||
alice ##> "/create link #team"
|
||||
(shortLink, fullLink) <- getGroupLinks alice "team" GRMember True
|
||||
bob ##> ("/_connect plan 1 " <> shortLink)
|
||||
bob <## "group link: ok to connect directly"
|
||||
groupSLinkData <- getTermLine bob
|
||||
bob ##> ("/_prepare group 1 " <> fullLink <> " " <> shortLink <> " " <> groupSLinkData)
|
||||
bob <## "#team: group is prepared"
|
||||
bob ##> "/_connect group #1"
|
||||
bob <## "#team: connection started"
|
||||
alice <## "bob (Bob): accepting request to join group #team..."
|
||||
concurrentlyN_
|
||||
[ alice <## "#team: bob joined the group",
|
||||
do
|
||||
bob <## "#team: joining the group..."
|
||||
bob <## "#team: you joined the group"
|
||||
bob <## "#team: member cath (Catherine) is connected",
|
||||
do
|
||||
cath <## "#team: alice added bob (Bob) to the group (connecting...)"
|
||||
cath <## "#team: new member bob is connected"
|
||||
]
|
||||
-- connecting again is rejected before it can create a second connection to the host member
|
||||
bob ##> "/_connect group #1"
|
||||
bob <## "bad chat command: group is already being joined"
|
||||
alice #> "#team 1"
|
||||
[bob, cath] *<# "#team alice> 1"
|
||||
|
||||
testShortLinkPrepareGroupReject :: HasCallStack => TestParams -> IO ()
|
||||
testShortLinkPrepareGroupReject = testChatCfg3 cfg aliceProfile bobProfile cathProfile test
|
||||
where
|
||||
|
||||
Reference in New Issue
Block a user