Skip to content

Commit 9057378

Browse files
committed
Add RPC for remote MLS messaging
1 parent 28ef304 commit 9057378

File tree

3 files changed

+85
-25
lines changed

3 files changed

+85
-25
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import Data.Qualified
2626
import Data.Range
2727
import Data.Time.Clock (UTCTime)
2828
import Imports
29+
import qualified Network.Wai.Utilities.Error as Wai
2930
import Servant.API
3031
import Wire.API.Arbitrary (Arbitrary, GenericUniform (..))
3132
import Wire.API.Conversation
@@ -61,6 +62,7 @@ type GalleyApi =
6162
:<|> FedEndpoint "on-user-deleted-conversations" UserDeletedConversationsNotification EmptyResponse
6263
:<|> FedEndpoint "update-conversation" ConversationUpdateRequest ConversationUpdateResponse
6364
:<|> FedEndpoint "mls-welcome" MLSWelcomeRequest ()
65+
:<|> FedEndpoint "send-mls-message" MessageSendRequest MLSMessageResponse
6466

6567
data GetConversationsRequest = GetConversationsRequest
6668
{ gcrUserId :: UserId,
@@ -270,3 +272,13 @@ data MLSWelcomeRequest = MLSWelcomeRequest
270272
deriving stock (Generic)
271273
deriving (Arbitrary) via (GenericUniform MLSWelcomeRequest)
272274
deriving (FromJSON, ToJSON) via (CustomEncoded MLSWelcomeRequest)
275+
276+
data MLSMessageResponse
277+
= MLSMessageResponseError GalleyError
278+
| MLSProtocolError Text
279+
| MLSProposalFailure Wai.Error
280+
| MLSMessageResponseUpdates [ConversationUpdate]
281+
deriving stock (Show, Generic)
282+
deriving
283+
(ToJSON, FromJSON)
284+
via (CustomEncoded MLSMessageResponse)

services/galley/src/Galley/API/Federation.hs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ import Data.Qualified
3232
import Data.Range (Range (fromRange))
3333
import qualified Data.Set as Set
3434
import Data.Singletons (SingI (..), demote, sing)
35+
import Data.Tagged
3536
import qualified Data.Text.Lazy as LT
3637
import Data.Time.Clock
3738
import Galley.API.Action
3839
import Galley.API.Error
40+
import Galley.API.MLS.Message
3941
import qualified Galley.API.Mapping as Mapping
4042
import Galley.API.Message
4143
import Galley.API.Push
@@ -72,6 +74,7 @@ import Wire.API.Federation.API.Common (EmptyResponse (..))
7274
import Wire.API.Federation.API.Galley (ConversationUpdateResponse)
7375
import qualified Wire.API.Federation.API.Galley as F
7476
import Wire.API.Federation.Error
77+
import Wire.API.MLS.Serialisation
7578
import Wire.API.Routes.Internal.Brig.Connection
7679
import Wire.API.Routes.Named
7780
import Wire.API.ServantProto
@@ -91,6 +94,7 @@ federationSitemap =
9194
:<|> Named @"on-user-deleted-conversations" onUserDeleted
9295
:<|> Named @"update-conversation" updateConversation
9396
:<|> Named @"mls-welcome" mlsSendWelcome
97+
:<|> Named @"send-mls-message" sendMLSMessage
9498

9599
onConversationCreated ::
96100
Members
@@ -517,6 +521,43 @@ updateConversation origDomain updateRequest = do
517521
toResponse (Right (Left NoChanges)) = F.ConversationUpdateResponseNoChanges
518522
toResponse (Right (Right update)) = F.ConversationUpdateResponseUpdate update
519523

524+
sendMLSMessage ::
525+
( Members
526+
[ BrigAccess,
527+
ConversationStore,
528+
ExternalAccess,
529+
Error FederationError,
530+
FederatorAccess,
531+
GundeckAccess,
532+
Input (Local ()),
533+
Input Opts,
534+
Input UTCTime,
535+
LegalHoldStore,
536+
MemberStore,
537+
TeamStore,
538+
P.TinyLog
539+
]
540+
r
541+
) =>
542+
Domain ->
543+
F.MessageSendRequest ->
544+
Sem r F.MLSMessageResponse
545+
sendMLSMessage remoteDomain msr =
546+
fmap (either F.MLSProtocolError id)
547+
. runError
548+
. fmap (either F.MLSMessageResponseError id)
549+
. runError
550+
. fmap (either (F.MLSProposalFailure . pfInner) id)
551+
. runError
552+
$ do
553+
loc <- qualifyLocal ()
554+
let sender = toRemoteUnsafe remoteDomain (F.msrSender msr)
555+
raw <- either throw pure $ decodeMLS' (fromBase64ByteString (F.msrRawMessage msr))
556+
mapToGalleyError @MLSMessageStaticErrors
557+
. mapError @MLSProtocolError unTagged
558+
$ F.MLSMessageResponseUpdates . map lcuUpdate
559+
<$> postMLSMessage loc (qUntagged sender) Nothing raw
560+
520561
class ToGalleyRuntimeError (effs :: EffectRow) r where
521562
mapToGalleyError ::
522563
Member (Error GalleyError) r =>

services/galley/src/Galley/API/MLS/Message.hs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
module Galley.API.MLS.Message
2020
( postMLSMessageFromLocalUser,
2121
postMLSMessage,
22+
MLSMessageStaticErrors,
2223
)
2324
where
2425

@@ -63,24 +64,30 @@ import Wire.API.MLS.Message
6364
import Wire.API.MLS.Proposal
6465
import Wire.API.MLS.Serialisation
6566

67+
type MLSMessageStaticErrors =
68+
'[ ErrorS 'ConvNotFound,
69+
ErrorS 'MLSUnsupportedMessage,
70+
ErrorS 'MLSStaleMessage,
71+
ErrorS 'MLSProposalNotFound,
72+
ErrorS 'MissingLegalholdConsent,
73+
ErrorS 'MLSKeyPackageRefNotFound,
74+
ErrorS 'MLSClientMismatch,
75+
ErrorS 'MLSUnsupportedProposal
76+
]
77+
6678
postMLSMessageFromLocalUser ::
6779
( HasProposalEffects r,
68-
Members
69-
'[ Error FederationError,
70-
ErrorS 'ConvNotFound,
71-
ErrorS 'MLSUnsupportedMessage,
72-
ErrorS 'MLSStaleMessage,
73-
ErrorS 'MLSProposalNotFound,
74-
ErrorS 'MissingLegalholdConsent,
75-
TinyLog
76-
]
77-
r
80+
Members MLSMessageStaticErrors r,
81+
Member (Error FederationError) r,
82+
Member TinyLog r
7883
) =>
7984
Local UserId ->
8085
ConnId ->
8186
RawMLS SomeMessage ->
8287
Sem r [Event]
83-
postMLSMessageFromLocalUser lusr = postMLSMessage lusr (qUntagged lusr)
88+
postMLSMessageFromLocalUser lusr conn msg =
89+
map lcuEvent
90+
<$> postMLSMessage lusr (qUntagged lusr) (Just conn) msg
8491

