1
0
Fork 0
mirror of https://github.com/dani-garcia/vaultwarden.git synced 2025-05-23 20:13:59 +00:00

Config can now be serialized / deserialized

This commit is contained in:
Daniel García 2019-02-02 01:09:21 +01:00
parent 20d8d800f3
commit 86ed75bf7c
No known key found for this signature in database
GPG key ID: FC8A7D14C3CD543A
8 changed files with 207 additions and 261 deletions

View file

@ -3,77 +3,149 @@ use std::sync::RwLock;
use handlebars::Handlebars;
use crate::error::Error;
use crate::util::IntoResult;
lazy_static! {
pub static ref CONFIG: Config = Config::load();
pub static ref CONFIG: Config = Config::load().unwrap_or_else(|e| {
println!("Error loading config:\n\t{:?}\n", e);
exit(12)
});
}
macro_rules! make_config {
( $( $name:ident: $ty:ty ),+ $(,)* ) => {
( $( $name:ident : $ty:ty $(, $default_fn:expr)? );+ $(;)* ) => {
pub struct Config { inner: RwLock<_Config> }
pub struct Config { inner: RwLock<Inner> }
#[derive(Default)]
struct _Config {
_templates: Handlebars,
$(pub $name: $ty),+
struct Inner {
templates: Handlebars,
config: _Config,
}
#[derive(Debug, Default, Serialize, Deserialize)]
struct _Config { $(pub $name: $ty),+ }
paste::item! {
#[allow(unused)]
impl Config {
#[allow(unused)]
impl Config {
$(
pub fn $name(&self) -> $ty {
self.inner.read().unwrap().config.$name.clone()
}
pub fn [<set_ $name>](&self, value: $ty) {
self.inner.write().unwrap().config.$name = value;
}
)+
pub fn load() -> Result<Self, Error> {
use crate::util::get_env;
dotenv::dotenv().ok();
let mut config = _Config::default();
$(
pub fn $name(&self) -> $ty {
self.inner.read().unwrap().$name.clone()
}
pub fn [<set_ $name>](&self, value: $ty) {
self.inner.write().unwrap().$name = value;
}
config.$name = make_config!{ @expr &stringify!($name).to_uppercase(), $ty, &config, $($default_fn)? };
)+
Ok(Config {
inner: RwLock::new(Inner {
templates: load_templates(&config.templates_folder),
config,
}),
})
}
}
}
};
( @expr $name:expr, $ty:ty, $config:expr, $default_fn:expr ) => {{
match get_env($name) {
Some(v) => v,
None => {
let f: &Fn(&_Config) -> _ = &$default_fn;
f($config).into_result()?
}
}
}};
( @expr $name:expr, $ty:ty, $config:expr, ) => {
get_env($name)
};
}
make_config! {
database_url: String,
icon_cache_folder: String,
attachments_folder: String,
data_folder: String, |_| "data".to_string();
database_url: String, |c| format!("{}/{}", c.data_folder, "db.sqlite3");
icon_cache_folder: String, |c| format!("{}/{}", c.data_folder, "icon_cache");
attachments_folder: String, |c| format!("{}/{}", c.data_folder, "attachments");
templates_folder: String, |c| format!("{}/{}", c.data_folder, "templates");
icon_cache_ttl: u64,
icon_cache_negttl: u64,
rsa_key_filename: String, |c| format!("{}/{}", c.data_folder, "rsa_key");
private_rsa_key: String, |c| format!("{}.der", c.rsa_key_filename);
private_rsa_key_pem: String, |c| format!("{}.pem", c.rsa_key_filename);
public_rsa_key: String, |c| format!("{}.pub.der", c.rsa_key_filename);
private_rsa_key: String,
private_rsa_key_pem: String,
public_rsa_key: String,
websocket_enabled: bool, |_| false;
websocket_address: String, |_| "0.0.0.0".to_string();
websocket_port: u16, |_| 3012;
web_vault_folder: String,
web_vault_enabled: bool,
web_vault_folder: String, |_| "web-vault/".to_string();
web_vault_enabled: bool, |_| true;
websocket_enabled: bool,
websocket_url: String,
icon_cache_ttl: u64, |_| 2_592_000;
icon_cache_negttl: u64, |_| 259_200;
extended_logging: bool,
log_file: Option<String>,
disable_icon_download: bool, |_| false;
signups_allowed: bool, |_| true;
invitations_allowed: bool, |_| true;
password_iterations: i32, |_| 100_000;
show_password_hint: bool, |_| true;
disable_icon_download: bool,
signups_allowed: bool,
invitations_allowed: bool,
admin_token: Option<String>,
password_iterations: i32,
show_password_hint: bool,
domain: String, |_| "http://localhost".to_string();
domain_set: bool, |_| false;
domain: String,
domain_set: bool,
reload_templates: bool, |_| false;
yubico_cred_set: bool,
yubico_client_id: String,
yubico_secret_key: String,
yubico_server: Option<String>,
extended_logging: bool, |_| true;
log_file: Option<String>;
mail: Option<MailConfig>,
templates_folder: String,
reload_templates: bool,
admin_token: Option<String>;
yubico_client_id: Option<String>;
yubico_secret_key: Option<String>;
yubico_server: Option<String>;
// Mail settings
smtp_host: Option<String>;
smtp_ssl: bool, |_| true;
smtp_port: u16, |c| if c.smtp_ssl {587} else {25};
smtp_from: String, |c| if c.smtp_host.is_some() { err!("Please specify SMTP_FROM to enable SMTP support") } else { Ok(String::new() )};
smtp_from_name: String, |_| "Bitwarden_RS".to_string();
smtp_username: Option<String>;
smtp_password: Option<String>;
}
impl Config {
pub fn mail_enabled(&self) -> bool {
self.inner.read().unwrap().config.smtp_host.is_some()
}
pub fn render_template<T: serde::ser::Serialize>(
&self,
name: &str,
data: &T,
) -> Result<String, crate::error::Error> {
if CONFIG.reload_templates() {
warn!("RELOADING TEMPLATES");
let hb = load_templates(CONFIG.templates_folder().as_ref());
hb.render(name, data).map_err(Into::into)
} else {
let hb = &CONFIG.inner.read().unwrap().templates;
hb.render(name, data).map_err(Into::into)
}
}
}
fn load_templates(path: &str) -> Handlebars {
@ -106,140 +178,3 @@ fn load_templates(path: &str) -> Handlebars {
hb
}
impl Config {
pub fn render_template<T: serde::ser::Serialize>(
&self,
name: &str,
data: &T,
) -> Result<String, crate::error::Error> {
if CONFIG.reload_templates() {
warn!("RELOADING TEMPLATES");
let hb = load_templates(CONFIG.templates_folder().as_ref());
hb.render(name, data).map_err(Into::into)
} else {
let hb = &CONFIG.inner.read().unwrap()._templates;
hb.render(name, data).map_err(Into::into)
}
}
fn load() -> Self {
use crate::util::{get_env, get_env_or};
dotenv::dotenv().ok();
let df = get_env_or("DATA_FOLDER", "data".to_string());
let key = get_env_or("RSA_KEY_FILENAME", format!("{}/{}", &df, "rsa_key"));
let domain = get_env("DOMAIN");
let yubico_client_id = get_env("YUBICO_CLIENT_ID");
let yubico_secret_key = get_env("YUBICO_SECRET_KEY");
let templates_folder = get_env_or("TEMPLATES_FOLDER", format!("{}/{}", &df, "templates"));
let cfg = _Config {
database_url: get_env_or("DATABASE_URL", format!("{}/{}", &df, "db.sqlite3")),
icon_cache_folder: get_env_or("ICON_CACHE_FOLDER", format!("{}/{}", &df, "icon_cache")),
attachments_folder: get_env_or("ATTACHMENTS_FOLDER", format!("{}/{}", &df, "attachments")),
_templates: load_templates(&templates_folder),
templates_folder,
reload_templates: get_env_or("RELOAD_TEMPLATES", false),
// icon_cache_ttl defaults to 30 days (30 * 24 * 60 * 60 seconds)
icon_cache_ttl: get_env_or("ICON_CACHE_TTL", 2_592_000),
// icon_cache_negttl defaults to 3 days (3 * 24 * 60 * 60 seconds)
icon_cache_negttl: get_env_or("ICON_CACHE_NEGTTL", 259_200),
private_rsa_key: format!("{}.der", &key),
private_rsa_key_pem: format!("{}.pem", &key),
public_rsa_key: format!("{}.pub.der", &key),
web_vault_folder: get_env_or("WEB_VAULT_FOLDER", "web-vault/".into()),
web_vault_enabled: get_env_or("WEB_VAULT_ENABLED", true),
websocket_enabled: get_env_or("WEBSOCKET_ENABLED", false),
websocket_url: format!(
"{}:{}",
get_env_or("WEBSOCKET_ADDRESS", "0.0.0.0".to_string()),
get_env_or("WEBSOCKET_PORT", 3012)
),
extended_logging: get_env_or("EXTENDED_LOGGING", true),
log_file: get_env("LOG_FILE"),
disable_icon_download: get_env_or("DISABLE_ICON_DOWNLOAD", false),
signups_allowed: get_env_or("SIGNUPS_ALLOWED", true),
admin_token: get_env("ADMIN_TOKEN"),
invitations_allowed: get_env_or("INVITATIONS_ALLOWED", true),
password_iterations: get_env_or("PASSWORD_ITERATIONS", 100_000),
show_password_hint: get_env_or("SHOW_PASSWORD_HINT", true),
domain_set: domain.is_some(),
domain: domain.unwrap_or("http://localhost".into()),
yubico_cred_set: yubico_client_id.is_some() && yubico_secret_key.is_some(),
yubico_client_id: yubico_client_id.unwrap_or("00000".into()),
yubico_secret_key: yubico_secret_key.unwrap_or("AAAAAAA".into()),
yubico_server: get_env("YUBICO_SERVER"),
mail: MailConfig::load(),
};
Config {
inner: RwLock::new(cfg),
}
}
}
#[derive(Debug, Clone)]
pub struct MailConfig {
pub smtp_host: String,
pub smtp_port: u16,
pub smtp_ssl: bool,
pub smtp_from: String,
pub smtp_from_name: String,
pub smtp_username: Option<String>,
pub smtp_password: Option<String>,
}
impl MailConfig {
fn load() -> Option<Self> {
use crate::util::{get_env, get_env_or};
// When SMTP_HOST is absent, we assume the user does not want to enable it.
let smtp_host = match get_env("SMTP_HOST") {
Some(host) => host,
None => return None,
};
let smtp_from = get_env("SMTP_FROM").unwrap_or_else(|| {
error!("Please specify SMTP_FROM to enable SMTP support.");
exit(1);
});
let smtp_from_name = get_env_or("SMTP_FROM_NAME", "Bitwarden_RS".into());
let smtp_ssl = get_env_or("SMTP_SSL", true);
let smtp_port = get_env("SMTP_PORT").unwrap_or_else(|| if smtp_ssl { 587u16 } else { 25u16 });
let smtp_username = get_env("SMTP_USERNAME");
let smtp_password = get_env("SMTP_PASSWORD").or_else(|| {
if smtp_username.as_ref().is_some() {
error!("SMTP_PASSWORD is mandatory when specifying SMTP_USERNAME.");
exit(1);
} else {
None
}
});
Some(MailConfig {
smtp_host,
smtp_port,
smtp_ssl,
smtp_from,
smtp_from_name,
smtp_username,
smtp_password,
})
}
}