From 0ef32c0bccb2a10349894a6763ac73f8ec2ab443 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Thu, 1 Oct 2026 08:00:51 +0000 Subject: [PATCH] core: prevent moderators from accepting members with moderator role (#7629) --- src/Simplex/Chat/Library/Commands.hs | 3 ++- src/Simplex/Chat/Library/Subscriber.hs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index 4fe288ca8e..2751861e8a 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -2867,7 +2867,8 @@ processChatCommand cxt nm = \case Nothing -> throwChatError $ CEContactNotActive ct APIAcceptMember groupId gmId role -> withUser $ \user@User {userId} -> do (g@(GIK gInfo _), m) <- withFastStore $ \db -> (,) <$> getGroupInfoKeys db cxt user groupId <*> getGroupMemberById db cxt user gmId - assertUserGroupRole gInfo $ max GRModerator role + -- same rule as role change (moderators grant up to member); pending member's role is a stand-in, so treat it as member + assertUserGroupRole gInfo $ roleRequiredToChange GRMember role case memberStatus m of GSMemPendingApproval | memberCategory m == GCInviteeMember -> do -- only host can approve let GroupInfo {groupProfile = GroupProfile {memberAdmission}} = gInfo diff --git a/src/Simplex/Chat/Library/Subscriber.hs b/src/Simplex/Chat/Library/Subscriber.hs index f956c292bc..bac8ae4da8 100644 --- a/src/Simplex/Chat/Library/Subscriber.hs +++ b/src/Simplex/Chat/Library/Subscriber.hs @@ -2826,7 +2826,8 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag xGrpLinkAcpt :: GroupInfoKeys -> GroupMember -> GroupAcceptance -> GroupMemberRole -> MemberId -> RcvMessage -> UTCTime -> CM () xGrpLinkAcpt g@(GIK gInfo@GroupInfo {membership} _) m acceptance role memberId msg brokerTs - | memberRole' m < GRModerator || memberRole' m < role = + -- same rule as role change (moderators grant up to member); pending member's role is a stand-in, so treat it as member + | memberRole' m < roleRequiredToChange GRMember role = messageError "x.grp.link.acpt with insufficient member permissions" | sameMemberId memberId membership = processUserAccepted | otherwise =