Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
68 changes: 43 additions & 25 deletions cassandra-schema.cql
Original file line number Diff line number Diff line change
Expand Up @@ -1290,31 +1290,6 @@ CREATE TABLE brig_test.service_team (
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';

CREATE TABLE brig_test.invitation (
inviter uuid,
id uuid,
code ascii,
created_at timestamp,
email text,
name text,
phone text,
PRIMARY KEY (inviter, id)
) WITH CLUSTERING ORDER BY (id ASC)
AND bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND dclocal_read_repair_chance = 0.1
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';

CREATE TABLE brig_test.blacklist (
key text PRIMARY KEY
) WITH bloom_filter_fp_chance = 0.1
Expand Down Expand Up @@ -1665,6 +1640,49 @@ CREATE TABLE brig_test.password_reset (
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';

CREATE TABLE brig_test.federation_remotes (
domain text PRIMARY KEY,
search_policy int
) WITH bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND dclocal_read_repair_chance = 0.1
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';

CREATE TABLE brig_test.invitation (
inviter uuid,
id uuid,
code ascii,
created_at timestamp,
email text,
name text,
phone text,
PRIMARY KEY (inviter, id)
) WITH CLUSTERING ORDER BY (id ASC)
AND bloom_filter_fp_chance = 0.01
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
AND comment = ''
AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND crc_check_chance = 1.0
AND dclocal_read_repair_chance = 0.1
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = '99PERCENTILE';

CREATE TABLE brig_test.activation_keys (
key ascii PRIMARY KEY,
challenge ascii,
Expand Down
55 changes: 55 additions & 0 deletions libs/wire-api/src/Wire/API/Routes/FederationDomainConfig.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module Wire.API.Routes.FederationDomainConfig
( FederationDomainConfig (..),
FederationDomainConfigs (..),
)
where

import Data.Aeson (FromJSON, ToJSON)
import Data.Domain (Domain)
import Data.Schema
import qualified Data.Swagger as S
import GHC.Generics
import Imports
import Wire.API.User.Search (FederatedUserSearchPolicy)

data FederationDomainConfig = FederationDomainConfig
{ domain :: Domain,
cfgSearchPolicy :: FederatedUserSearchPolicy
}
deriving (Eq, Ord, Show, Generic)
deriving (ToJSON, FromJSON, S.ToSchema) via Schema FederationDomainConfig

instance ToSchema FederationDomainConfig where
schema =
object "FederationDomainConfig" $
FederationDomainConfig
<$> domain .= field "domain" schema
<*> cfgSearchPolicy .= field "search_policy" schema

newtype FederationDomainConfigs = FederationDomainConfigs
{fromFederationDomainConfigs :: [FederationDomainConfig]}
deriving (Show, Generic)
deriving (ToJSON, FromJSON, S.ToSchema) via Schema FederationDomainConfigs

instance ToSchema FederationDomainConfigs where
schema =
object "FederationDomainConfigs" $
FederationDomainConfigs
<$> fromFederationDomainConfigs .= field "remotes" (array schema)
29 changes: 29 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 @@ -23,6 +23,7 @@ module Wire.API.Routes.Internal.Brig
TeamsAPI,
UserAPI,
AuthAPI,
FederationRemotesAPI,
EJPDRequest,
GetAccountConferenceCallingConfig,
PutAccountConferenceCallingConfig,
Expand All @@ -38,6 +39,7 @@ where
import Control.Lens ((.~))
import Data.Aeson (FromJSON, ToJSON)
import qualified Data.Code as Code
import Data.Domain (Domain)
import Data.Id as Id
import Data.Qualified (Qualified)
import Data.Schema hiding (swaggerDoc)
Expand All @@ -53,6 +55,7 @@ import Wire.API.Error.Brig
import Wire.API.MLS.Credential
import Wire.API.MLS.KeyPackage
import Wire.API.MakesFederatedCall
import Wire.API.Routes.FederationDomainConfig
import Wire.API.Routes.Internal.Brig.Connection
import Wire.API.Routes.Internal.Brig.EJPD
import Wire.API.Routes.Internal.Brig.OAuth (OAuthAPI)
Expand Down Expand Up @@ -327,6 +330,7 @@ type API =
:<|> UserAPI
:<|> AuthAPI
:<|> OAuthAPI
:<|> FederationRemotesAPI
)

type TeamsAPI =
Expand Down Expand Up @@ -397,6 +401,31 @@ type AuthAPI =
:> MultiVerb1 'GET '[JSON] (RespondEmpty 200 "OK")
)

-- | This is located in brig, not in federator, because brig has a cassandra instance. This
-- is not ideal, but since all services have a local in-ram copy of this table and keep track
-- of changes via rabbitmq, we argue it's "fine" for federators to ask brig once on startup.
type FederationRemotesAPI =
Named
"get-federation-remotes"
( "federation"
:> "remotes"
:> Get '[JSON] FederationDomainConfigs
)
:<|> Named
"add-federation-remotes"
( "federation"
:> "remotes"
:> ReqBody '[JSON] FederationDomainConfig
:> Post '[JSON] ()
)
:<|> Named
"delete-federation-remotes"
( "federation"
:> "remotes"
:> Capture "domain" Domain
:> Delete '[JSON] ()
)

swaggerDoc :: Swagger
swaggerDoc =
toSwagger (Proxy @API)
Expand Down
2 changes: 1 addition & 1 deletion libs/wire-api/src/Wire/API/User/Search.hs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ data FederatedUserSearchPolicy
= NoSearch
| ExactHandleSearch
| FullSearch
deriving (Show, Eq, Generic, Enum, Bounded)
deriving (Show, Eq, Ord, Generic, Enum, Bounded)
deriving (Arbitrary) via (GenericUniform FederatedUserSearchPolicy)
deriving (ToJSON, FromJSON) via (Schema FederatedUserSearchPolicy)

Expand Down
1 change: 1 addition & 0 deletions libs/wire-api/wire-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ library
Wire.API.Routes.ClientAlgebra
Wire.API.Routes.Cookies
Wire.API.Routes.CSV
Wire.API.Routes.FederationDomainConfig
Wire.API.Routes.Internal.Brig
Wire.API.Routes.Internal.Brig.Connection
Wire.API.Routes.Internal.Brig.EJPD
Expand Down
2 changes: 2 additions & 0 deletions services/brig/brig.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ library
Brig.Data.Activation
Brig.Data.Client
Brig.Data.Connection
Brig.Data.Federation
Brig.Data.Instances
Brig.Data.LoginCode
Brig.Data.MLS.KeyPackage
Expand Down Expand Up @@ -668,6 +669,7 @@ executable brig-schema
V73_ReplaceNonceTable
V74_AddOAuthTables
V75_AddOAuthCodeChallenge
V76_FederationRemotes
V_FUTUREWORK

hs-source-dirs: schema/src
Expand Down
4 changes: 3 additions & 1 deletion services/brig/schema/src/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import qualified V72_AddNonceTable
import qualified V73_ReplaceNonceTable
import qualified V74_AddOAuthTables
import qualified V75_AddOAuthCodeChallenge
import qualified V76_FederationRemotes

main :: IO ()
main = do
Expand Down Expand Up @@ -97,7 +98,8 @@ main = do
V72_AddNonceTable.migration,
V73_ReplaceNonceTable.migration,
V74_AddOAuthTables.migration,
V75_AddOAuthCodeChallenge.migration
V75_AddOAuthCodeChallenge.migration,
V76_FederationRemotes.migration
-- When adding migrations here, don't forget to update
-- 'schemaVersion' in Brig.App

Expand Down
37 changes: 37 additions & 0 deletions services/brig/schema/src/V76_FederationRemotes.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{-# LANGUAGE QuasiQuotes #-}

-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module V76_FederationRemotes
( migration,
)
where

import Cassandra.Schema
import Imports
import Text.RawString.QQ

migration :: Migration
migration =
Migration 76 "Table for keeping track of instances we federate with" $
schema'
[r| CREATE TABLE federation_remotes (
domain text PRIMARY KEY,
search_policy int
)
|]
9 changes: 9 additions & 0 deletions services/brig/src/Brig/API/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import qualified Brig.Code as Code
import Brig.Data.Activation
import qualified Brig.Data.Client as Data
import qualified Brig.Data.Connection as Data
import qualified Brig.Data.Federation as Data
import qualified Brig.Data.MLS.KeyPackage as Data
import qualified Brig.Data.User as Data
import Brig.Effects.BlacklistPhonePrefixStore (BlacklistPhonePrefixStore)
Expand Down Expand Up @@ -89,6 +90,7 @@ import Wire.API.Federation.API
import Wire.API.MLS.Credential
import Wire.API.MLS.KeyPackage
import Wire.API.MLS.Serialisation
import Wire.API.Routes.FederationDomainConfig
import Wire.API.Routes.Internal.Brig
import qualified Wire.API.Routes.Internal.Brig as BrigIRoutes
import Wire.API.Routes.Internal.Brig.Connection
Expand Down Expand Up @@ -119,6 +121,7 @@ servantSitemap =
:<|> userAPI
:<|> authAPI
:<|> internalOauthAPI
:<|> federationRemotesAPI

ejpdAPI ::
Member GalleyProvider r =>
Expand Down Expand Up @@ -171,6 +174,12 @@ authAPI =
:<|> Named @"login-code" getLoginCode
:<|> Named @"reauthenticate" reauthenticate

federationRemotesAPI :: ServerT BrigIRoutes.FederationRemotesAPI (Handler r)
federationRemotesAPI =
Named @"get-federation-remotes" (lift $ FederationDomainConfigs <$> wrapClient Data.getFederationRemotes) -- TODO: get this from TVar! also merge in config file!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't see the code for this, but perhaps this would require a full-table scan, which Cassandra doesn't like. If we have to list all the domain, perhaps we should store them differently.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

full table table scan is bad even if the table is <100 entries? then i'm not sure what the alternative is...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be done, but needs some clever, not obvious things like this: https://nblair.github.io/2017/02/16/cassandra-full-table-scan/

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative is to store the list in 1 row with id = 1. I think we already do this somewhere.
Then have a separate table to remember all the configuration for each endpoint. This also has the benefit of not forgetting preferences for a remote even if you stop federating with them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use RabbitMQ with mqtt, we can use retain flags to hold onto the last value sent for domain updates. When the clients connect, they will receive this message and can immediately update themselves to the latest state.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://nblair.github.io/2017/02/16/cassandra-full-table-scan/ says it's fine to pull 10k rows in one query. so wouldn't c553c0e be a good solution?

:<|> Named @"add-federation-remotes" (lift . wrapClient . Data.addFederationRemote)
:<|> Named @"delete-federation-remotes" (lift . wrapClient . Data.deleteFederationRemote)

-- | Responds with 'Nothing' if field is NULL in existing user or user does not exist.
getAccountConferenceCallingConfig :: UserId -> (Handler r) (ApiFt.WithStatusNoLock ApiFt.ConferenceCallingConfig)
getAccountConferenceCallingConfig uid =
Expand Down
8 changes: 4 additions & 4 deletions services/brig/src/Brig/API/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ import Brig.API.Types
import Brig.App
import qualified Brig.Code as Code
import qualified Brig.Data.User as Data
import Brig.Options (FederationDomainConfig, federationDomainConfigs, set2FACodeGenerationDelaySecs)
import qualified Brig.Options as Opts
import Brig.Options (federationDomainConfigs, set2FACodeGenerationDelaySecs)
import Brig.Types.Intra (accountUser)
import Control.Lens (view)
import Control.Monad.Catch (throwM)
Expand All @@ -65,6 +64,7 @@ import Util.Logging (sha256String)
import Wire.API.Error
import Wire.API.Error.Brig
import Wire.API.Federation.Error
import Wire.API.Routes.FederationDomainConfig as FD
import Wire.API.User
import Wire.API.User.Search (FederatedUserSearchPolicy (NoSearch))
import qualified Wire.Sem.Concurrency as C
Expand Down Expand Up @@ -171,11 +171,11 @@ exceptTToMaybe = (pure . either Just (const Nothing)) <=< runExceptT
lookupDomainConfig :: MonadReader Env m => Domain -> m (Maybe FederationDomainConfig)
lookupDomainConfig domain = do
domainConfigs <- fromMaybe [] <$> view (settings . federationDomainConfigs)
pure $ find ((== domain) . Opts.domain) domainConfigs
pure $ find ((== domain) . FD.domain) domainConfigs

-- | If domain is not configured fall back to `FullSearch`
lookupSearchPolicy :: MonadReader Env m => Domain -> m FederatedUserSearchPolicy
lookupSearchPolicy domain = fromMaybe NoSearch <$> (Opts.cfgSearchPolicy <$$> lookupDomainConfig domain)
lookupSearchPolicy domain = fromMaybe NoSearch <$> (FD.cfgSearchPolicy <$$> lookupDomainConfig domain)

-- | Convert a qualified value into a local one. Throw if the value is not actually local.
ensureLocal :: Qualified a -> AppT r (Local a)
Expand Down
2 changes: 1 addition & 1 deletion services/brig/src/Brig/App.hs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ import Wire.API.User.Identity (Email)
import Wire.API.User.Profile (Locale)

schemaVersion :: Int32
schemaVersion = 75
schemaVersion = 76

-------------------------------------------------------------------------------
-- Environment
Expand Down
Loading