Skip to content

Commit

Permalink
[FS-1335] Remove clients from subconversations when user is removed f…
Browse files Browse the repository at this point in the history
…rom main conversation (#2942)
  • Loading branch information
pcapriotti authored Feb 15, 2023
1 parent d9d1641 commit e1253d4
Show file tree
Hide file tree
Showing 13 changed files with 515 additions and 129 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removing or kicking a user from a conversation also removes the user's clients from any subconversation.
19 changes: 19 additions & 0 deletions libs/wire-api/src/Wire/API/User/Client.hs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ module Wire.API.User.Client
longitude,
Latitude (..),
Longitude (..),

-- * List of MLS client ids
ClientList (..),
)
where

Expand Down Expand Up @@ -472,6 +475,22 @@ instance ToSchema Client where
mlsPublicKeysFieldSchema :: ObjectSchema SwaggerDoc MLSPublicKeys
mlsPublicKeysFieldSchema = fromMaybe mempty <$> optField "mls_public_keys" mlsPublicKeysSchema

--------------------------------------------------------------------------------
-- ClientList

-- | Client list for internal API.
data ClientList = ClientList {clClients :: [ClientId]}
deriving stock (Eq, Show, Generic)
deriving (Arbitrary) via (GenericUniform ClientList)
deriving (FromJSON, ToJSON, Swagger.ToSchema) via Schema ClientList

instance ToSchema ClientList where
schema =
object "ClientList" $
ClientList
<$> clClients
.= field "client_ids" (array schema)

--------------------------------------------------------------------------------
-- PubClient

Expand Down
53 changes: 28 additions & 25 deletions services/galley/src/Galley/API/Action.hs
Original file line number Diff line number Diff line change
Expand Up @@ -132,21 +132,36 @@ type family HasConversationActionEffects (tag :: ConversationActionTag) r :: Con
r
HasConversationActionEffects 'ConversationLeaveTag r =
( Members
'[ MemberStore,
Error InternalError,
'[ Error InternalError,
Error NoChanges,
ExternalAccess,
FederatorAccess,
GundeckAccess,
Input UTCTime,
Input Env,
Input UTCTime,
MemberStore,
ProposalStore,
SubConversationStore,
TinyLog
]
r
)
HasConversationActionEffects 'ConversationRemoveMembersTag r =
(Members '[MemberStore, Error NoChanges] r)
( Members
'[ MemberStore,
SubConversationStore,
ProposalStore,
Input Env,
Input UTCTime,
ExternalAccess,
FederatorAccess,
GundeckAccess,
Error InternalError,
Error NoChanges,
TinyLog
]
r
)
HasConversationActionEffects 'ConversationMemberUpdateTag r =
(Members '[MemberStore, ErrorS 'ConvMemberNotFound] r)
HasConversationActionEffects 'ConversationDeleteTag r =
Expand Down Expand Up @@ -309,6 +324,9 @@ type family PerformActionCalls tag where
PerformActionCalls 'ConversationLeaveTag =
( CallsFed 'Galley "on-mls-message-sent"
)
PerformActionCalls 'ConversationRemoveMembersTag =
( CallsFed 'Galley "on-mls-message-sent"
)
PerformActionCalls 'ConversationDeleteTag =
( CallsFed 'Galley "on-delete-mls-conversation"
)
Expand All @@ -334,31 +352,16 @@ performAction tag origUser lconv action = do
performConversationJoin origUser lconv action
SConversationLeaveTag -> do
let victims = [origUser]
E.deleteMembers (tUnqualified lcnv) (toUserList lconv victims)
-- update in-memory view of the conversation
let lconv' =
lconv <&> \c ->
foldQualified
lconv
( \lu ->
c
{ convLocalMembers =
filter (\lm -> lmId lm /= tUnqualified lu) (convLocalMembers c)
}
)
( \ru ->
c
{ convRemoteMembers =
filter (\rm -> rmId rm /= ru) (convRemoteMembers c)
}
)
origUser
lconv' <- traverse (convDeleteMembers (toUserList lconv victims)) lconv
-- send remove proposals in the MLS case
traverse_ (removeUser lconv') victims
pure (mempty, action)
SConversationRemoveMembersTag -> do
let presentVictims = filter (isConvMemberL lconv) (toList action)
when (null presentVictims) noChanges
E.deleteMembers (tUnqualified lcnv) (toUserList lconv presentVictims)
traverse_ (convDeleteMembers (toUserList lconv presentVictims)) lconv
-- send remove proposals in the MLS case
traverse_ (removeUser lconv) presentVictims
pure (mempty, action) -- FUTUREWORK: should we return the filtered action here?
SConversationMemberUpdateTag -> do
void $ ensureOtherMember lconv (cmuTarget action) conv
Expand Down Expand Up @@ -487,8 +490,8 @@ performConversationJoin qusr lconv (ConversationJoin invited role) = do
'[ ConversationStore,
Error InternalError,
ErrorS ('ActionDenied 'LeaveConversation),
ErrorS 'InvalidOperation,
ErrorS 'ConvNotFound,
ErrorS 'InvalidOperation,
ErrorS 'MissingLegalholdConsent,
ExternalAccess,
FederatorAccess,
Expand Down
3 changes: 2 additions & 1 deletion services/galley/src/Galley/API/Clients.hs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ rmClientH ::
MemberStore,
Error InternalError,
ProposalStore,
P.TinyLog
P.TinyLog,
SubConversationStore
]
r,
CallsFed 'Galley "on-client-removed",
Expand Down
1 change: 1 addition & 0 deletions services/galley/src/Galley/API/Federation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ onClientRemoved ::
Input UTCTime,
MemberStore,
ProposalStore,
SubConversationStore,
TinyLog
]
r,
Expand Down
36 changes: 35 additions & 1 deletion services/galley/src/Galley/API/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import Control.Exception.Safe (catchAny)
import Control.Lens hiding (Getter, Setter, (.=))
import Data.Id as Id
import Data.List1 (maybeList1)
import qualified Data.Map as Map
import Data.Qualified
import Data.Range
import Data.Singletons
Expand Down Expand Up @@ -60,6 +61,7 @@ import Galley.Effects.FederatorAccess
import Galley.Effects.GundeckAccess
import Galley.Effects.LegalHoldStore as LegalHoldStore
import Galley.Effects.MemberStore
import qualified Galley.Effects.MemberStore as E
import Galley.Effects.TeamStore
import qualified Galley.Intra.Push as Intra
import Galley.Monad
Expand All @@ -86,7 +88,7 @@ import qualified Servant hiding (WithStatus)
import System.Logger.Class hiding (Path, name)
import qualified System.Logger.Class as Log
import Wire.API.ApplyMods
import Wire.API.Conversation hiding (Member)
import Wire.API.Conversation
import Wire.API.Conversation.Action
import Wire.API.Conversation.Role
import Wire.API.CustomBackend
Expand All @@ -96,6 +98,7 @@ import Wire.API.Event.Conversation
import Wire.API.Federation.API
import Wire.API.Federation.API.Galley
import Wire.API.Federation.Error
import Wire.API.MLS.Group
import Wire.API.Provider.Service hiding (Service)
import Wire.API.Routes.API
import Wire.API.Routes.Internal.Galley.TeamFeatureNoConfigMulti
Expand All @@ -109,6 +112,7 @@ import Wire.API.Team
import Wire.API.Team.Feature
import Wire.API.Team.Member
import Wire.API.Team.SearchVisibility
import Wire.API.User.Client
import Wire.Sem.Paging
import Wire.Sem.Paging.Cassandra

