Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
99d0ba9
Delete stale FUTUREWORK
akshaymankar Oct 7, 2021
1d129cd
Brig: delete deprecated 'GET /i/users/connections-status` endpoint
akshaymankar Oct 7, 2021
6432287
brig: Servantify POST /i/users/connection-status
akshaymankar Oct 12, 2021
6a1c713
brig: Add internal endpoint to get qualified connection statuses
akshaymankar Oct 12, 2021
df7a864
Brig: Support creating accepted connections for tests
akshaymankar Oct 12, 2021
579f9e9
wire-api: roundtrip test for To/FromByteString @Relation
akshaymankar Oct 12, 2021
07c67ad
Check conn between adder and remotes when adding remotes to conv
akshaymankar Oct 12, 2021
b796074
Check connection between conversation creator and remote members
akshaymankar Oct 12, 2021
f55cee2
Add TODOs for federation endpoints checking conns
akshaymankar Oct 12, 2021
711780e
Do connection checking in onConversationCreated in the federation API
Oct 12, 2021
a8e1dd9
WIP: Fixing tests that fail
Oct 12, 2021
d7f04b6
Make existing federation tests succeed again by sprinkling some conne…
jschaul Oct 12, 2021
6617f1a
Add a (still failing) test for on-conversation-crated
jschaul Oct 12, 2021
05e7f34
Add more connections to pass federation API tests
akshaymankar Oct 13, 2021
201990e
Add TODO
akshaymankar Oct 13, 2021
5dcc1a8
onConvCreated: Ensure creator of conv is included as other member
akshaymankar Oct 13, 2021
d99d51d
More coverage for onConvCreated
akshaymankar Oct 13, 2021
a2fbfc7
onConvUpdated: Only allow connected users to add local users
akshaymankar Oct 13, 2021
4f620be
Add test case: Only unconnected users to add
smatting Oct 13, 2021
2cc38fe
Add changelog entry for feature
smatting Oct 13, 2021
b924da9
Fix integration tests
smatting Oct 13, 2021
b2e0900
Turn TODOs into FUTUREWORKs
pcapriotti Oct 14, 2021
2e1b6fc
Hi CI
pcapriotti Oct 14, 2021
ad6f732
Use for instead of pattern matching
pcapriotti Oct 15, 2021
4245888
Expand CHANGELOG entry
pcapriotti Oct 15, 2021
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/5-internal/delete-internal-get-conn-status
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Brig: Delete deprecated `GET /i/users/connections-status` endpoint.
1 change: 1 addition & 0 deletions changelog.d/6-federation/check-connections
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Check connections when adding remote users to a local conversation and local users to remote conversations.
1 change: 1 addition & 0 deletions changelog.d/6-federation/fix-remote-conv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The creator of a conversation now appears as a member when the conversation is fetched from a remote backend
24 changes: 3 additions & 21 deletions libs/brig-types/src/Brig/Types/Connection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
module Brig.Types.Connection
( module C,
UserIds (..),
ConnectionsStatusRequest (..),
UpdateConnectionsInternal (..),

-- * re-exports
Expand All @@ -40,6 +39,7 @@ where
import Brig.Types.Common as C
import Data.Aeson
import Data.Id (UserId)
import Data.Qualified
import Imports
import Wire.API.Arbitrary
import Wire.API.Connection
Expand All @@ -51,13 +51,6 @@ data UserIds = UserIds
{cUsers :: [UserId]}
deriving (Eq, Show, Generic)

-- | Data that is passed to the @\/i\/users\/connections-status@ endpoint.
data ConnectionsStatusRequest = ConnectionsStatusRequest
{ csrFrom :: ![UserId],
csrTo :: !(Maybe [UserId])
}
deriving (Eq, Show, Generic)

-- FUTUREWORK: This needs to get Qualified IDs when implementing
-- Legalhold + Federation, as it's used in the internal
-- putConnectionInternal / galley->Brig "/i/users/connections-status"
Expand All @@ -67,6 +60,8 @@ data ConnectionsStatusRequest = ConnectionsStatusRequest
data UpdateConnectionsInternal
= BlockForMissingLHConsent UserId [UserId]
| RemoveLHBlocksInvolving UserId
| -- | This must only be used by tests
CreateConnectionForTest UserId (Qualified UserId)
deriving (Eq, Show, Generic)
deriving (Arbitrary) via (GenericUniform UpdateConnectionsInternal)

Expand All @@ -86,16 +81,3 @@ instance ToJSON UserIds where
toJSON (UserIds us) =
object
["ids" .= us]

instance FromJSON ConnectionsStatusRequest where
parseJSON = withObject "ConnectionsStatusRequest" $ \o -> do
csrFrom <- o .: "from"
csrTo <- o .: "to"
pure ConnectionsStatusRequest {..}

instance ToJSON ConnectionsStatusRequest where
toJSON ConnectionsStatusRequest {csrFrom, csrTo} =
object
[ "from" .= csrFrom,
"to" .= csrTo
]
26 changes: 0 additions & 26 deletions libs/brig-types/src/Brig/Types/Intra.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}

