Skip to content

Commit

Permalink
[FS-1148] Resilient member adding in presence of unreachable backends…
Browse files Browse the repository at this point in the history
… (1/2) (#3248)

* Refactoring: use FailedToProcess
* Refactoring: make UnreachableUsers a NonEmpty
As agreed with client devs on Apr 4, 2023 in the Squad - Federation
chat, the absence of the `failed_to_send` field in response to an MLS
message send request has the same meaning as an empty list provided in
the same field.
* executeProposalAction: return failed-to-add users
* MLS test utility: reuse code among utilities
* Move and generalise mockUnreachableFor
* Introduce failed to remove (via failed to fetch client info)
* Propagate FailedToProcess across federation API arising from conversation updates
* Fix/align an MLS integration test
* Use a V4 add members endpoint in tests
* Rethrow the invalid-domain exception
* Rethrow federation-not-available error
* Fix a golden test for LeaveConversationResponse
* Golden tests for MLSMessageSendingStatus
* Fix a test with an unreachable user
* Test: clean up debugging leftovers
* Test utility: fix wording of a haddoc
* Clean up conv action federation failure handling
* Move unreachability stuff into its own module
  • Loading branch information
mdimjasevic authored and supersven committed Jul 5, 2023
1 parent d3dc67a commit 339e39b
Show file tree
Hide file tree
Showing 30 changed files with 677 additions and 294 deletions.
1 change: 1 addition & 0 deletions changelog.d/1-api-changes/mls-conv-add-across-federation
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Report a failure to add remote users to an MLS conversation
1 change: 1 addition & 0 deletions changelog.d/6-federation/failed-to-process
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Several federation Galley endpoints have a breaking change in their response types: "leave-conversation", "update-conversation", "send-mls-message" and "send-mls-commit-bundle".
10 changes: 5 additions & 5 deletions libs/wire-api-federation/src/Wire/API/Federation/API/Galley.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ import Wire.API.Conversation.Typing
import Wire.API.Error.Galley
import Wire.API.Federation.API.Common
import Wire.API.Federation.Endpoint
import Wire.API.MLS.Message
import Wire.API.MLS.SubConversation
import Wire.API.MakesFederatedCall
import Wire.API.Message
import Wire.API.Routes.Public.Galley.Messaging
import Wire.API.Unreachable
import Wire.API.Util.Aeson (CustomEncoded (..))
import Wire.Arbitrary (Arbitrary, GenericUniform (..))

Expand Down Expand Up @@ -365,11 +365,11 @@ newtype MessageSendResponse = MessageSendResponse
)

newtype LeaveConversationResponse = LeaveConversationResponse
{leaveResponse :: Either RemoveFromConversationError ()}
{leaveResponse :: Either RemoveFromConversationError FailedToProcess}
deriving stock (Eq, Show)
deriving
(ToJSON, FromJSON)
via (Either (CustomEncoded RemoveFromConversationError) ())
via (Either (CustomEncoded RemoveFromConversationError) FailedToProcess)

type UserDeletedNotificationMaxConvs = 1000

Expand Down Expand Up @@ -398,7 +398,7 @@ data ConversationUpdateRequest = ConversationUpdateRequest

data ConversationUpdateResponse
= ConversationUpdateResponseError GalleyError
| ConversationUpdateResponseUpdate ConversationUpdate
| ConversationUpdateResponseUpdate (ConversationUpdate, FailedToProcess)
| ConversationUpdateResponseNoChanges
deriving stock (Eq, Show, Generic)
deriving
Expand All @@ -423,7 +423,7 @@ data MLSMessageResponse
= MLSMessageResponseError GalleyError
| MLSMessageResponseProtocolError Text
| MLSMessageResponseProposalFailure Wai.Error
| MLSMessageResponseUpdates [ConversationUpdate] UnreachableUsers
| MLSMessageResponseUpdates [ConversationUpdate] FailedToProcess
deriving stock (Eq, Show, Generic)
deriving (ToJSON, FromJSON) via (CustomEncoded MLSMessageResponse)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ spec =
testObjects
[ (MLSMessageSendingStatus.testObject_MLSMessageSendingStatus1, "testObject_MLSMessageSendingStatus1.json"),
(MLSMessageSendingStatus.testObject_MLSMessageSendingStatus2, "testObject_MLSMessageSendingStatus2.json"),
(MLSMessageSendingStatus.testObject_MLSMessageSendingStatus3, "testObject_MLSMessageSendingStatus3.json")
(MLSMessageSendingStatus.testObject_MLSMessageSendingStatus3, "testObject_MLSMessageSendingStatus3.json"),
(MLSMessageSendingStatus.testObject_MLSMessageSendingStatus4, "testObject_MLSMessageSendingStatus4.json"),
(MLSMessageSendingStatus.testObject_MLSMessageSendingStatus5, "testObject_MLSMessageSendingStatus5.json"),
(MLSMessageSendingStatus.testObject_MLSMessageSendingStatus6, "testObject_MLSMessageSendingStatus6.json")
]
testObjects [(LeaveConversationRequest.testObject_LeaveConversationRequest1, "testObject_LeaveConversationRequest1.json")]
testObjects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import Imports
import Wire.API.Federation.API.Galley

