Skip to content

Commit

Permalink
New team feature EnforceFileDownloadLocation.
Browse files Browse the repository at this point in the history
  • Loading branch information
fisx committed Dec 13, 2023
1 parent bdabda4 commit fb7fe8d
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 12 deletions.
9 changes: 7 additions & 2 deletions libs/galley-types/src/Galley/Types/Teams.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ module Galley.Types.Teams
flagMLS,
flagMlsE2EId,
flagMlsMigration,
flagEnforceFileDownloadLocation,
Defaults (..),
ImplicitLockStatus (..),
unImplicitLockStatus,
Expand Down Expand Up @@ -165,7 +166,8 @@ data FeatureFlags = FeatureFlags
_flagMLS :: !(Defaults (WithStatus MLSConfig)),
_flagOutlookCalIntegration :: !(Defaults (WithStatus OutlookCalIntegrationConfig)),
_flagMlsE2EId :: !(Defaults (WithStatus MlsE2EIdConfig)),
_flagMlsMigration :: !(Defaults (WithStatus MlsMigrationConfig))
_flagMlsMigration :: !(Defaults (WithStatus MlsMigrationConfig)),
_flagEnforceFileDownloadLocation :: !(Defaults (WithStatus EnforceFileDownloadLocationConfig))
}
deriving (Eq, Show, Generic)

Expand Down Expand Up @@ -218,6 +220,7 @@ instance FromJSON FeatureFlags where
<*> (fromMaybe (Defaults (defFeatureStatus @OutlookCalIntegrationConfig)) <$> (obj .:? "outlookCalIntegration"))
<*> (fromMaybe (Defaults (defFeatureStatus @MlsE2EIdConfig)) <$> (obj .:? "mlsE2EId"))
<*> (fromMaybe (Defaults (defFeatureStatus @MlsMigrationConfig)) <$> (obj .:? "mlsMigration"))
<*> (fromMaybe (Defaults (defFeatureStatus @EnforceFileDownloadLocationConfig)) <$> (obj .:? "enforceFileDownloadLocation"))
where
withImplicitLockStatusOrDefault :: forall cfg. (IsFeatureConfig cfg, Schema.ToSchema cfg) => Object -> Key -> A.Parser (Defaults (ImplicitLockStatus cfg))
withImplicitLockStatusOrDefault obj fieldName = fromMaybe (Defaults (ImplicitLockStatus (defFeatureStatus @cfg))) <$> obj .:? fieldName
Expand All @@ -241,6 +244,7 @@ instance ToJSON FeatureFlags where
outlookCalIntegration
mlsE2EId
mlsMigration
enforceFileDownloadLocation
) =
object
[ "sso" .= sso,
Expand All @@ -258,7 +262,8 @@ instance ToJSON FeatureFlags where
"mls" .= mls,
"outlookCalIntegration" .= outlookCalIntegration,
"mlsE2EId" .= mlsE2EId,
"mlsMigration" .= mlsMigration
"mlsMigration" .= mlsMigration,
"enforceFileDownloadLocation" .= enforceFileDownloadLocation
]

