Skip to content

Commit

Permalink
New team feature EnforceFileDownloadLocation (#3779)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisx authored Jan 4, 2024
1 parent 9b40c03 commit dbcda21
Show file tree
Hide file tree
Showing 20 changed files with 224 additions and 30 deletions.
3 changes: 3 additions & 0 deletions cassandra-schema.cql
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,9 @@ CREATE TABLE galley_test.team_features (
app_lock_status int,
conference_calling int,
digital_signatures int,
enforce_file_download_location text,
enforce_file_download_location_lock_status int,
enforce_file_download_location_status int,
expose_invitation_urls_to_team_admin int,
file_sharing int,
file_sharing_lock_status int,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add custom feature flag; only supported for some on-prem installations; locked & disabled by default
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
22 changes: 18 additions & 4 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
:<|> IFeatureStatusGetWithDesc EnforceFileDownloadLocationConfig "<p><b>Custom feature: only supported for some decidated on-prem systems.</b></p>"
:<|> IFeatureStatusPutWithDesc '[] '() EnforceFileDownloadLocationConfig "<p><b>Custom feature: only supported for some decidated on-prem systems.</b></p>"
:<|> IFeatureStatusPatchWithDesc '[] '() EnforceFileDownloadLocationConfig "<p><b>Custom feature: only supported for some decidated on-prem systems.</b></p>"
:<|> IFeatureStatusLockStatusPutWithDesc EnforceFileDownloadLocationConfig "<p><b>Custom feature: only supported for some decidated on-prem systems.</b></p>"
-- all feature configs
:<|> Named
"feature-configs-internal"
Expand Down Expand Up @@ -372,11 +377,17 @@ type ITeamsAPIBase =
)
)

type IFeatureStatusGet f = Named '("iget", f) (FeatureStatusBaseGet f)
type IFeatureStatusGet f = IFeatureStatusGetWithDesc f ""

type IFeatureStatusPut calls errs f = Named '("iput", f) (ApplyMods calls (FeatureStatusBasePutInternal errs f))
type IFeatureStatusGetWithDesc f desc = Named '("iget", f) (Description desc :> FeatureStatusBaseGet f)

type IFeatureStatusPatch calls errs f = Named '("ipatch", f) (ApplyMods calls (FeatureStatusBasePatchInternal errs f))
type IFeatureStatusPut calls errs f = IFeatureStatusPutWithDesc calls errs f ""

type IFeatureStatusPutWithDesc calls errs f desc = Named '("iput", f) (ApplyMods calls (Description desc :> FeatureStatusBasePutInternal errs f))

type IFeatureStatusPatch calls errs f = IFeatureStatusPatchWithDesc calls errs f ""

type IFeatureStatusPatchWithDesc calls errs f desc = Named '("ipatch", f) (ApplyMods calls (Description desc :> FeatureStatusBasePatchInternal errs f))

type FeatureStatusBasePutInternal errs featureConfig =
FeatureStatusBaseInternal
Expand Down Expand Up @@ -409,10 +420,13 @@ type FeatureStatusBaseInternal desc errs featureConfig a =
:> FeatureSymbol featureConfig
:> a

type IFeatureStatusLockStatusPut featureName =
type IFeatureStatusLockStatusPut featureName = IFeatureStatusLockStatusPutWithDesc featureName ""