testObject_LeaveConversationResponse1 :: LeaveConversationResponse
testObject_LeaveConversationResponse1 = LeaveConversationResponse $ Right ()
testObject_LeaveConversationResponse1 = LeaveConversationResponse $ Right mempty

testObject_LeaveConversationResponse2 :: LeaveConversationResponse
testObject_LeaveConversationResponse2 = LeaveConversationResponse $ Left RemoveFromConversationErrorRemovalNotAllowed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,40 +24,65 @@ import Data.Qualified
import qualified Data.UUID as UUID
import Imports
import Wire.API.MLS.Message
import Wire.API.Unreachable

testObject_MLSMessageSendingStatus1 :: MLSMessageSendingStatus
testObject_MLSMessageSendingStatus1 =
MLSMessageSendingStatus
{ mmssEvents = [],
mmssTime = toUTCTimeMillis (read "1864-04-12 12:22:43.673 UTC"),
mmssUnreachableUsers = UnreachableUsers []
mmssFailedToProcess = mempty
}

testObject_MLSMessageSendingStatus2 :: MLSMessageSendingStatus
testObject_MLSMessageSendingStatus2 =
MLSMessageSendingStatus
{ mmssEvents = [],
mmssTime = toUTCTimeMillis (read "2001-04-12 12:22:43.673 UTC"),
mmssUnreachableUsers = failed1
mmssFailedToProcess = failedToSend failed1
}

testObject_MLSMessageSendingStatus3 :: MLSMessageSendingStatus
testObject_MLSMessageSendingStatus3 =
MLSMessageSendingStatus
{ mmssEvents = [],
mmssTime = toUTCTimeMillis (read "1999-04-12 12:22:43.673 UTC"),
mmssUnreachableUsers = failed2
mmssFailedToProcess = failedToSend failed2
}

failed1 :: UnreachableUsers
testObject_MLSMessageSendingStatus4 :: MLSMessageSendingStatus
testObject_MLSMessageSendingStatus4 =
MLSMessageSendingStatus
{ mmssEvents = [],
mmssTime = toUTCTimeMillis (read "2023-04-12 12:22:43.673 UTC"),
mmssFailedToProcess = failedToAdd failed1
}

testObject_MLSMessageSendingStatus5 :: MLSMessageSendingStatus
testObject_MLSMessageSendingStatus5 =
MLSMessageSendingStatus
{ mmssEvents = [],
mmssTime = toUTCTimeMillis (read "1901-04-12 12:22:43.673 UTC"),
mmssFailedToProcess = failedToRemove failed2
}

testObject_MLSMessageSendingStatus6 :: MLSMessageSendingStatus
testObject_MLSMessageSendingStatus6 =
MLSMessageSendingStatus
{ mmssEvents = [],
mmssTime = toUTCTimeMillis (read "1905-04-12 12:22:43.673 UTC"),
mmssFailedToProcess = failedToAdd failed1 <> failedToRemove failed2
}

failed1 :: [Qualified UserId]
failed1 =
let domain = Domain "offline.example.com"
in UnreachableUsers [Qualified (Id . fromJust . UUID.fromString $ "00000000-0000-0000-0000-000200000008") domain]
in [Qualified (Id . fromJust . UUID.fromString $ "00000000-0000-0000-0000-000200000008") domain]

