Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/3-bug-fixes/mls-message-epoch-0
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reject messages in MLS groups while in epoch 0.
2 changes: 1 addition & 1 deletion integration/test/API/Galley.hs
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ getSelfMember user conv = do
req <- baseRequest user Galley Versioned (joinHttpPath ["conversations", domain, cnv, "self"])
submit "GET" req

resetConversation :: (MakesValue user) => user -> String -> Word64 -> App Response
resetConversation :: (HasCallStack, MakesValue user) => user -> String -> Word64 -> App Response
resetConversation user groupId epoch = do
req <- baseRequest user Galley Versioned (joinHttpPath ["mls", "reset-conversation"])
let payload = object ["group_id" .= groupId, "epoch" .= epoch]
Expand Down
8 changes: 6 additions & 2 deletions integration/test/MLS/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,8 +1015,8 @@ removeMemberFromChannel user channel userToBeRemoved = do
}

resetMLSConversation ::
(HasCallStack, MakesValue cid, MakesValue conv) =>
cid ->
(HasCallStack, MakesValue conv) =>
ClientIdentity ->
conv ->
App Value
resetMLSConversation cid conv = do
Expand All @@ -1043,4 +1043,8 @@ resetMLSConversation cid conv = do
)
$ Map.delete convId mls.convs
}

mlsConv' <- getMLSConv convId'
keys <- getMLSPublicKeys cid >>= getJSON 200
resetClientGroup mlsConv'.ciphersuite cid mlsConv'.groupId convId' keys
pure conv'
22 changes: 22 additions & 0 deletions integration/test/Test/MLS.hs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,28 @@ testPastStaleApplicationMessage otherDomain = do
-- bob's application messages are now rejected
void $ postMLSMessage bob1 msg2.message >>= getJSON 409

testEpochZeroApplicationMessage :: (HasCallStack) => App ()
testEpochZeroApplicationMessage = do
[alice] <- createAndConnectUsers [make OwnDomain]
alice1 <- createMLSClient def alice
conv <- createNewGroup def alice1
void $ createAddCommit alice1 conv [] >>= sendAndConsumeCommitBundle
mlsConv <- getMLSConv conv

-- send message, make sure that's succeeding
msg <- createApplicationMessage mlsConv.convId alice1 "group is initialised"
postMLSMessage alice1 msg.message >>= assertStatus 201

-- reset conversation, so it exists on server and client with epoch 0
convId' <- objConvId =<< resetMLSConversation alice1 conv

-- send message, make sure that's failing
msg' <- createApplicationMessage convId' alice1 "group not initialised"
postMLSMessage alice1 msg'.message >>= flip withResponse \resp -> do
j <- getJSON 400 resp
j %. "label" `shouldMatch` "mls-protocol-error"
j %. "message" `shouldMatch` "Application messages at epoch 0 are not supported"

testFutureStaleApplicationMessage :: (HasCallStack) => App ()
testFutureStaleApplicationMessage = do
[alice, bob, charlie] <- createAndConnectUsers [OwnDomain, OwnDomain, OwnDomain]
Expand Down
6 changes: 3 additions & 3 deletions integration/test/Test/MLS/Reset.hs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ testResetSelfConversation = do
void $ createAddCommit alice1 convId [alice] >>= sendAndConsumeCommitBundle
mlsConv <- getMLSConv convId

conv' <- resetMLSConversation alice conv
conv' <- resetMLSConversation alice1 conv
conv' %. "group_id" `shouldNotMatch` (mlsConv.groupId :: String)
conv' %. "epoch" `shouldMatchInt` 0
convId' <- objConvId conv'
Expand All @@ -83,15 +83,15 @@ testResetOne2OneConversation = do
otherDomain <- asString OtherDomain
conv <- getMLSOne2OneConversation alice bob >>= getJSON 200
convOwnerDomain <- asString $ conv %. "conversation.qualified_id.domain"
let user = if convOwnerDomain == otherDomain then bob else alice
let (user, cid) = if convOwnerDomain == otherDomain then (bob, bob1) else (alice, alice1)
convId <- objConvId (conv %. "conversation")

resetOne2OneGroup def alice1 conv
void $ createAddCommit alice1 convId [bob] >>= sendAndConsumeCommitBundle
void $ createPendingProposalCommit convId alice1 >>= sendAndConsumeCommitBundle
mlsConv <- getMLSConv convId

conv' <- resetMLSConversation user (conv %. "conversation")
conv' <- resetMLSConversation cid (conv %. "conversation")
conv' %. "group_id" `shouldNotMatch` (mlsConv.groupId :: String)
conv' %. "epoch" `shouldMatchInt` 0
convId' <- objConvId conv'
Expand Down
7 changes: 5 additions & 2 deletions services/galley/src/Galley/API/MLS/Message.hs
Original file line number Diff line number Diff line change
Expand Up @@ -506,10 +506,13 @@ postMLSMessageToLocalConv qusr c con msg ctype convOrSubId = do
for_ convOrSub.ciphersuite $ \ciphersuite -> do
checkConversationOutOfSync mempty lConvOrSub ciphersuite

-- reject application messages older than 2 epochs
-- FUTUREWORK: consider rejecting this message if the conversation epoch is 0
-- reject application messages for epoch 0
let epochInt :: Epoch -> Integer
epochInt = fromIntegral . epochNumber
when (epochInt msg.epoch == 0) . throw $
mlsProtocolError "Application messages at epoch 0 are not supported"

-- reject application messages older than 2 epochs
case convOrSub.mlsMeta.cnvmlsActiveData of
Nothing -> throw $ mlsProtocolError "Application messages at epoch 0 are not supported"
Just activeData ->
Expand Down