Expand Down Expand Up @@ -271,6 +275,19 @@ type InternalAPIBase =
:> ReqBody '[Servant.JSON] Connect
:> ConversationVerb
)
-- This endpoint is meant for testing membership of a conversation
:<|> Named
"get-conversation-clients"
( Summary "Get mls conversation client list"
:> ZLocalUser
:> CanThrow 'ConvNotFound
:> "conversation"
:> Capture "cnv" ConvId
:> MultiVerb1
'GET
'[Servant.JSON]
(Respond 200 "Clients" ClientList)
)
:<|> Named
"guard-legalhold-policy-conflicts"
( "guard-legalhold-policy-conflicts"
Expand Down Expand Up @@ -479,6 +496,7 @@ internalAPI =
mkNamedAPI @"status" (pure ())
<@> mkNamedAPI @"delete-user" (callsFed rmUser)
<@> mkNamedAPI @"connect" (callsFed Create.createConnectConversation)
<@> mkNamedAPI @"get-conversation-clients" iGetMLSClientListForConv
<@> mkNamedAPI @"guard-legalhold-policy-conflicts" guardLegalholdPolicyConflictsH
<@> legalholdWhitelistedTeamsAPI
<@> iTeamsAPI
Expand Down Expand Up @@ -688,6 +706,7 @@ rmUser ::
MemberStore,
ProposalStore,
P.TinyLog,
SubConversationStore,
TeamStore
]
r,
Expand Down Expand Up @@ -842,3 +861,18 @@ guardLegalholdPolicyConflictsH ::
guardLegalholdPolicyConflictsH glh = do
mapError @LegalholdConflicts (const $ Tagged @'MissingLegalholdConsent ()) $
guardLegalholdPolicyConflicts (glhProtectee glh) (glhUserClients glh)

-- | Get an MLS conversation client list
iGetMLSClientListForConv ::
forall r.
Members
'[ MemberStore,
ErrorS 'ConvNotFound
]
r =>
Local UserId ->
ConvId ->
Sem r ClientList
iGetMLSClientListForConv lusr cnv = do
cm <- E.lookupMLSClients (convToGroupId (qualifyAs lusr cnv))
pure $ ClientList (concatMap (Map.keys . snd) (Map.assocs cm))
Loading

0 comments on commit e1253d4

Please sign in to comment.