-- This file is part of the Wire Server implementation.
Expand All @@ -24,7 +23,6 @@ module Brig.Types.Intra
( AccountStatus (..),
AccountStatusUpdate (..),
AccountStatusResp (..),
ConnectionStatus (..),
UserAccount (..),
NewUserScimInvitation (..),
UserSet (..),
Expand Down Expand Up @@ -91,30 +89,6 @@ instance FromJSON AccountStatusUpdate where
instance ToJSON AccountStatusUpdate where
toJSON s = object ["status" .= suStatus s]

-------------------------------------------------------------------------------
-- ConnectionStatus

data ConnectionStatus = ConnectionStatus
{ csFrom :: !UserId,
csTo :: !UserId,
csStatus :: !Relation
}
deriving (Eq, Show, Generic)

instance FromJSON ConnectionStatus where
parseJSON = withObject "connection-status" $ \o ->
ConnectionStatus <$> o .: "from"
<*> o .: "to"
<*> o .: "status"

instance ToJSON ConnectionStatus where
toJSON cs =
object
[ "from" .= csFrom cs,
"to" .= csTo cs,
"status" .= csStatus cs
]

-------------------------------------------------------------------------------
-- UserAccount

Expand Down
6 changes: 6 additions & 0 deletions libs/types-common/src/Data/Qualified.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ module Data.Qualified
foldQualified,
partitionQualified,
indexQualified,
bucketQualified,
indexRemote,
deprecatedSchema,
)
Expand Down Expand Up @@ -131,6 +132,11 @@ indexQualified = foldr add mempty
add :: Qualified a -> Map Domain [a] -> Map Domain [a]
add (Qualified x domain) = Map.insertWith (<>) domain [x]

-- | Bucket a list of qualified values by domain.
bucketQualified :: Foldable f => f (Qualified a) -> [Qualified [a]]
bucketQualified = map (\(d, a) -> Qualified a d) . Map.assocs . indexQualified

-- FUTUREWORK: Rename this to 'bucketRemote'
indexRemote :: (Functor f, Foldable f) => f (Remote a) -> [Remote [a]]
indexRemote =
map (uncurry toRemoteUnsafe)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,11 @@ newtype GetConversationsResponse = GetConversationsResponse
data NewRemoteConversation conv = NewRemoteConversation
{ -- | The time when the conversation was created
rcTime :: UTCTime,
-- | The user that created the conversation
-- | The user that created the conversation.
--
-- FUTUREWORK: Make this unqualified and assume that this user has the same domain
-- as the backend invoking this RPC. Otehrwise a third party can figure out
-- connections.
rcOrigUserId :: Qualified UserId,
-- | The conversation ID, local to the backend invoking the RPC
rcCnvId :: conv,
Expand Down
37 changes: 19 additions & 18 deletions libs/wire-api/src/Wire/API/Connection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,16 @@ where
import Control.Applicative (optional)
import Control.Lens ((?~))
import Data.Aeson as Aeson
import Data.Attoparsec.ByteString (takeByteString)
import Data.ByteString.Conversion
import Data.Id
import Data.Json.Util (UTCTimeMillis)
import Data.Qualified (Qualified (qUnqualified), deprecatedSchema)
import Data.Range
import qualified Data.Schema as P
import Data.Swagger as S
import qualified Data.Swagger.Build.Api as Doc
import Data.Swagger.Schema as S
import Data.Text as Text
import Imports
import Servant.API
import Wire.API.Arbitrary (Arbitrary (..), GenericUniform (..))
import Wire.API.Routes.MultiTablePaging

Expand Down Expand Up @@ -173,6 +172,9 @@ data Relation
deriving (Arbitrary) via (GenericUniform Relation)
deriving (FromJSON, ToJSON, S.ToSchema) via (P.Schema Relation)

instance S.ToParamSchema Relation where
toParamSchema _ = mempty & S.type_ ?~ S.SwaggerString

-- | 'updateConnectionInternal', requires knowledge of the previous state (before
-- 'MissingLegalholdConsent'), but the clients don't need that information. To avoid having
-- to change the API, we introduce an internal variant of 'Relation' with surjective mapping
Expand Down Expand Up @@ -245,20 +247,19 @@ instance P.ToSchema Relation where
P.element "missing-legalhold-consent" MissingLegalholdConsent
]

