Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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.
15 changes: 10 additions & 5 deletions integration/test/MLS/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,16 +1015,17 @@ removeMemberFromChannel user channel userToBeRemoved = do
}

resetMLSConversation ::
(HasCallStack, MakesValue cid, MakesValue conv) =>
cid ->
(HasCallStack, MakesValue user, MakesValue conv) =>
user ->
ClientIdentity ->
conv ->
App Value
resetMLSConversation cid conv = do
resetMLSConversation user cid conv = do
convId <- objConvId conv
mlsConv <- getMLSConv convId
resetConversation cid mlsConv.groupId mlsConv.epoch >>= assertStatus 200
resetConversation user mlsConv.groupId mlsConv.epoch >>= assertStatus 200

conv' <- getConversation cid convId >>= getJSON 200
conv' <- getConversation user convId >>= getJSON 200
groupId <- conv' %. "group_id" & asString
groupId `shouldNotMatch` (mlsConv.groupId :: String)
conv' %. "epoch" `shouldMatchInt` 0
Expand All @@ -1043,4 +1044,8 @@ resetMLSConversation cid conv = do
)
$ Map.delete convId mls.convs
}

mlsConv' <- getMLSConv convId'
keys <- getMLSPublicKeys user >>= 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 alice 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 alice 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 user 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