instance FromJSON FeatureSSO where
Expand Down
1 change: 1 addition & 0 deletions libs/galley-types/test/unit/Test/Galley/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ instance Arbitrary FeatureFlags where
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
where
unlocked :: ImplicitLockStatus a -> ImplicitLockStatus a
unlocked = ImplicitLockStatus . Public.setLockStatus Public.LockStatusUnlocked . _unImplicitLockStatus
5 changes: 5 additions & 0 deletions libs/wire-api/src/Wire/API/Routes/Internal/Galley.hs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ type IFeatureAPI =
:<|> IFeatureStatusPut '[] '() MlsMigrationConfig
:<|> IFeatureStatusPatch '[] '() MlsMigrationConfig
:<|> IFeatureStatusLockStatusPut MlsMigrationConfig
-- EnforceFileDownloadLocationConfig
:<|> IFeatureStatusGet EnforceFileDownloadLocationConfig
:<|> IFeatureStatusPut '[] '() EnforceFileDownloadLocationConfig
:<|> IFeatureStatusPatch '[] '() EnforceFileDownloadLocationConfig
:<|> IFeatureStatusLockStatusPut EnforceFileDownloadLocationConfig
-- all feature configs
:<|> Named
"feature-configs-internal"
Expand Down
2 changes: 2 additions & 0 deletions libs/wire-api/src/Wire/API/Routes/Public/Galley/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ type FeatureAPI =
:<|> From 'V5 ::> FeatureStatusPut '[] '() MlsE2EIdConfig
:<|> From 'V5 ::> FeatureStatusGet MlsMigrationConfig
:<|> From 'V5 ::> FeatureStatusPut '[] '() MlsMigrationConfig
:<|> From 'V5 ::> FeatureStatusGet EnforceFileDownloadLocationConfig
:<|> From 'V5 ::> FeatureStatusPut '[] '() EnforceFileDownloadLocationConfig
:<|> AllFeatureConfigsUserGet
:<|> AllFeatureConfigsTeamGet
:<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" LegalholdConfig
Expand Down
48 changes: 41 additions & 7 deletions libs/wire-api/src/Wire/API/Team/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ module Wire.API.Team.Feature
OutlookCalIntegrationConfig (..),
MlsE2EIdConfig (..),
MlsMigrationConfig (..),
EnforceFileDownloadLocationConfig (..),
AllFeatureConfigs (..),
unImplicitLockStatus,
ImplicitLockStatus (..),
Expand Down Expand Up @@ -112,6 +113,7 @@ import Deriving.Aeson
import GHC.TypeLits
import Imports
import Servant (FromHttpApiData (..), ToHttpApiData (..))
import Test.QuickCheck (getPrintableString)
import Test.QuickCheck.Arbitrary (arbitrary)
import Test.QuickCheck.Gen (suchThat)
import Wire.API.Conversation.Protocol
Expand All @@ -128,11 +130,11 @@ import Wire.Arbitrary (Arbitrary, GenericUniform (..))
-- **<NameOfFeature>Config**. If your feature doesn't have a config besides
-- being enabled/disabled, locked/unlocked, then the config should be a unit
-- type, e.g. **data MyFeatureConfig = MyFeatureConfig**. Add a singleton for
-- the new data type. Implement type classes 'ToSchema', 'IsFeatureConfig' and
-- 'Arbitrary'. If your feature doesn't have a config implement
-- 'FeatureTrivialConfig'.
-- the new data type. Implement type classes 'RenderableSymbol', 'ToSchema',
-- 'IsFeatureConfig' and 'Arbitrary'. If your feature doesn't have a config
-- implement 'FeatureTrivialConfig'.
--
-- 2. Add the config to to 'AllFeatureConfigs'.
-- 2. Add the config to 'AllFeatureConfigs'.
--
-- 3. If your feature is configurable on a per-team basis, add a schema
-- migration in galley and extend 'getFeatureStatus' and similar functions in
Expand All @@ -147,7 +149,7 @@ import Wire.Arbitrary (Arbitrary, GenericUniform (..))
-- and setting (with side-effects). Note that we don't have to check the
-- lockstatus inside 'setConfigForTeam' because the lockstatus is checked in
-- 'setFeatureStatus' before which is the public API for setting the feature
-- status. Also extend FeaturePersistentAllFeatures.
-- status.
--
-- 6. Add public routes to Wire.API.Routes.Public.Galley.Feature:
-- 'FeatureStatusGet', 'FeatureStatusPut' (optional). Then implement them in
Expand All @@ -172,7 +174,9 @@ import Wire.Arbitrary (Arbitrary, GenericUniform (..))
-- - add the defaults to 'charts/galley/values.yaml'
-- - optionally add config for CI to 'hack/helm_vars/wire-server/values.yaml'
--
-- 12. Add a section to the documentation at an appropriate place (e.g. 'docs/src/developer/reference/config-options.md' or 'docs/src/understand/team-feature-settings.md')
-- 12. Add a section to the documentation at an appropriate place
-- (e.g. 'docs/src/developer/reference/config-options.md' or
-- 'docs/src/understand/team-feature-settings.md')
class IsFeatureConfig cfg where
type FeatureSymbol cfg :: Symbol
defFeatureStatus :: WithStatus cfg
Expand Down Expand Up @@ -203,6 +207,7 @@ data FeatureSingleton cfg where
FeatureSingletonOutlookCalIntegrationConfig :: FeatureSingleton OutlookCalIntegrationConfig
FeatureSingletonMlsE2EIdConfig :: FeatureSingleton MlsE2EIdConfig
FeatureSingletonMlsMigration :: FeatureSingleton MlsMigrationConfig
FeatureSingletonEnforceFileDownloadLocation :: FeatureSingleton EnforceFileDownloadLocationConfig