failed2 :: UnreachableUsers
failed2 :: [Qualified UserId]
failed2 =
let domain = Domain "golden.example.com"
in UnreachableUsers
[ Qualified (Id . fromJust . UUID.fromString $ "00000000-0000-0000-0000-000200000008") domain,
Qualified (Id . fromJust . UUID.fromString $ "00000000-0000-0000-0000-000100000007") domain
]
in flip Qualified domain . Id . fromJust . UUID.fromString
<$> [ "00000000-0000-0000-0000-000200000008",
"00000000-0000-0000-0000-000100000007"
]
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"Right": []
"Right": {}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"events": [],
"time": "1864-04-12T12:22:43.673Z",
"failed_to_send": []
}
"events": [],
"time": "1864-04-12T12:22:43.673Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"events": [],
"failed_to_add": [
{
"domain": "offline.example.com",
"id": "00000000-0000-0000-0000-000200000008"
}
],
"time": "2023-04-12T12:22:43.673Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"events": [],
"failed_to_remove": [
{
"domain": "golden.example.com",
"id": "00000000-0000-0000-0000-000200000008"
},
{
"domain": "golden.example.com",
"id": "00000000-0000-0000-0000-000100000007"
}
],
"time": "1901-04-12T12:22:43.673Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"events": [],
"failed_to_add": [
{
"domain": "offline.example.com",
"id": "00000000-0000-0000-0000-000200000008"
}
],
"failed_to_remove": [
{
"domain": "golden.example.com",
"id": "00000000-0000-0000-0000-000200000008"
},
{
"domain": "golden.example.com",
"id": "00000000-0000-0000-0000-000100000007"
}
],
"time": "1905-04-12T12:22:43.673Z"
}
24 changes: 3 additions & 21 deletions libs/wire-api/src/Wire/API/MLS/Message.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ module Wire.API.MLS.Message
MLSCipherTextSym0,
MLSMessageSendingStatus (..),
KnownFormatTag (..),
UnreachableUsers (..),
verifyMessageSignature,
mkSignedMessage,
)
Expand All @@ -50,10 +49,8 @@ import Data.Binary
import Data.Binary.Get
import Data.Binary.Put
import qualified Data.ByteArray as BA
import Data.Id
import Data.Json.Util
import Data.Kind
import Data.Qualified
import Data.Schema
import Data.Singletons.TH
import qualified Data.Swagger as S
Expand All @@ -67,6 +64,7 @@ import Wire.API.MLS.Group
import Wire.API.MLS.KeyPackage
import Wire.API.MLS.Proposal
import Wire.API.MLS.Serialisation
import Wire.API.Unreachable
import Wire.Arbitrary (GenericUniform (..))

data WireFormatTag = MLSPlainText | MLSCipherText
Expand Down Expand Up @@ -318,22 +316,10 @@ instance SerialiseMLS (MessagePayload 'MLSPlainText) where
-- so the next case is left as a stub
serialiseMLS _ = pure ()

newtype UnreachableUsers = UnreachableUsers {unreachableUsers :: [Qualified UserId]}
deriving stock (Eq, Show)
deriving (A.ToJSON, A.FromJSON, S.ToSchema) via Schema UnreachableUsers
deriving newtype (Semigroup, Monoid)

instance ToSchema UnreachableUsers where
schema =
named "UnreachableUsers" $
UnreachableUsers
<$> unreachableUsers
.= array schema

data MLSMessageSendingStatus = MLSMessageSendingStatus
{ mmssEvents :: [Event],
mmssTime :: UTCTimeMillis,
mmssUnreachableUsers :: UnreachableUsers
mmssFailedToProcess :: FailedToProcess
}
deriving (Eq, Show)
deriving (A.ToJSON, A.FromJSON, S.ToSchema) via Schema MLSMessageSendingStatus
Expand All @@ -352,11 +338,7 @@ instance ToSchema MLSMessageSendingStatus where
"time"
(description ?~ "The time of sending the message.")
schema
<*> mmssUnreachableUsers
.= fieldWithDocModifier
"failed_to_send"
(description ?~ "List of federated users who could not be reached and did not receive the message")
schema
<*> mmssFailedToProcess .= failedToProcessObjectSchema

verifyMessageSignature :: CipherSuiteTag -> Message 'MLSPlainText -> ByteString -> Bool
verifyMessageSignature cs msg pubkey =
Expand Down
Loading

0 comments on commit 339e39b

Please sign in to comment.