diff --git a/src/config.rs b/src/config.rs index 8072bb1f..77e2d441 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,17 +2,18 @@ use std::process::exit; use std::sync::RwLock; use crate::error::Error; +use crate::util::get_env; lazy_static! { pub static ref CONFIG: Config = Config::load().unwrap_or_else(|e| { println!("Error loading config:\n\t{:?}\n", e); exit(12) }); - pub static ref CONFIG_PATH: String = "data/config.json".into(); + pub static ref CONFIG_FILE: String = get_env("CONFIG_FILE").unwrap_or("data/config.json".into()); } macro_rules! make_config { - ( $( $name:ident : $ty:ty, $editable:literal, $none_action:ident $(, $default:expr)? );+ $(;)? ) => { + ( $( $(#[doc = $doc:literal])+ $name:ident : $ty:ty, $editable:literal, $none_action:ident $(, $default:expr)? );+ $(;)? ) => { pub struct Config { inner: RwLock } @@ -35,7 +36,6 @@ macro_rules! make_config { impl ConfigBuilder { fn from_env() -> Self { dotenv::dotenv().ok(); - use crate::util::get_env; let mut builder = ConfigBuilder::default(); $( @@ -100,11 +100,9 @@ macro_rules! make_config { )+ pub fn load() -> Result { - // TODO: Get config.json from CONFIG_PATH env var or -c console option - // Loading from env and file let _env = ConfigBuilder::from_env(); - let _usr = ConfigBuilder::from_file(&CONFIG_PATH).unwrap_or_default(); + let _usr = ConfigBuilder::from_file(&CONFIG_FILE).unwrap_or_default(); // Create merged config, config file overwrites env let builder = _env.merge(&_usr); @@ -138,12 +136,22 @@ macro_rules! make_config { } } + fn _get_doc(doc: &str) -> serde_json::Value { + let mut split = doc.split("|>").map(str::trim); + json!({ + "group": split.next(), + "name": split.next(), + "description": split.next() + }) + } + json!([ $( { "editable": $editable, "name": stringify!($name), "value": cfg.$name, "default": make_config!{ @default &cfg, $none_action, $($default)? }, "type": _get_form_type(stringify!($ty)), + "doc": _get_doc(concat!($($doc),+)), }, )+ ]) } } @@ -176,57 +184,96 @@ macro_rules! make_config { } -//STRUCTURE: name: type, is_editable, none_action, +//STRUCTURE: +// /// Group |> Friendly Name |> Description (Optional) +// name: type, is_editable, none_action, +// // Where none_action applied when the value wasn't provided and can be: // def: Use a default value // auto: Value is auto generated based on other values // option: Value is optional make_config! { + /// folders |> Data folder |> Main data folder data_folder: String, false, def, "data".to_string(); + /// folders |> Database URL database_url: String, false, auto, |c| format!("{}/{}", c.data_folder, "db.sqlite3"); + /// folders |> Icon chache folder icon_cache_folder: String, false, auto, |c| format!("{}/{}", c.data_folder, "icon_cache"); + /// folders |> Attachments folder attachments_folder: String, false, auto, |c| format!("{}/{}", c.data_folder, "attachments"); + /// folders |> Templates folder templates_folder: String, false, auto, |c| format!("{}/{}", c.data_folder, "templates"); + /// folders |> Session JWT key rsa_key_filename: String, false, auto, |c| format!("{}/{}", c.data_folder, "rsa_key"); + /// ws |> Enable websocket notifications websocket_enabled: bool, false, def, false; + /// ws |> Websocket address websocket_address: String, false, def, "0.0.0.0".to_string(); + /// ws |> Websocket port websocket_port: u16, false, def, 3012; + /// folders |> Web vault folder web_vault_folder: String, false, def, "web-vault/".to_string(); - web_vault_enabled: bool, true, def, true; + /// settings |> Enable web vault + web_vault_enabled: bool, false, def, true; + /// icons |> Positive icon cache expiry |> Number of seconds to consider that an already cached icon is fresh. After this period, the icon will be redownloaded icon_cache_ttl: u64, true, def, 2_592_000; + /// icons |> Negative icon cache expiry |> Number of seconds before trying to download an icon that failed again. icon_cache_negttl: u64, true, def, 259_200; + /// settings |> Disable icon downloads |> Set to true to disable icon downloading, this would still serve icons from $ICON_CACHE_FOLDER, + /// but it won't produce any external network request. Needs to set $ICON_CACHE_TTL to 0, + /// otherwise it will delete them and they won't be downloaded again. disable_icon_download: bool, true, def, false; + /// settings |> Allow new signups |> Controls if new users can register. Note that while this is disabled, users could still be invited signups_allowed: bool, true, def, true; + /// settings |> Allow invitations |> Controls whether users can be invited by organization admins, even when signups are disabled invitations_allowed: bool, true, def, true; + /// settings |> Password iterations |> Number of server-side passwords hashing iterations. The changes only apply when a user changes their password. Not recommended to lower the value password_iterations: i32, true, def, 100_000; + /// settings |> Show password hints |> Controls if the password hint should be shown directly in the web page. Otherwise, if email is disabled, there is no way to see the password hint show_password_hint: bool, true, def, true; + /// settings |> Domain URL |> This needs to be set to the URL used to access the server, including 'http[s]://' and port, if it's different than the default. Some server functions don't work correctly without this value domain: String, true, def, "http://localhost".to_string(); + /// private |> Domain set domain_set: bool, false, def, false; + /// settings |> Reload templates (Dev) |> When this is set to true, the templates get reloaded with every request. ONLY use this during development, as it can slow down the server reload_templates: bool, true, def, false; + /// log |> Enable extended logging extended_logging: bool, false, def, true; + /// log |> Log file path log_file: String, false, option; + /// settings |> Admin page token |> The token used to authenticate in this very same page. Changing it here won't deauthorize the current session admin_token: String, true, option; + /// yubico |> Yubico Client ID yubico_client_id: String, true, option; + /// yubico |> Yubico secret Key yubico_secret_key: String, true, option; + /// yubico |> Yubico Server yubico_server: String, true, option; - // Mail settings + // TODO: Remove SMTP from name once groups work + /// mail |> SMTP Host smtp_host: String, true, option; + /// mail |> Enable SMTP SSL smtp_ssl: bool, true, def, true; + /// mail |> SMTP Port smtp_port: u16, true, auto, |c| if c.smtp_ssl {587} else {25}; + /// mail |> SMTP From Address smtp_from: String, true, def, String::new(); + /// mail |> SMTP From Name smtp_from_name: String, true, def, "Bitwarden_RS".to_string(); + /// mail |> SMTP Username smtp_username: String, true, option; + /// mail |> SMTP Password smtp_password: String, true, option; } @@ -270,7 +317,7 @@ impl Config { //Save to file use std::{fs::File, io::Write}; - let mut file = File::create(&*CONFIG_PATH)?; + let mut file = File::create(&*CONFIG_FILE)?; file.write_all(config_str.as_bytes())?; Ok(()) diff --git a/src/static/templates/admin/page.hbs b/src/static/templates/admin/page.hbs index 9101e7b3..8a041b97 100644 --- a/src/static/templates/admin/page.hbs +++ b/src/static/templates/admin/page.hbs @@ -60,17 +60,17 @@
{{#each config}} {{#if editable}} -
+
{{#case type "text" "number"}} - -
+ +
{{/case}} {{#case type "checkbox"}} -
{{name}}
-
+
{{doc.name}}
+