class FeatureTrivialConfig cfg where
trivialConfig :: cfg
Expand Down Expand Up @@ -1084,6 +1089,32 @@ instance IsFeatureConfig MlsMigrationConfig where
featureSingleton = FeatureSingletonMlsMigration
objectSchema = field "config" schema

----------------------------------------------------------------------
-- EnforceFileDownloadLocationConfig

data EnforceFileDownloadLocationConfig = EnforceFileDownloadLocationConfig
{ enforcedDownloadLocation :: Text
}
deriving stock (Eq, Show, Generic)

instance RenderableSymbol EnforceFileDownloadLocationConfig where
renderSymbol = "EnforceFileDownloadLocationConfig"

instance Arbitrary EnforceFileDownloadLocationConfig where
arbitrary = EnforceFileDownloadLocationConfig . cs . getPrintableString <$> arbitrary

instance ToSchema EnforceFileDownloadLocationConfig where
schema =
object "EnforceFileDownloadLocation" $
EnforceFileDownloadLocationConfig
<$> enforcedDownloadLocation .= field "enforcedDownloadLocation" schema

instance IsFeatureConfig EnforceFileDownloadLocationConfig where
type FeatureSymbol EnforceFileDownloadLocationConfig = "enforceFileDownloadLocation"
defFeatureStatus = withStatus FeatureStatusDisabled LockStatusLocked (EnforceFileDownloadLocationConfig "") FeatureTTLUnlimited
featureSingleton = FeatureSingletonEnforceFileDownloadLocation
objectSchema = field "config" schema

----------------------------------------------------------------------
-- FeatureStatus

Expand Down Expand Up @@ -1161,7 +1192,8 @@ data AllFeatureConfigs = AllFeatureConfigs
afcExposeInvitationURLsToTeamAdmin :: WithStatus ExposeInvitationURLsToTeamAdminConfig,
afcOutlookCalIntegration :: WithStatus OutlookCalIntegrationConfig,
afcMlsE2EId :: WithStatus MlsE2EIdConfig,
afcMlsMigration :: WithStatus MlsMigrationConfig
afcMlsMigration :: WithStatus MlsMigrationConfig,
afcEnforceFileDownloadLocation :: WithStatus EnforceFileDownloadLocationConfig
}
deriving stock (Eq, Show)
deriving (FromJSON, ToJSON, S.ToSchema) via (Schema AllFeatureConfigs)
Expand All @@ -1188,6 +1220,7 @@ instance ToSchema AllFeatureConfigs where
<*> afcOutlookCalIntegration .= featureField
<*> afcMlsE2EId .= featureField
<*> afcMlsMigration .= featureField
<*> afcEnforceFileDownloadLocation .= featureField
where
featureField ::
forall cfg.
Expand Down Expand Up @@ -1216,5 +1249,6 @@ instance Arbitrary AllFeatureConfigs where
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary

makeLenses ''ImplicitLockStatus
1 change: 1 addition & 0 deletions services/galley/galley.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ library
Galley.Schema.V87_TeamFeatureSupportedProtocols
Galley.Schema.V88_RemoveMemberClientAndTruncateMLSGroupMemberClient
Galley.Schema.V89_MlsLockStatus
Galley.Schema.V90_EnforceFileDownloadLocationConfig
Galley.Types.Clients
Galley.Types.ToUserRole
Galley.Types.UserList
Expand Down
4 changes: 4 additions & 0 deletions services/galley/src/Galley/API/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ featureAPI =
<@> mkNamedAPI @'("iput", MlsMigrationConfig) setFeatureStatusInternal
<@> mkNamedAPI @'("ipatch", MlsMigrationConfig) patchFeatureStatusInternal
<@> mkNamedAPI @'("ilock", MlsMigrationConfig) (updateLockStatus @MlsMigrationConfig)
<@> mkNamedAPI @'("iget", EnforceFileDownloadLocationConfig) (getFeatureStatus DontDoAuth)
<@> mkNamedAPI @'("iput", EnforceFileDownloadLocationConfig) setFeatureStatusInternal
<@> mkNamedAPI @'("ipatch", EnforceFileDownloadLocationConfig) patchFeatureStatusInternal
<@> mkNamedAPI @'("ilock", EnforceFileDownloadLocationConfig) (updateLockStatus @EnforceFileDownloadLocationConfig)
<@> mkNamedAPI @"feature-configs-internal" (maybe getAllFeatureConfigsForServer getAllFeatureConfigsForUser)

waiInternalSitemap :: Routes a (Sem GalleyEffects) ()
Expand Down
2 changes: 2 additions & 0 deletions services/galley/src/Galley/API/Public/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ featureAPI =
<@> mkNamedAPI @'("put", MlsE2EIdConfig) (setFeatureStatus . DoAuth)
<@> mkNamedAPI @'("get", MlsMigrationConfig) (getFeatureStatus . DoAuth)
<@> mkNamedAPI @'("put", MlsMigrationConfig) (setFeatureStatus . DoAuth)
<@> mkNamedAPI @'("get", EnforceFileDownloadLocationConfig) (getFeatureStatus . DoAuth)
<@> mkNamedAPI @'("put", EnforceFileDownloadLocationConfig) (setFeatureStatus . DoAuth)
<@> mkNamedAPI @"get-all-feature-configs-for-user" getAllFeatureConfigsForUser
<@> mkNamedAPI @"get-all-feature-configs-for-team" getAllFeatureConfigsForTeam
<@> mkNamedAPI @'("get-config", LegalholdConfig) getFeatureStatusForUser
Expand Down
2 changes: 2 additions & 0 deletions services/galley/src/Galley/API/Teams/Features.hs
Original file line number Diff line number Diff line change
Expand Up @@ -393,3 +393,5 @@ instance SetFeatureConfig MlsMigrationConfig where
)
$ throw MLSProtocolMismatch
persistAndPushEvent tid wsnl

instance SetFeatureConfig EnforceFileDownloadLocationConfig
13 changes: 11 additions & 2 deletions services/galley/src/Galley/API/Teams/Features/Get.hs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ getAllFeatureConfigsForServer =
<*> getConfigForServer @OutlookCalIntegrationConfig
<*> getConfigForServer @MlsE2EIdConfig
<*> getConfigForServer @MlsMigrationConfig
<*> getConfigForServer @EnforceFileDownloadLocationConfig

getAllFeatureConfigsUser ::
forall r.
Expand Down Expand Up @@ -272,6 +273,7 @@ getAllFeatureConfigsUser uid =
<*> getConfigForUser @OutlookCalIntegrationConfig uid
<*> getConfigForUser @MlsE2EIdConfig uid
<*> getConfigForUser @MlsMigrationConfig uid
<*> getConfigForUser @EnforceFileDownloadLocationConfig uid