instance FromByteString Relation where
parser =
takeByteString >>= \case
"accepted" -> return Accepted
"blocked" -> return Blocked
"pending" -> return Pending
"ignored" -> return Ignored
"sent" -> return Sent
"cancelled" -> return Cancelled
"missing-legalhold-consent" -> return MissingLegalholdConsent
x -> fail $ "Invalid relation-type " <> show x

instance ToByteString Relation where
builder = \case
instance FromHttpApiData Relation where
parseQueryParam = \case
"accepted" -> return Accepted
"blocked" -> return Blocked
"pending" -> return Pending
"ignored" -> return Ignored
"sent" -> return Sent
"cancelled" -> return Cancelled
"missing-legalhold-consent" -> return MissingLegalholdConsent
x -> Left $ "Invalid relation-type " <> x

instance ToHttpApiData Relation where
toQueryParam = \case
Accepted -> "accepted"
Blocked -> "blocked"
Pending -> "pending"
Expand All @@ -267,7 +268,7 @@ instance ToByteString Relation where
Cancelled -> "cancelled"
MissingLegalholdConsent -> "missing-legalhold-consent"

--------------------------------------------------------------------------------
----------------
-- Requests

-- | Payload type for a connection request from one user to another.
Expand Down
26 changes: 26 additions & 0 deletions libs/wire-api/src/Wire/API/Routes/Internal/Brig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import qualified Servant
import Servant.Swagger (HasSwagger (toSwagger))
import Servant.Swagger.Internal.Orphans ()
import Servant.Swagger.UI
import Wire.API.Connection
import Wire.API.Routes.Internal.Brig.Connection
import Wire.API.Routes.Internal.Brig.EJPD
import qualified Wire.API.Team.Feature as ApiFt

Expand Down Expand Up @@ -85,12 +87,36 @@ type DeleteAccountFeatureConfig =
:> "conferenceCalling"
:> Delete '[Servant.JSON] NoContent

type GetAllConnectionsUnqualified =
Summary "Get all connections of a given user"
:> "users"
:> "connections-status"
:> ReqBody '[Servant.JSON] ConnectionsStatusRequest
:> QueryParam'
[ Optional,
Strict,
Description "Only returns connections with the given relation, if omitted, returns all connections"
]
"filter"
Relation
:> Post '[Servant.JSON] [ConnectionStatus]

type GetAllConnections =
Summary "Get all connections of a given user"
:> "users"
:> "connections-status"
:> "v2"
:> ReqBody '[Servant.JSON] ConnectionsStatusRequestV2
:> Post '[Servant.JSON] [ConnectionStatusV2]

type API =
"i"
:> ( EJPDRequest
:<|> GetAccountFeatureConfig
:<|> PutAccountFeatureConfig
:<|> DeleteAccountFeatureConfig
:<|> GetAllConnectionsUnqualified
:<|> GetAllConnections
)

