From 70f3ab8ec3d6ccfd8ec8c71c888459de484d9b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Mon, 9 Mar 2020 22:04:03 +0100 Subject: [PATCH] Migrate lazy_static to once_cell, less macro magic and slightly faster --- Cargo.lock | 56 ++++++++++------------------------ Cargo.toml | 4 +-- src/api/admin.rs | 6 ++-- src/api/core/two_factor/u2f.rs | 7 ++--- src/api/icons.rs | 9 +++--- src/auth.rs | 33 ++++++++++---------- src/config.rs | 26 ++++++++-------- src/main.rs | 2 -- 8 files changed, 59 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 628cc1a0..656df625 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,7 +131,6 @@ dependencies = [ "handlebars", "idna 0.2.0", "jsonwebtoken", - "lazy_static", "lettre", "libsqlite3-sys", "log 0.4.8", @@ -140,6 +139,7 @@ dependencies = [ "num-derive", "num-traits", "oath", + "once_cell", "openssl", "percent-encoding 2.1.0", "quoted_printable", @@ -702,11 +702,10 @@ dependencies = [ [[package]] name = "fern" -version = "0.5.9" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69ab0d5aca163e388c3a49d284fed6c3d0810700e77c5ae2756a50ec1a4daaa" +checksum = "8c9a4820f0ccc8a7afd67c39a0f1a0f4b07ca1725164271a64939d7aeb9af065" dependencies = [ - "chrono", "log 0.4.8", "syslog", ] @@ -938,16 +937,16 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04478cf718862650a0bf66acaf8f2f8c906fbc703f35c916c1f4211b069a364" +checksum = "c213fa6a618dc1da552f54f85cba74b05d8e883c92ec4e89067736938084c26e" dependencies = [ "log 0.4.8", "mac", "markup5ever", - "proc-macro2 0.3.8", - "quote 0.5.2", - "syn 0.13.11", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] @@ -1561,6 +1560,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "once_cell" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" + [[package]] name = "opaque-debug" version = "0.2.3" @@ -1861,15 +1866,6 @@ dependencies = [ "syn 1.0.16", ] -[[package]] -name = "proc-macro2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" -dependencies = [ - "unicode-xid 0.1.0", -] - [[package]] name = "proc-macro2" version = "0.4.30" @@ -1907,15 +1903,6 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quote" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" -dependencies = [ - "proc-macro2 0.3.8", -] - [[package]] name = "quote" version = "0.6.13" @@ -2533,9 +2520,9 @@ checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" [[package]] name = "soup" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16eb6b0678654a57009598ed84610f2afa5fadb22f3815e9f23dc5eab1056031" +checksum = "ee42b8c117ede655c8ffe18dafcd239b23eb3bb7a2c71b1f01237587736f139f" dependencies = [ "html5ever", "regex", @@ -2650,17 +2637,6 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" -[[package]] -name = "syn" -version = "0.13.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" -dependencies = [ - "proc-macro2 0.3.8", - "quote 0.5.2", - "unicode-xid 0.1.0", -] - [[package]] name = "syn" version = "0.15.44" diff --git a/Cargo.toml b/Cargo.toml index 585b9b38..9ce8d750 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,8 +83,8 @@ yubico = { version = "0.7.1", features = ["online-tokio"], default-features = fa # A `dotenv` implementation for Rust dotenv = { version = "0.15.0", default-features = false } -# Lazy static macro -lazy_static = "1.4.0" +# Lazy initialization +once_cell = "1.3.1" # More derives derive_more = "0.99.3" diff --git a/src/api/admin.rs b/src/api/admin.rs index 03e62700..54dbdf95 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -1,3 +1,4 @@ +use once_cell::sync::Lazy; use serde_json::Value; use std::process::Command; @@ -38,9 +39,8 @@ pub fn routes() -> Vec { ] } -lazy_static! { - static ref CAN_BACKUP: bool = cfg!(feature = "sqlite") && Command::new("sqlite3").arg("-version").status().is_ok(); -} +static CAN_BACKUP: Lazy = + Lazy::new(|| cfg!(feature = "sqlite") && Command::new("sqlite3").arg("-version").status().is_ok()); #[get("/")] fn admin_disabled() -> &'static str { diff --git a/src/api/core/two_factor/u2f.rs b/src/api/core/two_factor/u2f.rs index d3dcc573..77f1418b 100644 --- a/src/api/core/two_factor/u2f.rs +++ b/src/api/core/two_factor/u2f.rs @@ -1,3 +1,4 @@ +use once_cell::sync::Lazy; use rocket::Route; use rocket_contrib::json::Json; use serde_json; @@ -18,10 +19,8 @@ use crate::CONFIG; const U2F_VERSION: &str = "U2F_V2"; -lazy_static! { - static ref APP_ID: String = format!("{}/app-id.json", &CONFIG.domain()); - static ref U2F: U2f = U2f::new(APP_ID.clone()); -} +static APP_ID: Lazy = Lazy::new(|| format!("{}/app-id.json", &CONFIG.domain())); +static U2F: Lazy = Lazy::new(|| U2f::new(APP_ID.clone())); pub fn routes() -> Vec { routes![ diff --git a/src/api/icons.rs b/src/api/icons.rs index 556395ee..bceef26e 100644 --- a/src/api/icons.rs +++ b/src/api/icons.rs @@ -1,3 +1,4 @@ +use once_cell::sync::Lazy; use std::fs::{create_dir_all, remove_file, symlink_metadata, File}; use std::io::prelude::*; use std::net::ToSocketAddrs; @@ -26,16 +27,16 @@ const FALLBACK_ICON: &[u8; 344] = include_bytes!("../static/fallback-icon.png"); const ALLOWED_CHARS: &str = "_-."; -lazy_static! { +static CLIENT: Lazy = Lazy::new(|| { // Reuse the client between requests - static ref CLIENT: Client = Client::builder() + Client::builder() .use_sys_proxy() .gzip(true) .timeout(Duration::from_secs(CONFIG.icon_download_timeout())) .default_headers(_header_map()) .build() - .unwrap(); -} + .unwrap() +}); fn is_valid_domain(domain: &str) -> bool { // Don't allow empty or too big domains or path traversal diff --git a/src/auth.rs b/src/auth.rs index cbcdb47a..d007d727 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -3,6 +3,7 @@ // use crate::util::read_file; use chrono::{Duration, Utc}; +use once_cell::sync::Lazy; use jsonwebtoken::{self, Algorithm, Header}; use serde::de::DeserializeOwned; @@ -13,23 +14,21 @@ use crate::CONFIG; const JWT_ALGORITHM: Algorithm = Algorithm::RS256; -lazy_static! { - pub static ref DEFAULT_VALIDITY: Duration = Duration::hours(2); - static ref JWT_HEADER: Header = Header::new(JWT_ALGORITHM); - pub static ref JWT_LOGIN_ISSUER: String = format!("{}|login", CONFIG.domain_origin()); - pub static ref JWT_INVITE_ISSUER: String = format!("{}|invite", CONFIG.domain_origin()); - pub static ref JWT_DELETE_ISSUER: String = format!("{}|delete", CONFIG.domain_origin()); - pub static ref JWT_VERIFYEMAIL_ISSUER: String = format!("{}|verifyemail", CONFIG.domain_origin()); - pub static ref JWT_ADMIN_ISSUER: String = format!("{}|admin", CONFIG.domain_origin()); - static ref PRIVATE_RSA_KEY: Vec = match read_file(&CONFIG.private_rsa_key()) { - Ok(key) => key, - Err(e) => panic!("Error loading private RSA Key.\n Error: {}", e), - }; - static ref PUBLIC_RSA_KEY: Vec = match read_file(&CONFIG.public_rsa_key()) { - Ok(key) => key, - Err(e) => panic!("Error loading public RSA Key.\n Error: {}", e), - }; -} +pub static DEFAULT_VALIDITY: Lazy = Lazy::new(|| Duration::hours(2)); +static JWT_HEADER: Lazy
= Lazy::new(|| Header::new(JWT_ALGORITHM)); +pub static JWT_LOGIN_ISSUER: Lazy = Lazy::new(|| format!("{}|login", CONFIG.domain_origin())); +static JWT_INVITE_ISSUER: Lazy = Lazy::new(|| format!("{}|invite", CONFIG.domain_origin())); +static JWT_DELETE_ISSUER: Lazy = Lazy::new(|| format!("{}|delete", CONFIG.domain_origin())); +static JWT_VERIFYEMAIL_ISSUER: Lazy = Lazy::new(|| format!("{}|verifyemail", CONFIG.domain_origin())); +static JWT_ADMIN_ISSUER: Lazy = Lazy::new(|| format!("{}|admin", CONFIG.domain_origin())); +static PRIVATE_RSA_KEY: Lazy> = Lazy::new(|| match read_file(&CONFIG.private_rsa_key()) { + Ok(key) => key, + Err(e) => panic!("Error loading private RSA Key.\n Error: {}", e), +}); +static PUBLIC_RSA_KEY: Lazy> = Lazy::new(|| match read_file(&CONFIG.public_rsa_key()) { + Ok(key) => key, + Err(e) => panic!("Error loading public RSA Key.\n Error: {}", e), +}); pub fn encode_jwt(claims: &T) -> String { match jsonwebtoken::encode(&JWT_HEADER, claims, &PRIVATE_RSA_KEY) { diff --git a/src/config.rs b/src/config.rs index 12e04d65..0d79b215 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +use once_cell::sync::Lazy; use std::process::exit; use std::sync::RwLock; @@ -6,16 +7,17 @@ use reqwest::Url; use crate::error::Error; use crate::util::{get_env, get_env_bool}; -lazy_static! { - pub static ref CONFIG: Config = Config::load().unwrap_or_else(|e| { +static CONFIG_FILE: Lazy = Lazy::new(|| { + let data_folder = get_env("DATA_FOLDER").unwrap_or_else(|| String::from("data")); + get_env("CONFIG_FILE").unwrap_or_else(|| format!("{}/config.json", data_folder)) +}); + +pub static CONFIG: Lazy = Lazy::new(|| { + Config::load().unwrap_or_else(|e| { println!("Error loading config:\n\t{:?}\n", e); exit(12) - }); - pub static ref CONFIG_FILE: String = { - let data_folder = get_env("DATA_FOLDER").unwrap_or_else(|| String::from("data")); - get_env("CONFIG_FILE").unwrap_or_else(|| format!("{}/config.json", data_folder)) - }; -} + }) +}); pub type Pass = String; @@ -54,7 +56,7 @@ macro_rules! make_config { $($( builder.$name = make_config! { @getenv &stringify!($name).to_uppercase(), $ty }; )+)+ - + builder } @@ -420,8 +422,8 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { if cfg!(feature = "postgresql") && !db_url.starts_with("postgresql:") { err!("`DATABASE_URL` should start with postgresql: when using the PostgreSQL server") } - - let dom = cfg.domain.to_lowercase(); + + let dom = cfg.domain.to_lowercase(); if !dom.starts_with("http://") && !dom.starts_with("https://") { err!("DOMAIN variable needs to contain the protocol (http, https). Use 'http[s]://bw.example.com' instead of 'bw.example.com'"); } @@ -555,7 +557,7 @@ impl Config { warn!("Failed to parse email address '{}'", email); return false; } - + // Allow signups if the whitelist is empty/not configured // (it doesn't contain any domains), or if it matches at least // one domain. diff --git a/src/main.rs b/src/main.rs index 5274795f..4de84ba2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,8 +16,6 @@ extern crate diesel; #[macro_use] extern crate diesel_migrations; #[macro_use] -extern crate lazy_static; -#[macro_use] extern crate derive_more; #[macro_use] extern crate num_derive;