Skip to content

Commit 3db4338

Browse files
smattingpcapriotti
andauthored
Add commit bundle support (#2688)
* wire-api: Add types and test (wip) * Add endpoint in galley * Implement naive PublicGroupState (broken) * Split into PublicGroupStateTBS and PGS * Refactor: use deriving via newtype * Add roundtrip tests * bump cli * Add integration test for commit bundles * Implement federated commit bundle requests * Test remote commit bundles * Fix build * Add CHANGELOG entry * Extract action from commit for welcome verification * Change status code from 409 to 400 for some errors The conflict status code 409 should be used for errors that are caused by race conditions, such as in cases where the client has an out-of-date view on the state of the backend. * Remove redundant error handling * Implement welcome check for commit bundles * Test welcome mismatch * Add new endpoint to charts and demo Co-authored-by: Paolo Capriotti <[email protected]>
1 parent cb6e9c2 commit 3db4338

File tree

26 files changed

+891
-100
lines changed

26 files changed

+891
-100
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add new endpoint `/mls/commit-bundles` for submitting MLS `CommitBundle`s. A `CommitBundle` is a triple consisting of a commit message, an optional welcome message and a public group state.

charts/nginz/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,9 @@ nginx_conf:
478478
- path: /mls/messages
479479
envs:
480480
- all
481+
- path: /mls/commit-bundles
482+
envs:
483+
- all
481484
- path: /mls/public-keys
482485
envs:
483486
- all

deploy/services-demo/conf/nginz/nginx.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,11 @@ http {
425425
proxy_pass http://galley;
426426
}
427427

428+
location /mls/commit-bundles {
429+
include common_response_with_zauth.conf;
430+
proxy_pass http://galley;
431+
}
432+
428433
location /mls/public-keys {
429434
include common_response_with_zauth.conf;
430435
proxy_pass http://galley;

libs/wire-api-federation/src/Wire/API/Federation/API/Galley.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ type GalleyApi =
6969
:<|> FedEndpoint "mls-welcome" MLSWelcomeRequest EmptyResponse
7070
:<|> FedEndpoint "on-mls-message-sent" RemoteMLSMessage EmptyResponse
7171
:<|> FedEndpoint "send-mls-message" MessageSendRequest MLSMessageResponse
72+
:<|> FedEndpoint "send-mls-commit-bundle" MessageSendRequest MLSMessageResponse
7273
:<|> FedEndpoint "on-client-removed" ClientRemovedRequest EmptyResponse
7374

7475
data ClientRemovedRequest = ClientRemovedRequest

libs/wire-api/src/Wire/API/Error/Galley.hs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ data GalleyError
8181
| MLSSelfRemovalNotAllowed
8282
| MLSGroupConversationMismatch
8383
| MLSClientSenderUserMismatch
84+
| MLSWelcomeMismatch
8485
| --
8586
NoBindingTeamMembers
8687
| NoBindingTeam
@@ -192,13 +193,15 @@ type instance MapError 'MLSClientMismatch = 'StaticError 409 "mls-client-mismatc
192193

193194
type instance MapError 'MLSStaleMessage = 'StaticError 409 "mls-stale-message" "The conversation epoch in a message is too old"
194195

195-
type instance MapError 'MLSCommitMissingReferences = 'StaticError 409 "mls-commit-missing-references" "The commit is not referencing all pending proposals"
196+
type instance MapError 'MLSCommitMissingReferences = 'StaticError 400 "mls-commit-missing-references" "The commit is not referencing all pending proposals"
196197

197-
type instance MapError 'MLSSelfRemovalNotAllowed = 'StaticError 409 "mls-self-removal-not-allowed" "Self removal from group is not allowed"
198+
type instance MapError 'MLSSelfRemovalNotAllowed = 'StaticError 400 "mls-self-removal-not-allowed" "Self removal from group is not allowed"
198199

199-
type instance MapError 'MLSGroupConversationMismatch = 'StaticError 409 "mls-group-conversation-mismatch" "Conversation ID resolved from Group ID does not match submitted Conversation ID"
200+
type instance MapError 'MLSGroupConversationMismatch = 'StaticError 400 "mls-group-conversation-mismatch" "Conversation ID resolved from Group ID does not match submitted Conversation ID"
200201

201-
type instance MapError 'MLSClientSenderUserMismatch = 'StaticError 409 "mls-client-sender-user-mismatch" "User ID resolved from Client ID does not match message's sender user ID"
202+
type instance MapError 'MLSClientSenderUserMismatch = 'StaticError 400 "mls-client-sender-user-mismatch" "User ID resolved from Client ID does not match message's sender user ID"
203+
204+
type instance MapError 'MLSWelcomeMismatch = 'StaticError 400 "mls-welcome-mismatch" "The list of targets of a welcome message does not match the list of new clients in a group"
202205

203206
type instance MapError 'NoBindingTeamMembers = 'StaticError 403 "non-binding-team-members" "Both users must be members of the same binding team"
204207

libs/wire-api/src/Wire/API/MLS/CipherSuite.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import Wire.Arbitrary
3737

3838
newtype CipherSuite = CipherSuite {cipherSuiteNumber :: Word16}
3939
deriving stock (Eq, Show)
40-
deriving newtype (ParseMLS, Arbitrary)
40+
deriving newtype (ParseMLS, SerialiseMLS, Arbitrary)
4141

4242
instance ToSchema CipherSuite where
4343
schema =

libs/wire-api/src/Wire/API/MLS/Commit.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Imports
2121
import Wire.API.MLS.KeyPackage
2222
import Wire.API.MLS.Proposal
2323
import Wire.API.MLS.Serialisation
24+
import Wire.Arbitrary
2425

2526
data Commit = Commit
2627
{ cProposals :: [ProposalOrRef],
@@ -53,7 +54,13 @@ data HPKECiphertext = HPKECiphertext
5354
{ hcOutput :: ByteString,
5455
hcCiphertext :: ByteString
5556
}
56-
deriving (Eq, Show)
57+
deriving (Eq, Show, Generic)
58+
deriving (Arbitrary) via (GenericUniform HPKECiphertext)
5759

5860
instance ParseMLS HPKECiphertext where
5961
parseMLS = HPKECiphertext <$> parseMLSBytes @Word16 <*> parseMLSBytes @Word16
62+
63+
instance SerialiseMLS HPKECiphertext where
64+
serialiseMLS (HPKECiphertext out ct) = do
65+
serialiseMLSBytes @Word16 out
66+
serialiseMLSBytes @Word16 ct
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- This file is part of the Wire Server implementation.
2+
--
3+
-- Copyright (C) 2022 Wire Swiss GmbH <[email protected]>
4+
--
5+
-- This program is free software: you can redistribute it and/or modify it under
6+
-- the terms of the GNU Affero General Public License as published by the Free
7+
-- Software Foundation, either version 3 of the License, or (at your option) any
8+
-- later version.
9+
--
10+
-- This program is distributed in the hope that it will be useful, but WITHOUT
11+
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12+
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13+
-- details.
14+
--
15+
-- You should have received a copy of the GNU Affero General Public License along
16+
-- with this program. If not, see <https://www.gnu.org/licenses/>.
17+
{-# LANGUAGE RecordWildCards #-}
18+
19+
module Wire.API.MLS.CommitBundle where
20+
21+
import qualified Data.Swagger as S
22+
import Imports
23+
import Wire.API.MLS.GroupInfoBundle
24+
import Wire.API.MLS.Message
25+
import Wire.API.MLS.Serialisation
26+
import Wire.API.MLS.Welcome
27+
28+
data CommitBundle = CommitBundle
29+
{ cbCommitMsg :: RawMLS (Message 'MLSPlainText),
30+
cbWelcome :: Maybe (RawMLS Welcome),
31+
cbGroupInfoBundle :: GroupInfoBundle
32+
}
33+
deriving (Eq, Show)
34+
35+
instance ParseMLS CommitBundle where
36+
parseMLS = CommitBundle <$> parseMLS <*> parseMLSOptional parseMLS <*> parseMLS
37+
38+
instance S.ToSchema CommitBundle where
39+
declareNamedSchema _ = pure (mlsSwagger "CommitBundle")
40+
41+
instance SerialiseMLS CommitBundle where
42+
serialiseMLS (CommitBundle commit welcome gi) = do
43+
serialiseMLS commit
44+
serialiseMLSOptional serialiseMLS welcome
45+
serialiseMLS gi

libs/wire-api/src/Wire/API/MLS/Extension.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ import Wire.API.MLS.Serialisation
5252
import Wire.Arbitrary
5353

5454
newtype ProtocolVersion = ProtocolVersion {pvNumber :: Word8}
55-
deriving newtype (Eq, Ord, Show, Binary, Arbitrary)
56-
deriving (ParseMLS) via (BinaryMLS ProtocolVersion)
55+
deriving newtype (Eq, Ord, Show, Binary, Arbitrary, ParseMLS, SerialiseMLS)
5756

5857
data ProtocolVersionTag = ProtocolMLS10 | ProtocolMLSDraft11
5958
deriving stock (Bounded, Enum, Eq, Show, Generic)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
-- This file is part of the Wire Server implementation.
2+
--
3+
-- Copyright (C) 2022 Wire Swiss GmbH <[email protected]>
4+
--
5+
-- This program is free software: you can redistribute it and/or modify it under
6+
-- the terms of the GNU Affero General Public License as published by the Free
7+
-- Software Foundation, either version 3 of the License, or (at your option) any
8+
-- later version.
9+
--
10+
-- This program is distributed in the hope that it will be useful, but WITHOUT
11+
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12+
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13+
-- details.
14+
--
15+
-- You should have received a copy of the GNU Affero General Public License along
16+
-- with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
module Wire.API.MLS.GroupInfoBundle where
19+
20+
import Imports
21+
import Test.QuickCheck
22+
import Wire.API.MLS.PublicGroupState
23+
import Wire.API.MLS.Serialisation
24+
import Wire.Arbitrary
25+
26+
data GroupInfoEncryption = UnencryptedGroupInfo | JweEncryptedGroupInfo
27+
deriving stock (Eq, Show, Generic, Bounded, Enum)
28+
deriving (Arbitrary) via (GenericUniform GroupInfoEncryption)
29+
30+
data GroupInfoTreeType = TreeFull | TreeDelta | TreeByRef
31+
deriving stock (Eq, Show, Generic, Bounded, Enum)
32+
deriving (Arbitrary) via (GenericUniform GroupInfoTreeType)
33+
34+
data GroupInfoBundle = GroupInfoBundle
35+
{ gipEncryptionType :: GroupInfoEncryption,
36+
gipTreeType :: GroupInfoTreeType,
37+
gipGroupState :: PublicGroupState
38+
}
39+
deriving stock (Eq, Show, Generic)
40+
deriving (Arbitrary) via GenericUniform GroupInfoBundle
41+
42+
instance ParseMLS GroupInfoBundle where
43+
parseMLS =
44+
GroupInfoBundle
45+
<$> parseMLSEnum @Word8 "GroupInfoEncryptionEnum"
46+
<*> parseMLSEnum @Word8 "RatchetTreeEnum"
47+
<*> parseMLS
48+
49+
instance SerialiseMLS GroupInfoBundle where
50+
serialiseMLS (GroupInfoBundle e t pgs) = do
51+
serialiseMLSEnum @Word8 e
52+
serialiseMLSEnum @Word8 t
53+
serialiseMLS pgs

0 commit comments

Comments
 (0)