mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-09-17 08:05:23 +00:00
wip
This commit is contained in:
@@ -76,7 +76,7 @@ import qualified Simplex.FileTransfer.Transport as XFTP
|
||||
import Simplex.FileTransfer.Types (FileErrorType (..), RcvFileId, SndFileId)
|
||||
import Simplex.Messaging.Agent
|
||||
import Simplex.Messaging.Agent.Client (getAgentWorker, temporaryOrHostError, waitForUserNetwork, waitForWork, waitWhileSuspended, withWorkItems, withWork_)
|
||||
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), Worker (..))
|
||||
import Simplex.Messaging.Agent.Env.SQLite (Worker (..))
|
||||
import Simplex.Messaging.Agent.Protocol
|
||||
import qualified Simplex.Messaging.Agent.Protocol as AP (AgentErrorType (..))
|
||||
import Simplex.Messaging.Agent.RetryInterval (RetryInterval (..), nextRetryDelay)
|
||||
@@ -3129,7 +3129,7 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
| otherwise =
|
||||
withStore' (\db -> runExceptT $ getGroupMemberByMemberId db vr user gInfo memId) >>= \case
|
||||
Right member -> changeMemberRole gInfo member $ RGEMemberRole (groupMemberId' member) (fromLocalProfile $ memberProfile member) memRole
|
||||
-- in relay groups the roster delivers the (privileged) member separately; no-op until then
|
||||
-- in channels the roster delivers the chat item for previously-unknown privileged members
|
||||
Left _
|
||||
| useRelays' gInfo -> pure Nothing
|
||||
| otherwise -> messageError "x.grp.mem.role with unknown member ID" $> Nothing
|
||||
@@ -3177,29 +3177,37 @@ processAgentMessageConn vr user@User {userId} corrId agentConnId agentMessage =
|
||||
let GroupRoster {roster = entries} = validRoster
|
||||
rosterIds = map (\RosterMember {memberId} -> memberId) entries
|
||||
defaultRole <- unknownMemberRole gInfo
|
||||
conflicts <- withStore $ \db -> do
|
||||
conflicts <- catMaybes <$> mapM (applyRosterEntryDB db) entries
|
||||
(conflicts, applied) <- withStore $ \db -> do
|
||||
acc <- foldrM (applyRosterEntry db defaultRole) ([], []) entries
|
||||
-- absent privileged members revert to the joiner default
|
||||
currentPriv <- liftIO $ getGroupRosterMembers db vr user gInfo
|
||||
liftIO $ forM_ currentPriv $ \m ->
|
||||
when (memberId' m `notElem` rosterIds) $
|
||||
updateGroupMemberRole db user m defaultRole
|
||||
pure conflicts
|
||||
pure acc
|
||||
forM_ conflicts $ \mid' ->
|
||||
messageWarning $ "x.grp.roster: member key conflict, keeping trusted key, memberId=" <> safeDecodeUtf8 (strEncode mid')
|
||||
applyRosterEntryDB :: DB.Connection -> RosterMember -> ExceptT StoreError IO (Maybe MemberId)
|
||||
applyRosterEntryDB db RosterMember {memberId, name, key = MemberKey pubKey, role} =
|
||||
getCreateUnknownGMByMemberId db vr user gInfo memberId name role True >>= \case
|
||||
Just (m, _created) -> case memberPubKey m of
|
||||
Just k
|
||||
| k == pubKey -> Nothing <$ liftIO (unless (memberRole' m == role) $ updateGroupMemberRole db user m role)
|
||||
| otherwise -> pure (Just memberId)
|
||||
Nothing -> Nothing <$ liftIO (setGroupMemberKeyRole db m pubKey role)
|
||||
Nothing -> pure Nothing
|
||||
signedMsgBytes :: Maybe ByteString
|
||||
signedMsgBytes = case verifiedMsg of
|
||||
VMSigned _ sm _ -> Just $ smpEncode sm
|
||||
VMUnsigned _ -> Nothing
|
||||
forM_ applied $ \(member, fromRole) -> createItems member fromRole
|
||||
applyRosterEntry :: DB.Connection -> GroupMemberRole -> RosterMember -> ([MemberId], [(GroupMember, GroupMemberRole)]) -> ExceptT StoreError IO ([MemberId], [(GroupMember, GroupMemberRole)])
|
||||
applyRosterEntry db defaultRole RosterMember {memberId, name, key = MemberKey pubKey, role} (cs, as) =
|
||||
applyEntry `catchAllErrors` \_ -> pure (cs, as)
|
||||
where
|
||||
applied m = (cs, ((m :: GroupMember) {memberRole = role}, memberRole' m) : as)
|
||||
applyEntry = getCreateUnknownGMByMemberId db vr user gInfo memberId name defaultRole True >>= \case
|
||||
Nothing -> pure (cs, as)
|
||||
Just (m, _) -> case memberPubKey m of
|
||||
Just k
|
||||
| k /= pubKey -> pure (memberId : cs, as)
|
||||
| memberRole' m == role -> pure (cs, as)
|
||||
| otherwise -> liftIO (updateGroupMemberRole db user m role) $> applied m
|
||||
Nothing -> liftIO (setGroupMemberKeyRole db m pubKey role) $> applied m
|
||||
createItems :: GroupMember -> GroupMemberRole -> CM ()
|
||||
createItems member fromRole = do
|
||||
let toRole = memberRole' member
|
||||
gEvent = RGEMemberRole (groupMemberId' member) (fromLocalProfile $ memberProfile member) toRole
|
||||
(gInfo', author', scopeInfo) <- mkGroupChatScope gInfo author
|
||||
createInternalChatItem user (CDGroupRcv gInfo' scopeInfo author') (CIRcvGroupEvent gEvent) (Just brokerTs)
|
||||
toView CEvtMemberRole {user, groupInfo = gInfo', byMember = author', member, fromRole, toRole, msgSigned = Just MSSVerified}
|
||||
|
||||
checkHostRole :: GroupMember -> GroupMemberRole -> CM ()
|
||||
checkHostRole GroupMember {memberRole, localDisplayName} memRole =
|
||||
|
||||
+44
-22
@@ -9409,18 +9409,23 @@ testChannelChangeRoleSigned ps =
|
||||
dan #$> ("/_get chat #1 count=1", chat, [(0, "changed role of cath to admin (signed)")])
|
||||
eve #$> ("/_get chat #1 count=1", chat, [(0, "changed role of cath to admin (signed)")])
|
||||
|
||||
-- change role of silent member; cath/eve don't know dan, so the relay-group branch
|
||||
-- in xGrpMemRole silently no-ops (the roster will deliver the privileged set separately)
|
||||
-- change role of silent member; cath/eve don't know dan via xGrpMemRole, but the
|
||||
-- subsequent roster apply emits the chat item with dan TOFU-created at the new role
|
||||
threadDelay 1000000
|
||||
alice ##> "/mr #team dan admin"
|
||||
alice <## "#team: you changed the role of dan to admin (signed)"
|
||||
bob <## "#team: alice changed the role of dan from member to admin (signed)"
|
||||
dan <## "#team: alice changed your role from member to admin (signed)"
|
||||
concurrentlyN_
|
||||
[ bob <## "#team: alice changed the role of dan from member to admin (signed)",
|
||||
dan <## "#team: alice changed your role from member to admin (signed)",
|
||||
cath <## "#team: alice changed the role of dan from member to admin (signed)",
|
||||
eve <## "#team: alice changed the role of dan from member to admin (signed)"
|
||||
]
|
||||
alice #$> ("/_get chat #1 count=1", chat, [(1, "changed role of dan to admin (signed)")])
|
||||
bob #$> ("/_get chat #1 count=1", chat, [(0, "changed role of dan to admin (signed)")])
|
||||
cath #$> ("/_get chat #1 count=1", chat, [(0, "changed your role to admin (signed)")]) -- now new chat item
|
||||
-- roster-emitted items don't carry the signed marker in chat content text (live event does)
|
||||
cath #$> ("/_get chat #1 count=1", chat, [(0, "changed role of dan to admin")])
|
||||
dan #$> ("/_get chat #1 count=1", chat, [(0, "changed your role to admin (signed)")])
|
||||
eve #$> ("/_get chat #1 count=1", chat, [(0, "changed role of cath to admin (signed)")]) -- now new chat item
|
||||
eve #$> ("/_get chat #1 count=1", chat, [(0, "changed role of dan to admin")])
|
||||
|
||||
testChannelBlockMemberSigned :: HasCallStack => TestParams -> IO ()
|
||||
testChannelBlockMemberSigned ps =
|
||||
@@ -9518,14 +9523,17 @@ testChannelModeratorActionViaRoster ps =
|
||||
eve <# "#team dan> hello from dan [>>]"
|
||||
]
|
||||
|
||||
-- alice promotes cath. dan/eve don't know cath yet, so their XGrpMemRole is silently
|
||||
-- skipped (channel branch in xGrpMemRole returns Nothing) until the roster arrives
|
||||
-- and creates cath's record with the new role.
|
||||
-- dan/eve XGrpMemRole is skipped (target unknown); roster apply creates cath
|
||||
-- and emits the role-change chat item
|
||||
threadDelay 1000000
|
||||
alice ##> "/mr #team cath moderator"
|
||||
alice <## "#team: you changed the role of cath to moderator (signed)"
|
||||
bob <## "#team: alice changed the role of cath from member to moderator (signed)"
|
||||
cath <## "#team: alice changed your role from member to moderator (signed)"
|
||||
concurrentlyN_
|
||||
[ bob <## "#team: alice changed the role of cath from member to moderator (signed)",
|
||||
cath <## "#team: alice changed your role from member to moderator (signed)",
|
||||
dan <## "#team: alice changed the role of cath from member to moderator (signed)",
|
||||
eve <## "#team: alice changed the role of cath from member to moderator (signed)"
|
||||
]
|
||||
|
||||
-- cath (moderator) blocks dan; profile prepend carries cath's full profile to dan/eve
|
||||
threadDelay 1000000
|
||||
@@ -9540,9 +9548,12 @@ testChannelModeratorActionViaRoster ps =
|
||||
dan <## "#team: bob introduced cath (Catherine) in the channel"
|
||||
|
||||
-- frank joins after the roster update; cached roster gives him cath as moderator.
|
||||
-- both alice (owner) and cath (mod) receive XGrpMemNew(frank) via introduceInChannel
|
||||
-- both alice (owner) and cath (mod) receive XGrpMemNew(frank) via introduceInChannel.
|
||||
-- the roster apply also emits the role-change chat item on frank's side (owner
|
||||
-- profile may not be loaded yet, so the actor renders by memberId hash)
|
||||
threadDelay 1000000
|
||||
memberJoinChannel "team" [bob] [alice, cath] shortLink fullLink frank
|
||||
frank <### [EndsWith "changed the role of cath from member to moderator (signed)"]
|
||||
threadDelay 500000
|
||||
checkMemberRole frank "cath" "moderator"
|
||||
where
|
||||
@@ -9563,12 +9574,16 @@ testChannelRemovedModeratorRefreshesRoster ps =
|
||||
(shortLink, fullLink) <- prepareChannel1Relay "team" alice bob
|
||||
forM_ [cath, dan, eve] $ \member ->
|
||||
memberJoinChannel "team" [bob] [alice] shortLink fullLink member
|
||||
-- dan/eve don't know cath; XGrpMemRole is silently skipped (relay-group branch)
|
||||
-- dan/eve XGrpMemRole is skipped; roster apply creates cath and emits the chat item
|
||||
threadDelay 1000000
|
||||
alice ##> "/mr #team cath moderator"
|
||||
alice <## "#team: you changed the role of cath to moderator (signed)"
|
||||
bob <## "#team: alice changed the role of cath from member to moderator (signed)"
|
||||
cath <## "#team: alice changed your role from member to moderator (signed)"
|
||||
concurrentlyN_
|
||||
[ bob <## "#team: alice changed the role of cath from member to moderator (signed)",
|
||||
cath <## "#team: alice changed your role from member to moderator (signed)",
|
||||
dan <## "#team: alice changed the role of cath from member to moderator (signed)",
|
||||
eve <## "#team: alice changed the role of cath from member to moderator (signed)"
|
||||
]
|
||||
threadDelay 1000000
|
||||
alice ##> "/rm #team cath"
|
||||
alice <## "#team: you removed cath from the group (signed)"
|
||||
@@ -9595,12 +9610,16 @@ testChannelLeftModeratorDropsFromRoster ps =
|
||||
(shortLink, fullLink) <- prepareChannel1Relay "team" alice bob
|
||||
forM_ [cath, dan, eve] $ \member ->
|
||||
memberJoinChannel "team" [bob] [alice] shortLink fullLink member
|
||||
-- promote cath; dan/eve unknown branch silently no-ops, they pick up cath from the roster
|
||||
-- promote cath; dan/eve XGrpMemRole skipped, roster apply emits the chat item
|
||||
threadDelay 1000000
|
||||
alice ##> "/mr #team cath moderator"
|
||||
alice <## "#team: you changed the role of cath to moderator (signed)"
|
||||
bob <## "#team: alice changed the role of cath from member to moderator (signed)"
|
||||
cath <## "#team: alice changed your role from member to moderator (signed)"
|
||||
concurrentlyN_
|
||||
[ bob <## "#team: alice changed the role of cath from member to moderator (signed)",
|
||||
cath <## "#team: alice changed your role from member to moderator (signed)",
|
||||
dan <## "#team: alice changed the role of cath from member to moderator (signed)",
|
||||
eve <## "#team: alice changed the role of cath from member to moderator (signed)"
|
||||
]
|
||||
-- cath (moderator) leaves; owner xGrpLeave refreshes the cached roster
|
||||
threadDelay 1000000
|
||||
cath ##> "/leave #team"
|
||||
@@ -9631,13 +9650,16 @@ testChannelRoleTransitionsUpdateRoster ps =
|
||||
(shortLink, fullLink) <- prepareChannel1Relay "team" alice bob
|
||||
forM_ [cath, dan, eve] $ \member ->
|
||||
memberJoinChannel "team" [bob] [alice] shortLink fullLink member
|
||||
-- member -> moderator: dan/eve don't know cath, role event silently skipped;
|
||||
-- the subsequent roster broadcast gives them cath as moderator
|
||||
-- member -> moderator: dan/eve XGrpMemRole skipped; roster apply creates cath and emits chat item
|
||||
threadDelay 1000000
|
||||
alice ##> "/mr #team cath moderator"
|
||||
alice <## "#team: you changed the role of cath to moderator (signed)"
|
||||
bob <## "#team: alice changed the role of cath from member to moderator (signed)"
|
||||
cath <## "#team: alice changed your role from member to moderator (signed)"
|
||||
concurrentlyN_
|
||||
[ bob <## "#team: alice changed the role of cath from member to moderator (signed)",
|
||||
cath <## "#team: alice changed your role from member to moderator (signed)",
|
||||
dan <## "#team: alice changed the role of cath from member to moderator (signed)",
|
||||
eve <## "#team: alice changed the role of cath from member to moderator (signed)"
|
||||
]
|
||||
-- moderator -> admin (within roster): dan/eve now know cath, so role event lands cleanly
|
||||
threadDelay 1000000
|
||||
alice ##> "/mr #team cath admin"
|
||||
|
||||
Reference in New Issue
Block a user