getAllFeatureConfigsTeam ::
forall r.
Expand Down Expand Up @@ -302,6 +304,7 @@ getAllFeatureConfigsTeam tid =
<*> getConfigForTeam @OutlookCalIntegrationConfig tid
<*> getConfigForTeam @MlsE2EIdConfig tid
<*> getConfigForTeam @MlsMigrationConfig tid
<*> getConfigForTeam @EnforceFileDownloadLocationConfig tid

-- | Note: this is an internal function which doesn't cover all features, e.g. LegalholdConfig
genericGetConfigForTeam ::
Expand Down Expand Up @@ -490,8 +493,14 @@ instance GetFeatureConfig MlsMigrationConfig where
getConfigForServer =
input <&> view (settings . featureFlags . flagMlsMigration . unDefaults)

-- -- | If second factor auth is enabled, make sure that end-points that don't support it, but should, are blocked completely. (This is a workaround until we have 2FA for those end-points as well.)
-- --
instance GetFeatureConfig EnforceFileDownloadLocationConfig where
getConfigForServer =
input <&> view (settings . featureFlags . flagEnforceFileDownloadLocation . unDefaults)

-- | If second factor auth is enabled, make sure that end-points that don't support it, but
-- should, are blocked completely. (This is a workaround until we have 2FA for those
-- end-points as well.)
--
-- This function exists to resolve a cyclic dependency.
guardSecondFactorDisabled ::
forall r a.
Expand Down
13 changes: 13 additions & 0 deletions services/galley/src/Galley/Cassandra/TeamFeatures.hs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ getFeatureConfig FeatureSingletonMlsMigration tid = do
select = "select mls_migration_status, mls_migration_start_time, mls_migration_finalise_regardless_after from team_features where team_id = ?"
getFeatureConfig FeatureSingletonExposeInvitationURLsToTeamAdminConfig tid = getTrivialConfigC "expose_invitation_urls_to_team_admin" tid
getFeatureConfig FeatureSingletonOutlookCalIntegrationConfig tid = getTrivialConfigC "outlook_cal_integration_status" tid
getFeatureConfig FeatureSingletonEnforceFileDownloadLocation tid = do
let q = query1 select (params LocalQuorum (Identity tid))
retry x1 q <&> \case
Nothing -> Nothing
Just (Nothing, _) -> Nothing
Just (Just fs, mbLocation) ->
Just $ WithStatusNoLock fs (EnforceFileDownloadLocationConfig $ fromMaybe "" mbLocation) FeatureTTLUnlimited
where
select :: PrepQuery R (Identity TeamId) (Maybe FeatureStatus, Maybe Text)
select = "select enforce_file_download_location_status, enforce_file_download_location from team_features where team_id = ?"

setFeatureConfig :: MonadClient m => FeatureSingleton cfg -> TeamId -> WithStatusNoLock cfg -> m ()
setFeatureConfig FeatureSingletonLegalholdConfig tid statusNoLock = setFeatureStatusC "legalhold_status" tid (wssStatus statusNoLock)
Expand Down Expand Up @@ -246,6 +256,7 @@ setFeatureConfig FeatureSingletonMlsMigration tid status = do
"insert into team_features (team_id, mls_migration_status, mls_migration_start_time, mls_migration_finalise_regardless_after) values (?, ?, ?, ?)"
setFeatureConfig FeatureSingletonExposeInvitationURLsToTeamAdminConfig tid statusNoLock = setFeatureStatusC "expose_invitation_urls_to_team_admin" tid (wssStatus statusNoLock)
setFeatureConfig FeatureSingletonOutlookCalIntegrationConfig tid statusNoLock = setFeatureStatusC "outlook_cal_integration_status" tid (wssStatus statusNoLock)
setFeatureConfig FeatureSingletonEnforceFileDownloadLocation tid statusNoLock = undefined