8592
postMLSMessage ::
8693
( HasProposalEffects r,
@@ -97,9 +104,9 @@ postMLSMessage ::
97104
) =>
98105
Local x ->
99106
Qualified UserId ->
100-
ConnId ->
107+
Maybe ConnId ->
101108
RawMLS SomeMessage ->
102-
Sem r [Event]
109+
Sem r [LocalConversationUpdate]
103110
postMLSMessage loc qusr con smsg = case rmValue smsg of
104111
SomeMessage tag msg -> do
105112
-- fetch conversation
@@ -128,8 +135,8 @@ postMLSMessage loc qusr con smsg = case rmValue smsg of
128135
type HasProposalEffects r =
129136
( Member BrigAccess r,
130137
Member ConversationStore r,
131-
Member (Error MLSProtocolError) r,
132138
Member (Error MLSProposalFailure) r,
139+
Member (Error MLSProtocolError) r,
133140
Member (ErrorS 'MLSKeyPackageRefNotFound) r,
134141
Member (ErrorS 'MLSClientMismatch) r,
135142
Member (ErrorS 'MLSUnsupportedProposal) r,
@@ -169,11 +176,11 @@ processCommit ::
169176
Member (ErrorS 'MissingLegalholdConsent) r
170177
) =>
171178
Qualified UserId ->
172-
ConnId ->
179+
Maybe ConnId ->
173180
Local Data.Conversation ->
174181
Epoch ->
175182
Commit ->
176-
Sem r [Event]
183+
Sem r [LocalConversationUpdate]
177184
processCommit qusr con lconv epoch commit = do
178185
-- check epoch number
179186
curEpoch <-
@@ -183,12 +190,12 @@ processCommit qusr con lconv epoch commit = do
183190

184191
-- process and execute proposals
185192
action <- foldMap applyProposalRef (cProposals commit)
186-
events <- executeProposalAction qusr con lconv action
193+
updates <- executeProposalAction qusr con lconv action
187194

188195
-- increment epoch number
189196
setConversationEpoch (Data.convId (tUnqualified lconv)) (succ epoch)
190197

191-
pure events
198+
pure updates
192199

193200
applyProposalRef ::
194201
( HasProposalEffects r,
@@ -227,10 +234,10 @@ executeProposalAction ::
227234
Member TeamStore r
228235
) =>
229236
Qualified UserId ->
230-
ConnId ->
237+
Maybe ConnId ->
231238
Local Data.Conversation ->
232239
ProposalAction ->
233-
Sem r [Event]
240+
Sem r [LocalConversationUpdate]
234241
executeProposalAction qusr con lconv action = do
235242
-- For the moment, assume a fixed ciphersuite.
236243
-- FUTUREWORK: store ciphersuite with the conversation
@@ -260,17 +267,17 @@ executeProposalAction qusr con lconv action = do
260267
-- FUTUREWORK: turn this error into a proper response
261268
throwS @'MLSClientMismatch
262269

263-
addMembers :: NonEmpty (Qualified UserId) -> Sem r [Event]
270+
addMembers :: NonEmpty (Qualified UserId) -> Sem r [LocalConversationUpdate]
264271
addMembers users =
265272
-- FUTUREWORK: update key package ref mapping to reflect conversation membership
266273
handleNoChanges
267274
. handleMLSProposalFailures @ProposalErrors
268-
. fmap (pure . lcuEvent) -- TODO: keep track of ConversationUpdate in the remote case
275+
. fmap (pure)
269276
. updateLocalConversationUnchecked
270277
@'ConversationJoinTag
271278
lconv
272279
qusr
273-
(Just con)
280+
con
274281
$ ConversationJoin users roleNameWireMember
275282

276283
handleNoChanges :: Monoid a => Sem (Error NoChanges ': r) a -> Sem r a
@@ -294,7 +301,7 @@ propagateMessage ::
294301
Local x ->
295302
Qualified UserId ->
296303
Data.Conversation ->
297-
ConnId ->
304+
Maybe ConnId ->
298305
ByteString ->
299306
Sem r ()
300307
propagateMessage loc qusr conv con raw = do
@@ -308,7 +315,7 @@ propagateMessage loc qusr conv con raw = do
308315
e = Event qcnv qusr now $ EdMLSMessage raw
309316
lclients = tUnqualified . clients <$> lmems
310317
mkPush :: UserId -> ClientId -> MessagePush 'NormalMessage
311-
mkPush u c = newMessagePush lcnv lmMap (Just con) defMessageMetadata (u, c) e
318+
mkPush u c = newMessagePush lcnv lmMap con defMessageMetadata (u, c) e
312319
runMessagePush loc (Just qcnv) $
313320
foldMap (uncurry mkPush) (cToList =<< lclients)
314321
where

0 commit comments

Comments
 (0)