type SwaggerDocsAPI = "api" :> "internal" :> SwaggerSchemaUI "swagger-ui" "swagger.json"
Expand Down
73 changes: 73 additions & 0 deletions libs/wire-api/src/Wire/API/Routes/Internal/Brig/Connection.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{-# LANGUAGE RecordWildCards #-}

module Wire.API.Routes.Internal.Brig.Connection where

import Data.Aeson (FromJSON, ToJSON)
import Data.Id
import Data.Qualified
import Data.Schema
import qualified Data.Swagger as S
import Imports
import Wire.API.Connection

data ConnectionsStatusRequest = ConnectionsStatusRequest
{ csrFrom :: ![UserId],
csrTo :: !(Maybe [UserId])
}
deriving (Eq, Show, Generic)
deriving (ToJSON, FromJSON, S.ToSchema) via (Schema ConnectionsStatusRequest)

instance ToSchema ConnectionsStatusRequest where
schema =
object "ConnectionsStatusRequest" $
ConnectionsStatusRequest
<$> csrFrom .= field "from" (array schema)
<*> csrTo .= optField "to" Nothing (array schema)

data ConnectionsStatusRequestV2 = ConnectionsStatusRequestV2
{ csrv2From :: ![UserId],
csrv2To :: !(Maybe [Qualified UserId]),
csrv2Relation :: !(Maybe Relation)
}
deriving (Eq, Show, Generic)
deriving (ToJSON, FromJSON, S.ToSchema) via (Schema ConnectionsStatusRequestV2)

instance ToSchema ConnectionsStatusRequestV2 where
schema =
object "ConnectionsStatusRequestV2" $
ConnectionsStatusRequestV2
<$> csrv2From .= field "from" (array schema)
<*> csrv2To .= optField "to" Nothing (array schema)
<*> csrv2Relation .= optField "relation" Nothing schema

data ConnectionStatus = ConnectionStatus
{ csFrom :: !UserId,
csTo :: !UserId,
csStatus :: !Relation
}
deriving (Eq, Show, Generic)
deriving (ToJSON, FromJSON, S.ToSchema) via (Schema ConnectionStatus)

instance ToSchema ConnectionStatus where
schema =
object "ConnectionStatus" $
ConnectionStatus
<$> csFrom .= field "from" schema
<*> csTo .= field "to" schema
<*> csStatus .= field "status" schema

data ConnectionStatusV2 = ConnectionStatusV2
{ csv2From :: !UserId,
csv2To :: !(Qualified UserId),
csv2Status :: !Relation
}
deriving (Eq, Show, Generic)
deriving (ToJSON, FromJSON, S.ToSchema) via (Schema ConnectionStatusV2)

instance ToSchema ConnectionStatusV2 where
schema =
object "ConnectionStatusV2" $
ConnectionStatusV2
<$> csv2From .= field "from" schema
<*> csv2To .= field "qualified_to" schema
<*> csv2Status .= field "status" schema
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import qualified Wire.API.Arbitrary as Arbitrary ()
import qualified Wire.API.Asset.V3 as Asset.V3
import qualified Wire.API.Asset.V3.Resumable as Asset.V3.Resumable
import qualified Wire.API.Call.Config as Call.Config
import qualified Wire.API.Connection as Connection
import qualified Wire.API.Conversation.Code as Conversation.Code
import qualified Wire.API.Conversation.Role as Conversation.Role
import qualified Wire.API.Properties as Properties
Expand Down Expand Up @@ -58,7 +57,6 @@ tests =
testRoundTrip @Call.Config.Transport,
testRoundTrip @Call.Config.TurnHost,
testRoundTrip @Call.Config.TurnURI,
testRoundTrip @Connection.Relation,
testRoundTrip @Conversation.Code.Key,
testRoundTrip @Conversation.Code.Value,
testRoundTrip @Conversation.Role.RoleName,
Expand Down
3 changes: 2 additions & 1 deletion libs/wire-api/wire-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ cabal-version: 1.12
--
-- see: https://github.com/sol/hpack
--
-- hash: d2c9713a3cbd002394d82471bd12407b388620823e1087fb4dd300cbecde7c25
-- hash: 2d17ec32d1990b4f59c918291cd7a1286d20e5c54ad921ecd5eb9d01b4b9f1c8

name: wire-api
version: 0.1.0
Expand Down Expand Up @@ -50,6 +50,7 @@ library
Wire.API.Push.Token
Wire.API.Push.V2.Token
Wire.API.Routes.Internal.Brig
Wire.API.Routes.Internal.Brig.Connection
Wire.API.Routes.Internal.Brig.EJPD
Wire.API.Routes.MultiTablePaging
Wire.API.Routes.MultiTablePaging.State
Expand Down
Loading