Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FS-873] Leaving MLS Conversations and Backend-side Removals #2667

Merged
merged 11 commits into from
Sep 14, 2022
37 changes: 29 additions & 8 deletions cassandra-schema.cql
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ CREATE TABLE galley_test.member (
conversation_role text,
hidden boolean,
hidden_ref text,
mls_clients_keypackages set<frozen<tuple<text, blob>>>,
otr_archived boolean,
otr_archived_ref text,
otr_muted boolean,
Expand Down Expand Up @@ -262,7 +261,6 @@ CREATE TABLE galley_test.member_remote_user (
user_remote_domain text,
user_remote_id uuid,
conversation_role text,
mls_clients_keypackages set<frozen<tuple<text, blob>>>,
PRIMARY KEY (conv, user_remote_domain, user_remote_id)
) WITH CLUSTERING ORDER BY (user_remote_domain ASC, user_remote_id ASC)
AND bloom_filter_fp_chance = 0.1
Expand Down Expand Up @@ -365,15 +363,18 @@ CREATE TABLE galley_test.group_id_conv_id (
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';

CREATE TABLE galley_test.user (
user uuid,
CREATE TABLE galley_test.member_client (
conv uuid,
PRIMARY KEY (user, conv)
) WITH CLUSTERING ORDER BY (conv ASC)
AND bloom_filter_fp_chance = 0.1
user_domain text,
user uuid,
client text,
key_package_ref blob,
PRIMARY KEY (conv, user_domain, user, client)
) WITH CLUSTERING ORDER BY (user_domain ASC, user ASC, client ASC)
AND bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy'}
AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND dclocal_read_repair_chance = 0.1
Expand Down Expand Up @@ -565,6 +566,26 @@ CREATE TABLE galley_test.mls_proposal_refs (
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';

CREATE TABLE galley_test.user (
user uuid,
conv uuid,
PRIMARY KEY (user, conv)
) WITH CLUSTERING ORDER BY (conv ASC)
AND bloom_filter_fp_chance = 0.1
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND dclocal_read_repair_chance = 0.1
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';

CREATE KEYSPACE gundeck_test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true;

CREATE TABLE gundeck_test.push (
Expand Down
1 change: 1 addition & 0 deletions changelog.d/1-api-changes/leave-mls-conv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Leaving an MLS conversation is now possible using the regular endpoint `DELETE /conversations/{cnv_domain}/{cnv}/members/{usr_domain}/{usr}`. When a user leaves, the backend sends external remove proposals for all their clients in the corresponding MLS group.
1 change: 1 addition & 0 deletions changelog.d/5-internal/mls-clients-in-conv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Clients and key package refs in an MLS conversation are now stored in their own table.
11 changes: 3 additions & 8 deletions libs/galley-types/src/Galley/Types/Conversations/Members.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,15 @@ where
import Data.Domain
import Data.Id as Id
import Data.Qualified
import qualified Data.Set as Set
import Imports
import Wire.API.Conversation
import Wire.API.Conversation.Role (RoleName, roleNameWireAdmin)
import Wire.API.MLS.KeyPackage
import Wire.API.Provider.Service (ServiceRef)

-- | Internal (cassandra) representation of a remote conversation member.
data RemoteMember = RemoteMember
{ rmId :: Remote UserId,
rmConvRoleName :: RoleName,
rmMLSClients :: Set (ClientId, KeyPackageRef)
rmConvRoleName :: RoleName
}
deriving stock (Show)

Expand All @@ -64,8 +61,7 @@ data LocalMember = LocalMember
{ lmId :: UserId,
lmStatus :: MemberStatus,
lmService :: Maybe ServiceRef,
lmConvRoleName :: RoleName,
lmMLSClients :: Set (ClientId, KeyPackageRef)
lmConvRoleName :: RoleName
}
deriving stock (Show)

Expand All @@ -78,8 +74,7 @@ newMemberWithRole (u, r) =
{ lmId = u,
lmService = Nothing,
lmStatus = defMemberStatus,
lmConvRoleName = r,
lmMLSClients = Set.empty
lmConvRoleName = r
}

localMemberToOther :: Domain -> LocalMember -> OtherMember
Expand Down
4 changes: 4 additions & 0 deletions libs/types-common/src/Data/Qualified.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module Data.Qualified
indexQualified,
bucketQualified,
bucketRemote,
isLocal,
deprecatedSchema,
qualifiedSchema,
qualifiedObjectSchema,
Expand Down Expand Up @@ -157,6 +158,9 @@ bucketRemote =
. indexQualified
. fmap qUntagged

isLocal :: Local x -> Qualified a -> Bool
isLocal loc = foldQualified loc (const True) (const False)

----------------------------------------------------------------------

deprecatedSchema :: S.HasDescription doc (Maybe Text) => Text -> ValueSchema doc a -> ValueSchema doc a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,5 @@ testObject_ConversationUpdate2 =
cuConvId =
Id (fromJust (UUID.fromString "00000000-0000-0000-0000-000100000006")),
cuAlreadyPresentUsers = [chad, dee],
cuAction = SomeConversationAction (sing @'ConversationLeaveTag) (pure qAlice)
cuAction = SomeConversationAction (sing @'ConversationLeaveTag) ()
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
{
"cuAction": {
"action": {
"users": [
{
"domain": "golden.example.com",
"id": "00000000-0000-0000-0000-000100004007"
}
]
},
"action": {},
"tag": "ConversationLeaveTag"
},
"cuAlreadyPresentUsers": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
{
"Right": {
"failed_to_send": {
"deleted": {
"golden.example.com": {
"00000000-0000-0000-0000-000200000008": [
"0"
],
"00000000-0000-0000-0000-000100000007": [
"00000000-0000-0000-0000-000100000005": [
"0",
"1"
],
"00000000-0000-0000-0000-000200000006": [
"0"
]
}
},
"redundant": {
"failed_to_send": {
"golden.example.com": {
"00000000-0000-0000-0000-000100000003": [
"00000000-0000-0000-0000-000100000007": [
"0",
"1"
],
"00000000-0000-0000-0000-000200000004": [
"00000000-0000-0000-0000-000200000008": [
"0"
]
}
},
"time": "1864-04-12T12:22:43.673Z",
"missing": {
"golden.example.com": {
"00000000-0000-0000-0000-000200000000": [
"0"
],
"00000000-0000-0000-0000-000100000002": [
"0",
"1"
],
"00000000-0000-0000-0000-000200000000": [
"0"
]
}
},
"deleted": {
"redundant": {
"golden.example.com": {
"00000000-0000-0000-0000-000100000005": [
"00000000-0000-0000-0000-000100000003": [
"0",
"1"
],
"00000000-0000-0000-0000-000200000006": [
"00000000-0000-0000-0000-000200000004": [
"0"
]
}
}
},
"time": "1864-04-12T12:22:43.673Z"
}
}
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
{
"Left": {
"tag": "MessageNotSentClientMissing",
"contents": {
"failed_to_send": {
"deleted": {
"golden.example.com": {
"00000000-0000-0000-0000-000200000008": [
"0"
],
"00000000-0000-0000-0000-000100000007": [
"00000000-0000-0000-0000-000100000005": [
"0",
"1"
],
"00000000-0000-0000-0000-000200000006": [
"0"
]
}
},
"redundant": {
"failed_to_send": {
"golden.example.com": {
"00000000-0000-0000-0000-000100000003": [
"00000000-0000-0000-0000-000100000007": [
"0",
"1"
],
"00000000-0000-0000-0000-000200000004": [
"00000000-0000-0000-0000-000200000008": [
"0"
]
}
},
"time": "1864-04-12T12:22:43.673Z",
"missing": {
"golden.example.com": {
"00000000-0000-0000-0000-000200000000": [
"0"
],
"00000000-0000-0000-0000-000100000002": [
"0",
"1"
],
"00000000-0000-0000-0000-000200000000": [
"0"
]
}
},
"deleted": {
"redundant": {
"golden.example.com": {
"00000000-0000-0000-0000-000100000005": [
"00000000-0000-0000-0000-000100000003": [
"0",
"1"
],
"00000000-0000-0000-0000-000200000006": [
"00000000-0000-0000-0000-000200000004": [
"0"
]
}
}
}
},
"time": "1864-04-12T12:22:43.673Z"
},
"tag": "MessageNotSentClientMissing"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"to": "1669240c-c510-43e0-bf1a-33378fa4ba55",
"action": "RemoteConnect",
"from": "69f66843-6cf1-48fb-8c05-1cf58c23566a",
"action": "RemoteConnect"
"to": "1669240c-c510-43e0-bf1a-33378fa4ba55"
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"to": "1669240c-c510-43e0-bf1a-33378fa4ba55",
"action": "RemoteRescind",
"from": "69f66843-6cf1-48fb-8c05-1cf58c23566a",
"action": "RemoteRescind"
"to": "1669240c-c510-43e0-bf1a-33378fa4ba55"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"tag": "NewConnectionResponseOk",
"contents": null
"contents": null,
"tag": "NewConnectionResponseOk"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"tag": "NewConnectionResponseOk",
"contents": "RemoteConnect"
"contents": "RemoteConnect",
"tag": "NewConnectionResponseOk"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"tag": "NewConnectionResponseOk",
"contents": "RemoteRescind"
"contents": "RemoteRescind",
"tag": "NewConnectionResponseOk"
}
6 changes: 3 additions & 3 deletions libs/wire-api/src/Wire/API/Conversation/Action.hs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import Wire.Arbitrary (Arbitrary (..))
-- individual effects per conversation action. See 'HasConversationActionEffects'.
type family ConversationAction (tag :: ConversationActionTag) :: * where
ConversationAction 'ConversationJoinTag = ConversationJoin
ConversationAction 'ConversationLeaveTag = NonEmptyList.NonEmpty (Qualified UserId)
ConversationAction 'ConversationLeaveTag = ()
ConversationAction 'ConversationMemberUpdateTag = ConversationMemberUpdate
ConversationAction 'ConversationDeleteTag = ()
ConversationAction 'ConversationRenameTag = ConversationRename
Expand Down Expand Up @@ -87,7 +87,7 @@ conversationActionSchema SConversationLeaveTag =
objectWithDocModifier
"ConversationLeave"
(S.description ?~ "The action of some users leaving a conversation on their own")
$ field "users" (nonEmptyArray schema)
$ pure ()
conversationActionSchema SConversationRemoveMembersTag =
objectWithDocModifier
"ConversationRemoveMembers"
Expand Down Expand Up @@ -151,7 +151,7 @@ conversationActionToEvent tag now quid qcnv action =
let ConversationJoin newMembers role = action
in EdMembersJoin $ SimpleMembers (map (`SimpleMember` role) (toList newMembers))
SConversationLeaveTag ->
EdMembersLeave (QualifiedUserIdList (toList action))
EdMembersLeave (QualifiedUserIdList [quid])
SConversationRemoveMembersTag ->
EdMembersLeave (QualifiedUserIdList (toList action))
SConversationMemberUpdateTag ->
Expand Down
2 changes: 1 addition & 1 deletion libs/wire-api/src/Wire/API/Conversation/Protocol.hs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ protocolTag (ProtocolMLS _) = ProtocolMLSTag
protocolValidAction :: Protocol -> ConversationActionTag -> Bool
protocolValidAction ProtocolProteus _ = True
protocolValidAction (ProtocolMLS _) ConversationJoinTag = False
protocolValidAction (ProtocolMLS _) ConversationLeaveTag = False
protocolValidAction (ProtocolMLS _) ConversationLeaveTag = True
protocolValidAction (ProtocolMLS _) ConversationRemoveMembersTag = False
protocolValidAction (ProtocolMLS _) ConversationDeleteTag = False
protocolValidAction (ProtocolMLS _) _ = True
Expand Down
2 changes: 1 addition & 1 deletion services/brig/test/integration/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import Data.List1 (List1)
import qualified Data.List1 as List1
import Data.Misc (PlainTextPassword (..))
import Data.Proxy
import Data.Qualified
import Data.Qualified hiding (isLocal)
import Data.Range
import qualified Data.Sequence as Seq
import Data.String.Conversions (cs)
Expand Down
4 changes: 4 additions & 0 deletions services/galley/galley.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ library
Galley.API.MLS.KeyPackage
Galley.API.MLS.Keys
Galley.API.MLS.Message
Galley.API.MLS.Propagate
Galley.API.MLS.Removal
Galley.API.MLS.Types
Galley.API.MLS.Welcome
Galley.API.One2One
Galley.API.Public
Expand Down Expand Up @@ -665,6 +668,7 @@ executable galley-schema
V70_MLSCipherSuite
V71_MemberClientKeypackage
V72_DropManagedConversations
V73_MemberClientTable

hs-source-dirs: schema/src
default-extensions:
Expand Down
Loading