From 646cedeea63b3722d6490c4612e9af663155126f Mon Sep 17 00:00:00 2001 From: Philipp Kolberg Date: Thu, 14 Dec 2023 17:30:47 +0100 Subject: [PATCH] Move feature flag parsing to util --- src/api/core/mod.rs | 16 ++++------------ src/config.rs | 18 +++++++++--------- src/util.rs | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs index 1dc8e59a..f415aade 100644 --- a/src/api/core/mod.rs +++ b/src/api/core/mod.rs @@ -47,15 +47,14 @@ pub fn events_routes() -> Vec { // // Move this somewhere else // -use rocket::{serde::json::Json, Catcher, Route}; -use serde_json::Value; +use rocket::{serde::json::Json, serde::json::Value, Catcher, Route}; use crate::{ api::{JsonResult, JsonUpcase, Notify, UpdateType}, auth::Headers, db::DbConn, error::Error, - util::get_reqwest_client, + util::{get_reqwest_client, parse_feature_flags}, }; #[derive(Serialize, Deserialize, Debug)] @@ -193,9 +192,7 @@ fn version() -> Json<&'static str> { #[get("/config")] fn config() -> Json { let domain = crate::CONFIG.domain(); - 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 feature_states = parse_feature_flags(&crate::CONFIG.feature_flags()); 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 @@ -218,12 +215,7 @@ fn config() -> Json { }, "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; + config["featureStates"] = serde_json::to_value(feature_states).unwrap(); Json(config) } diff --git a/src/config.rs b/src/config.rs index 67587156..231ef334 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,7 +9,7 @@ use reqwest::Url; use crate::{ db::DbConnType, error::Error, - util::{get_env, get_env_bool}, + util::{get_env, get_env_bool, parse_feature_flags}, }; static CONFIG_FILE: Lazy = Lazy::new(|| { @@ -547,8 +547,10 @@ 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(); + /// Customize the enabled feature flags on the clients |> This is a comma separated list of feature flags to en-/disable. + /// Features are enabled by default which can be overridden by prefixing the feature with a `!`. + /// Autofill v2 is disabled by default because it is causing issues https://github.com/dani-garcia/vaultwarden/discussions/4052 + feature_flags: String, false, def, "!autofill-v2,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. @@ -754,9 +756,7 @@ 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![ + const SUPPORTED_FLAGS: &[&str] = &[ "display-kdf-iteration-warning", "fido2-vault-credentials", "trusted-device-encryption", @@ -769,9 +769,9 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { "flexible-collections-v-1", "bulk-collection-access", ]; - for feature in features { - if !supported_flags.contains(&feature) { - err!(format!("Feature flag {feature:?} is not supported.")); + for flag in parse_feature_flags(&cfg.feature_flags).keys() { + if !SUPPORTED_FLAGS.contains(&flag.as_str()) { + err!(format!("Feature flag {flag:?} is not supported.")); } } diff --git a/src/util.rs b/src/util.rs index 9b43116f..dda1d5f0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,6 +2,7 @@ // Web Headers and caching // use std::{ + collections::HashMap, io::{Cursor, ErrorKind}, ops::Deref, }; @@ -747,3 +748,18 @@ pub fn convert_json_key_lcase_first(src_json: Value) -> Value { value => value, } } + +/// Parses the feature flags string into a HashMap. +pub fn parse_feature_flags(feature_flags: &str) -> HashMap { + let feature_flags_lowercase = feature_flags.to_lowercase(); + let features = feature_flags_lowercase.split(',').map(|f| f.trim()).collect::>(); + let mut feature_states: HashMap = HashMap::new(); + + for feature in features { + let is_enabled = !feature.starts_with('!'); + let flag = if is_enabled { feature } else { &feature[1..] }; + feature_states.insert(flag.to_string(), is_enabled); + } + + feature_states +} \ No newline at end of file