type IFeatureStatusLockStatusPutWithDesc featureName desc =
Named
'("ilock", featureName)
( Summary (AppendSymbol "(Un-)lock " (FeatureSymbol featureName))
:> Description desc
:> CanThrow 'NotATeamMember
:> CanThrow 'TeamNotFound
:> "teams"
Expand Down
26 changes: 22 additions & 4 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,16 @@ type FeatureAPI =
:<|> From 'V5 ::> FeatureStatusPut '[] '() MlsE2EIdConfig
:<|> From 'V5 ::> FeatureStatusGet MlsMigrationConfig
:<|> From 'V5 ::> FeatureStatusPut '[] '() MlsMigrationConfig
:<|> From 'V5
::> FeatureStatusGetWithDesc
EnforceFileDownloadLocationConfig
"<p><b>Custom feature: only supported for some decidated on-prem systems.</b></p>"
:<|> From 'V5
::> FeatureStatusPutWithDesc
'[]
'()
EnforceFileDownloadLocationConfig
"<p><b>Custom feature: only supported for some decidated on-prem systems.</b></p>"
:<|> 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 All @@ -107,15 +117,23 @@ type FeatureAPI =
:<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" SndFactorPasswordChallengeConfig
:<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is used by team management, webapp, and potentially the old Android client as of June 2022" MLSConfig

type FeatureStatusGet f =
type FeatureStatusGet f = FeatureStatusGetWithDesc f ""

type FeatureStatusGetWithDesc f desc =
Named
'("get", f)
(ZUser :> FeatureStatusBaseGet f)
( Description desc
:> (ZUser :> FeatureStatusBaseGet f)
)

type FeatureStatusPut segs errs f =
type FeatureStatusPut segs errs f = FeatureStatusPutWithDesc segs errs f ""

type FeatureStatusPutWithDesc segs errs f desc =
Named
'("put", f)
(ApplyMods segs (ZUser :> FeatureStatusBasePutPublic errs f))
( Description desc
:> (ApplyMods segs (ZUser :> FeatureStatusBasePutPublic errs f))
)

type FeatureStatusDeprecatedGet d f =
Named
Expand Down
57 changes: 47 additions & 10 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 @@ -164,15 +166,17 @@ import Wire.Arbitrary (Arbitrary, GenericUniform (..))
-- (https://github.com/wireapp/wire-server/pull/1811,
-- https://github.com/wireapp/wire-server/pull/1818)
--
-- 10. Extend the integration tests with cases
-- 10. Extend the integration tests with cases.
--
-- 11. Edit/update the configurations:
-- 11. If applicable, edit/update the configurations:
-- - optionally add the config for local integration tests to 'galley.integration.yaml'
-- - add a config mapping to 'charts/galley/templates/configmap.yaml'
-- - 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' (if applicable) or
-- 'docs/src/understand/team-feature-settings.md')
class IsFeatureConfig cfg where
type FeatureSymbol cfg :: Symbol
defFeatureStatus :: WithStatus cfg
Expand Down Expand Up @@ -202,7 +206,11 @@ data FeatureSingleton cfg where
FeatureSingletonExposeInvitationURLsToTeamAdminConfig :: FeatureSingleton ExposeInvitationURLsToTeamAdminConfig
FeatureSingletonOutlookCalIntegrationConfig :: FeatureSingleton OutlookCalIntegrationConfig
FeatureSingletonMlsE2EIdConfig :: FeatureSingleton MlsE2EIdConfig
FeatureSingletonMlsMigration :: FeatureSingleton MlsMigrationConfig
FeatureSingletonMlsMigration ::
-- FUTUREWORK: rename to `FeatureSingletonMlsMigrationConfig` (or drop the `Config` from
-- all other constructors)
FeatureSingleton MlsMigrationConfig
FeatureSingletonEnforceFileDownloadLocationConfig :: FeatureSingleton EnforceFileDownloadLocationConfig

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

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

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

instance RenderableSymbol EnforceFileDownloadLocationConfig where
renderSymbol = "EnforceFileDownloadLocationConfig"

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

instance ToSchema EnforceFileDownloadLocationConfig where
schema =
object "EnforceFileDownloadLocation" $
EnforceFileDownloadLocationConfig
<$> enforcedDownloadLocation .= maybe_ (optField "enforcedDownloadLocation" schema)

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

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

Expand Down Expand Up @@ -1161,7 +1195,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 +1223,7 @@ instance ToSchema AllFeatureConfigs where
<*> afcOutlookCalIntegration .= featureField
<*> afcMlsE2EId .= featureField
<*> afcMlsMigration .= featureField
<*> afcEnforceFileDownloadLocation .= featureField
where
featureField ::
forall cfg.
Expand Down Expand Up @@ -1216,5 +1252,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
Loading

0 comments on commit dbcda21

Please sign in to comment.