diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index 5c49395d7a..e073440488 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -1984,8 +1984,9 @@ processChatCommand cxt nm = \case APIGetUpdatedGroupLinkData groupId -> withUser $ \user -> do gInfo@GroupInfo {groupProfile = p} <- withFastStore $ \db -> getGroupInfo db cxt user groupId case p of - GroupProfile {publicGroup = Just PublicGroupProfile {groupLink = sLnk}} | useRelays' gInfo -> do - (_, cData@(ContactLinkData _ UserContactData {relays = currentRelayLinks}), _) <- getShortLinkConnReq' nm user sLnk + GroupProfile {publicGroup = Just PublicGroupProfile {groupLink = sLnk, publicGroupId}} | useRelays' gInfo -> do + (FixedLinkData {linkEntityId}, cData@(ContactLinkData _ UserContactData {relays = currentRelayLinks}), _) <- getShortLinkConnReq' nm user sLnk + unless ((B64UrlByteString <$> linkEntityId) == Just publicGroupId) $ throwChatError CEInvalidConnReq groupSLinkData_ <- liftIO $ decodeLinkUserData cData gInfo' <- case groupSLinkData_ of Just sLinkData -> fst <$> updateGroupFromLinkData user gInfo sLinkData Nothing @@ -2338,8 +2339,8 @@ processChatCommand cxt nm = \case groupSLinkData_ <- liftIO $ decodeLinkUserData cData -- Validate link entity ID matches group profile's publicGroupId (relay groups must have both) case groupSLinkData_ of - Just GroupShortLinkData {groupProfile = GroupProfile {publicGroup = Just PublicGroupProfile {publicGroupId}}} - | (B64UrlByteString <$> linkEntityId) == Just publicGroupId -> pure () + Just sLinkData@GroupShortLinkData {groupProfile = GroupProfile {publicGroup = Just PublicGroupProfile {publicGroupId}}} + | (B64UrlByteString <$> linkEntityId) == Just publicGroupId -> void $ updateGroupFromLinkData user gInfo sLinkData Nothing _ -> throwChatError CEInvalidConnReq let publicGroupData_ = groupSLinkData_ >>= \GroupShortLinkData {publicGroupData} -> publicGroupData publicMemberCount_ = (\PublicGroupData {publicMemberCount} -> publicMemberCount) <$> publicGroupData_ diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index 39b32b6e79..57fadea526 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -836,7 +836,7 @@ updatePreparedUserAndHostMembers' unless (memberStatus membership == GSMemConnected) $ liftIO $ updateUserMember currentTs hostMember' <- updateHostMember currentTs - when (gp /= groupProfile) $ + when (not (useRelays' gInfo) && gp /= groupProfile) $ void $ updateGroupProfile db user gInfo groupProfile when (isJust businessChat && isJust business) $ liftIO $ updateBusinessChatInfo db groupId business diff --git a/tests/ChatTests/Groups.hs b/tests/ChatTests/Groups.hs index 1ff60fc1d4..34217f36e4 100644 --- a/tests/ChatTests/Groups.hs +++ b/tests/ChatTests/Groups.hs @@ -315,6 +315,9 @@ chatGroupTests = do it "should preserve working link after welcome message update" testChannelLinkAfterWelcomeUpdate it "should set chat layout of channel joined via relays from link data" testChannelChatLayout it "should preserve owner key in link data after profile update" testChannelOwnerKeyAfterLinkUpdate + it "should keep channel profile from link data when joining" testChannelJoinKeepsLinkProfile + it "should apply channel profile from link data when joining" testChannelJoinAppliesLinkProfile + it "should check entity ID of channel link on refresh" testChannelLinkDataOtherChannel it "should update channel preferences (signed)" testChannelUpdatePrefsSigned it "should change member role (signed)" testChannelChangeRoleSigned it "should block member for all (signed)" testChannelBlockMemberSigned @@ -10664,6 +10667,60 @@ testChannelOwnerKeyAfterLinkUpdate ps = dan <## "changed to #team" ] +testChannelJoinKeepsLinkProfile :: HasCallStack => TestParams -> IO () +testChannelJoinKeepsLinkProfile ps = + withNewTestChat ps "alice" aliceProfile $ \alice -> + withNewTestChatOpts ps relayTestOpts "bob" bobProfile $ \bob -> + withNewTestChat ps "cath" cathProfile $ \cath -> do + (shortLink, fullLink) <- prepareChannel1Relay "team" alice bob + withCCTransaction bob $ \db -> + DB.execute_ db "UPDATE group_profiles SET short_descr = 'relay copy'" + memberJoinChannel "team" [bob] [alice] shortLink fullLink cath + withCCTransaction cath (\db -> DB.query_ db "SELECT short_descr FROM group_profiles" :: IO [Only (Maybe T.Text)]) + `shouldReturn` [Only Nothing] + +testChannelJoinAppliesLinkProfile :: HasCallStack => TestParams -> IO () +testChannelJoinAppliesLinkProfile ps = + withNewTestChat ps "alice" aliceProfile $ \alice -> + withNewTestChatOpts ps relayTestOpts "bob" bobProfile $ \bob -> + withNewTestChat ps "cath" cathProfile $ \cath -> do + (shortLink, fullLink) <- prepareChannel1Relay "team" alice bob + cath ##> ("/_connect plan 1 " <> shortLink) + cath <## "group link: ok to connect via relays" + groupSLinkData <- getTermLine cath + cath ##> ("/_prepare group 1 " <> fullLink <> " " <> shortLink <> " direct=off " <> groupSLinkData) + cath <## "#team: group is prepared" + withCCTransaction cath $ \db -> + DB.execute_ db "UPDATE group_profiles SET short_descr = 'earlier copy'" + cath ##> "/_connect group #1" + cath <## "#team: connection started" + concurrentlyN_ + [ cath <### ["#team: joining the group (connecting to relay bob)...", "#team: you joined the group (connected to relay bob)"], + do + bob <## "cath (Catherine): accepting request to join group #team..." + bob <## "#team: cath joined the group", + alice <### [EndsWith "introduced cath (Catherine) in the channel"] + ] + withCCTransaction cath (\db -> DB.query_ db "SELECT short_descr FROM group_profiles" :: IO [Only (Maybe T.Text)]) + `shouldReturn` [Only Nothing] + +testChannelLinkDataOtherChannel :: HasCallStack => TestParams -> IO () +testChannelLinkDataOtherChannel 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 + (shortLink2, fullLink2) <- prepareChannel' 2 "news" alice bob + memberJoinChannel' "news" 2 1 1 1 [bob] [alice] shortLink2 fullLink2 cath + withCCTransaction cath $ \db -> + DB.execute_ db "UPDATE group_profiles SET group_link = (SELECT group_link FROM group_profiles WHERE display_name = 'news') WHERE display_name = 'team'" + cath ##> "/_get group link data #1" + cath <## "" + cath <## "Connection link is invalid, possibly it was created in a previous version." + cath <## "Please ask your contact to check /version and update if needed." + cath <## "To update run: curl -o- https://raw.githubusercontent.com/simplex-chat/simplex-chat/master/install.sh | bash" + testChannelUpdatePrefsSigned :: HasCallStack => TestParams -> IO () testChannelUpdatePrefsSigned ps = withNewTestChat ps "alice" aliceProfile $ \alice ->