diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs index 509af35f..1dc8e59a 100644 --- a/src/api/core/mod.rs +++ b/src/api/core/mod.rs @@ -193,7 +193,10 @@ fn version() -> Json<&'static str> { #[get("/config")] fn config() -> Json { let domain = crate::CONFIG.domain(); - Json(json!({ + let feature_flags = crate::CONFIG.feature_flags().to_lowercase(); + let features = feature_flags.split(',').map(|f| f.trim()).collect::>(); + let mut feature_states = json!({}); + let mut config = json!({ // Note: The clients use this version to handle backwards compatibility concerns // This means they expect a version that closely matches the Bitwarden server version // We should make sure that we keep this updated when we support the new server features @@ -213,15 +216,15 @@ fn config() -> Json { "notifications": format!("{domain}/notifications"), "sso": "", }, - "featureStates": { - // Any feature flags that we want the clients to use - // Can check the enabled ones at: - // https://vault.bitwarden.com/api/config - "fido2-vault-credentials": true, // Passkey support - "autofill-v2": false, // Disabled because it is causing issues https://github.com/dani-garcia/vaultwarden/discussions/4052 - }, "object": "config", - })) + }); + // Disabled because it is causing issues https://github.com/dani-garcia/vaultwarden/discussions/4052 + feature_states["autofill-v2"] = serde_json::Value::Bool(false); + for feature in features { + feature_states[feature.to_string()] = serde_json::Value::Bool(true); + } + config["featureStates"] = feature_states; + Json(config) } pub fn catchers() -> Vec { diff --git a/src/config.rs b/src/config.rs index 041e89a7..67587156 100644 --- a/src/config.rs +++ b/src/config.rs @@ -547,6 +547,9 @@ make_config! { /// TOTP codes of the previous and next 30 seconds will be invalid. authenticator_disable_time_drift: bool, true, def, false; + /// Customize the enabled feature flags on the clients |> This is a comma separated list of feature flags to enable. + feature_flags: String, false, def, "fido2-vault-credentials".to_string(); + /// Require new device emails |> When a user logs in an email is required to be sent. /// If sending the email fails the login attempt will fail. require_device_email: bool, true, def, false; @@ -751,6 +754,27 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { ) } + let feature_flags = cfg.feature_flags.to_lowercase(); + let features = feature_flags.split(',').map(|f| f.trim()).collect::>(); + let supported_flags = vec![ + "display-kdf-iteration-warning", + "fido2-vault-credentials", + "trusted-device-encryption", + "passwordless-login", + "autofill-v2", + "autofill-overlay", + "browser-fileless-import", + "item-share", + "flexible-collections", + "flexible-collections-v-1", + "bulk-collection-access", + ]; + for feature in features { + if !supported_flags.contains(&feature) { + err!(format!("Feature flag {feature:?} is not supported.")); + } + } + if cfg._enable_duo && (cfg.duo_host.is_some() || cfg.duo_ikey.is_some() || cfg.duo_skey.is_some()) && !(cfg.duo_host.is_some() && cfg.duo_ikey.is_some() && cfg.duo_skey.is_some())