getFeatureLockStatus :: MonadClient m => FeatureSingleton cfg -> TeamId -> m (Maybe LockStatus)
getFeatureLockStatus FeatureSingletonFileSharingConfig tid = getLockStatusC "file_sharing_lock_status" tid
Expand All @@ -256,6 +267,7 @@ getFeatureLockStatus FeatureSingletonMlsE2EIdConfig tid = getLockStatusC "mls_e2
getFeatureLockStatus FeatureSingletonMlsMigration tid = getLockStatusC "mls_migration_lock_status" tid
getFeatureLockStatus FeatureSingletonOutlookCalIntegrationConfig tid = getLockStatusC "outlook_cal_integration_lock_status" tid
getFeatureLockStatus FeatureSingletonMLSConfig tid = getLockStatusC "mls_lock_status" tid
getFeatureLockStatus FeatureSingletonEnforceFileDownloadLocation tid = undefined
getFeatureLockStatus _ _ = pure Nothing

setFeatureLockStatus :: MonadClient m => FeatureSingleton cfg -> TeamId -> LockStatus -> m ()
Expand All @@ -267,6 +279,7 @@ setFeatureLockStatus FeatureSingletonMlsE2EIdConfig tid status = setLockStatusC
setFeatureLockStatus FeatureSingletonMlsMigration tid status = setLockStatusC "mls_migration_lock_status" tid status
setFeatureLockStatus FeatureSingletonOutlookCalIntegrationConfig tid status = setLockStatusC "outlook_cal_integration_lock_status" tid status
setFeatureLockStatus FeatureSingletonMLSConfig tid status = setLockStatusC "mls_lock_status" tid status
setFeatureLockStatus FeatureSingletonEnforceFileDownloadLocation tid status = undefined
setFeatureLockStatus _ _tid _status = pure ()

getTrivialConfigC ::
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2023 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 Galley.Schema.V90_EnforceFileDownloadLocationConfig
( migration,
)
where

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

migration :: Migration
migration =
Migration 90 "Add fields for EnforceFileDownloadLocationConfig" $
schema'
[r| ALTER TABLE team_features ADD (
enforce_file_download_location_lock_status int,
enforce_file_download_location_status int,
enforce_file_download_location text
)
|]
11 changes: 10 additions & 1 deletion services/galley/test/integration/API/Teams/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,8 @@ testAllFeatures = do
afcExposeInvitationURLsToTeamAdmin = withStatus FeatureStatusDisabled LockStatusLocked ExposeInvitationURLsToTeamAdminConfig FeatureTTLUnlimited,
afcOutlookCalIntegration = withStatus FeatureStatusDisabled LockStatusLocked OutlookCalIntegrationConfig FeatureTTLUnlimited,
afcMlsE2EId = withStatus FeatureStatusDisabled LockStatusUnlocked (wsConfig defFeatureStatus) FeatureTTLUnlimited,
afcMlsMigration = defaultMlsMigrationConfig
afcMlsMigration = defaultMlsMigrationConfig,
afcEnforceFileDownloadLocation = defaultEnforceFileDownloadLocationConfig
}

testFeatureConfigConsistency :: TestM ()
Expand Down Expand Up @@ -1534,3 +1535,11 @@ defaultMlsMigrationConfig =
finaliseRegardlessAfter = fmap fromUTCTimeMillis (readUTCTimeMillis "2029-10-17T00:00:00.000Z")
}
FeatureTTLUnlimited

defaultEnforceFileDownloadLocationConfig :: WithStatus EnforceFileDownloadLocationConfig
defaultEnforceFileDownloadLocationConfig =
withStatus
FeatureStatusDisabled
LockStatusLocked
(EnforceFileDownloadLocationConfig "*")
FeatureTTLUnlimited

0 comments on commit fb7fe8d

Please sign in to comment.