vw_small

Hardened fork of Vaultwarden (https://github.com/dani-garcia/vaultwarden) with fewer features.
git clone https://git.philomathiclife.com/repos/vw_small
Log | Files | Refs | README

commit c453528dc10d92c76776a7c96dd8de178a14cfff
parent 6ae48aa8c258c0b3d53966e6abb2d9756e65f56d
Author: BlackDex <black.dex@gmail.com>
Date:   Fri,  5 Nov 2021 19:18:54 +0100

Macro recursion decrease and other optimizations

- Decreased `recursion_limit` from 512 to 87
  Mainly done by optimizing the config macro's.
  This fixes an issue with the rust-analyzer which doesn't go beyond 128
- Removed Regex for masking sensitive values and replaced it with a map()
  This is much faster then using a Regex.
- Refactored the get_support_json macro's
- All items above also lowered the binary size and possibly compile-time
- Removed `_conn: DbConn` from several functions, these caused unnecessary database connections for functions who didn't used that at all
- Decreased json response for `/plans`
- Updated libraries and where needed some code changes
  This also fixes some rare issues with SMTP https://github.com/lettre/lettre/issues/678
- Using Rust 2021 instead of 2018
- Updated rust nightly

Diffstat:
MCargo.lock | 169++++++++++++++++++++++++++++++++-----------------------------------------------
MCargo.toml | 10+++++-----
Mdocker/Dockerfile.j2 | 2+-
Mdocker/amd64/Dockerfile.alpine | 2+-
Mdocker/amd64/Dockerfile.buildx.alpine | 2+-
Mrust-toolchain | 2+-
Msrc/api/admin.rs | 5++---
Msrc/api/core/accounts.rs | 4++--
Msrc/api/core/organizations.rs | 62+++++++++++++++++---------------------------------------------
Msrc/api/notifications.rs | 4++--
Msrc/auth.rs | 1-
Msrc/config.rs | 153++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/db/models/two_factor.rs | 1-
Msrc/error.rs | 2+-
Msrc/mail.rs | 10+++++-----
Msrc/main.rs | 6+++++-
Msrc/util.rs | 17+++++++++--------
17 files changed, 210 insertions(+), 242 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" dependencies = [ "gimli", ] @@ -74,9 +74,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.62" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" dependencies = [ "addr2line", "cc", @@ -134,18 +134,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -451,9 +439,9 @@ version = "0.3.0" source = "git+https://github.com/SergioBenitez/Devise.git?rev=e58b3ac9a#e58b3ac9afc3b6ff10a8aaf02a3e768a8f530089" dependencies = [ "bitflags", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -479,9 +467,9 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -639,12 +627,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - -[[package]] name = "futf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -710,9 +692,9 @@ checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ "autocfg", "proc-macro-hack", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -791,9 +773,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.25.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "glob" @@ -896,9 +878,9 @@ dependencies = [ "log 0.4.14", "mac", "markup5ever", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1128,9 +1110,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lettre" -version = "0.10.0-rc.3" +version = "0.10.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8697ded52353bdd6fec234b3135972433397e86d0493d9fc38fbf407b7c106a" +checksum = "71d8da8f34d086b081c9cc3b57d3bb3b51d16fc06b5c848a188e2f14d58ac2a5" dependencies = [ "base64 0.13.0", "fastrand", @@ -1139,7 +1121,7 @@ dependencies = [ "idna 0.2.3", "mime 0.3.16", "native-tls", - "nom 6.1.2", + "nom 7.1.0", "once_cell", "quoted_printable", "regex", @@ -1149,9 +1131,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" [[package]] name = "libsqlite3-sys" @@ -1269,9 +1251,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c" dependencies = [ "migrations_internals", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1300,6 +1282,12 @@ dependencies = [ ] [[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] name = "miniz_oxide" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1448,13 +1436,12 @@ dependencies = [ [[package]] name = "nom" -version = "6.1.2" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ - "bitvec", - "funty", "memchr", + "minimal-lexical", "version_check 0.9.3", ] @@ -1484,9 +1471,9 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1547,9 +1534,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.36" +version = "0.10.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -1567,18 +1554,18 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-src" -version = "111.16.0+1.1.1l" +version = "300.0.2+3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab2173f69416cf3ec12debb5823d244127d23a9b127d5a5189aa97c5fa2859f" +checksum = "14a760a11390b1a5daf72074d4f6ff1a6e772534ae191f999f57e9ee8146d1fb" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.67" +version = "0.9.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" +checksum = "c6517987b3f8226b5da3661dad65ff7f300cc59fb5ea8333ca191fc65fde3edf" dependencies = [ "autocfg", "cc", @@ -1599,9 +1586,9 @@ dependencies = [ [[package]] name = "parity-ws" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab8a461779bd022964cae2b4989fa9c99deb270bec162da2125ec03c09fcaa" +checksum = "5983d3929ad50f12c3eb9a6743f19d691866ecd44da74c0a3308c3f8a56df0c6" dependencies = [ "byteorder", "bytes 0.4.12", @@ -1749,9 +1736,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -1910,9 +1897,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid 0.2.2", ] @@ -1962,7 +1949,7 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", ] [[package]] @@ -1983,12 +1970,6 @@ dependencies = [ ] [[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - -[[package]] name = "rand" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2446,9 +2427,9 @@ version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2613,11 +2594,11 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "serde", "serde_derive", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2627,13 +2608,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" dependencies = [ "base-x", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "serde", "serde_derive", "serde_json", "sha1", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2664,7 +2645,7 @@ checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" dependencies = [ "phf_generator 0.8.0", "phf_shared 0.8.0", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", ] @@ -2687,11 +2668,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "unicode-xid 0.2.2", ] @@ -2709,12 +2690,6 @@ dependencies = [ ] [[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2754,9 +2729,9 @@ version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2811,10 +2786,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", "standback", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -2834,9 +2809,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" dependencies = [ "autocfg", "bytes 1.1.0", @@ -2872,9 +2847,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ "bytes 1.1.0", "futures-core", @@ -2930,9 +2905,9 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", ] [[package]] @@ -3224,9 +3199,9 @@ dependencies = [ "bumpalo", "lazy_static", "log 0.4.14", - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "wasm-bindgen-shared", ] @@ -3258,9 +3233,9 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ - "proc-macro2 1.0.30", + "proc-macro2 1.0.32", "quote 1.0.10", - "syn 1.0.80", + "syn 1.0.81", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3383,12 +3358,6 @@ dependencies = [ ] [[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - -[[package]] name = "xml5ever" version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -2,7 +2,7 @@ name = "vaultwarden" version = "1.0.0" authors = ["Daniel GarcĂ­a <dani-garcia@users.noreply.github.com>"] -edition = "2018" +edition = "2021" rust-version = "1.57" resolver = "2" @@ -46,7 +46,7 @@ url = "2.2.2" multipart = { version = "0.18.0", features = ["server"], default-features = false } # WebSockets library -ws = { version = "0.11.0", package = "parity-ws" } +ws = { version = "0.11.1", package = "parity-ws" } # MessagePack library rmpv = "1.0.0" @@ -112,7 +112,7 @@ num-derive = "0.3.3" # Email libraries tracing = { version = "0.1.29", features = ["log"] } # Needed to have lettre trace logging used when SMTP_DEBUG is enabled. -lettre = { version = "0.10.0-rc.3", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false } +lettre = { version = "0.10.0-rc.4", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false } # Template library handlebars = { version = "4.1.3", features = ["dir_source"] } @@ -124,7 +124,7 @@ regex = { version = "1.5.4", features = ["std", "perf", "unicode-perl"], default data-url = "0.1.0" # Used by U2F, JWT and Postgres -openssl = "0.10.36" +openssl = "0.10.38" # URL encoding library percent-encoding = "2.1.0" @@ -135,7 +135,7 @@ idna = "0.2.3" pico-args = "0.4.2" # Logging panics to logfile instead stderr only -backtrace = "0.3.62" +backtrace = "0.3.63" # Macro ident concatenation paste = "1.0.5" diff --git a/docker/Dockerfile.j2 b/docker/Dockerfile.j2 @@ -6,7 +6,7 @@ {% set build_stage_base_image = "rust:1.55-buster" %} {% if "alpine" in target_file %} {% if "amd64" in target_file %} -{% set build_stage_base_image = "clux/muslrust:nightly-2021-10-06" %} +{% set build_stage_base_image = "clux/muslrust:nightly-2021-10-23" %} {% set runtime_stage_base_image = "alpine:3.14" %} {% set package_arch_target = "x86_64-unknown-linux-musl" %} {% elif "armv7" in target_file %} diff --git a/docker/amd64/Dockerfile.alpine b/docker/amd64/Dockerfile.alpine @@ -27,7 +27,7 @@ FROM vaultwarden/web-vault@sha256:0e8daf80abb73ebca69d1971847450d24da45a74a525fd643246ee1dfa02108b as vault ########################## BUILD IMAGE ########################## -FROM clux/muslrust:nightly-2021-10-06 as build +FROM clux/muslrust:nightly-2021-10-23 as build # Alpine-based AMD64 (musl) does not support mysql/mariadb during compile time. ARG DB=sqlite,postgresql diff --git a/docker/amd64/Dockerfile.buildx.alpine b/docker/amd64/Dockerfile.buildx.alpine @@ -27,7 +27,7 @@ FROM vaultwarden/web-vault@sha256:0e8daf80abb73ebca69d1971847450d24da45a74a525fd643246ee1dfa02108b as vault ########################## BUILD IMAGE ########################## -FROM clux/muslrust:nightly-2021-10-06 as build +FROM clux/muslrust:nightly-2021-10-23 as build # Alpine-based AMD64 (musl) does not support mysql/mariadb during compile time. ARG DB=sqlite,postgresql diff --git a/rust-toolchain b/rust-toolchain @@ -1 +1 @@ -nightly-2021-10-14 +nightly-2021-11-05 diff --git a/src/api/admin.rs b/src/api/admin.rs @@ -236,7 +236,7 @@ impl AdminTemplateData { } #[get("/", rank = 1)] -fn admin_page(_token: AdminToken, _conn: DbConn) -> ApiResult<Html<String>> { +fn admin_page(_token: AdminToken) -> ApiResult<Html<String>> { let text = AdminTemplateData::new().render()?; Ok(Html(text)) } @@ -494,7 +494,6 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu // Execute some environment checks let running_within_docker = is_running_in_docker(); - let docker_base_image = docker_base_image(); let has_http_access = has_http_access(); let uses_proxy = env::var_os("HTTP_PROXY").is_some() || env::var_os("http_proxy").is_some() @@ -552,7 +551,7 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu "web_vault_version": web_vault_version.version, "latest_web_build": latest_web_build, "running_within_docker": running_within_docker, - "docker_base_image": docker_base_image, + "docker_base_image": docker_base_image(), "has_http_access": has_http_access, "ip_header_exists": &ip_header.0.is_some(), "ip_header_match": ip_header_name == CONFIG.ip_header(), diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs @@ -454,7 +454,7 @@ fn post_email(data: JsonUpcase<ChangeEmailData>, headers: Headers, conn: DbConn) } #[post("/accounts/verify-email")] -fn post_verify_email(headers: Headers, _conn: DbConn) -> EmptyResult { +fn post_verify_email(headers: Headers) -> EmptyResult { let user = headers.user; if !CONFIG.mail_enabled() { @@ -654,7 +654,7 @@ struct VerifyPasswordData { } #[post("/accounts/verify-password", data = "<data>")] -fn verify_password(data: JsonUpcase<VerifyPasswordData>, headers: Headers, _conn: DbConn) -> EmptyResult { +fn verify_password(data: JsonUpcase<VerifyPasswordData>, headers: Headers) -> EmptyResult { let data: VerifyPasswordData = data.into_inner().data; let user = headers.user; diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs @@ -1294,71 +1294,43 @@ fn put_policy( #[allow(unused_variables)] #[get("/organizations/<org_id>/tax")] -fn get_organization_tax(org_id: String, _headers: Headers, _conn: DbConn) -> EmptyResult { +fn get_organization_tax(org_id: String, _headers: Headers) -> Json<Value> { // Prevent a 404 error, which also causes Javascript errors. - err!("Only allowed when not self hosted.") + // Upstream sends "Only allowed when not self hosted." As an error message. + // If we do the same it will also output this to the log, which is overkill. + // An empty list/data also works fine. + Json(_empty_data_json()) } #[get("/plans")] -fn get_plans(_headers: Headers, _conn: DbConn) -> Json<Value> { +fn get_plans(_headers: Headers) -> Json<Value> { + // Respond with a minimal json just enough to allow the creation of an new organization. Json(json!({ "Object": "list", - "Data": [ - { + "Data": [{ "Object": "plan", "Type": 0, "Product": 0, "Name": "Free", - "IsAnnual": false, "NameLocalizationKey": "planNameFree", - "DescriptionLocalizationKey": "planDescFree", - "CanBeUsedByBusiness": false, - "BaseSeats": 2, - "BaseStorageGb": null, - "MaxCollections": 2, - "MaxUsers": 2, - "HasAdditionalSeatsOption": false, - "MaxAdditionalSeats": null, - "HasAdditionalStorageOption": false, - "MaxAdditionalStorage": null, - "HasPremiumAccessOption": false, - "TrialPeriodDays": null, - "HasSelfHost": false, - "HasPolicies": false, - "HasGroups": false, - "HasDirectory": false, - "HasEvents": false, - "HasTotp": false, - "Has2fa": false, - "HasApi": false, - "HasSso": false, - "UsersGetPremium": false, - "UpgradeSortOrder": -1, - "DisplaySortOrder": -1, - "LegacyYear": null, - "Disabled": false, - "StripePlanId": null, - "StripeSeatPlanId": null, - "StripeStoragePlanId": null, - "StripePremiumAccessPlanId": null, - "BasePrice": 0.0, - "SeatPrice": 0.0, - "AdditionalStoragePricePerGb": 0.0, - "PremiumAccessOptionPrice": 0.0 - } - ], + "DescriptionLocalizationKey": "planDescFree" + }], "ContinuationToken": null })) } #[get("/plans/sales-tax-rates")] -fn get_plans_tax_rates(_headers: Headers, _conn: DbConn) -> Json<Value> { +fn get_plans_tax_rates(_headers: Headers) -> Json<Value> { // Prevent a 404 error, which also causes Javascript errors. - Json(json!({ + Json(_empty_data_json()) +} + +fn _empty_data_json() -> Value { + json!({ "Object": "list", "Data": [], "ContinuationToken": null - })) + }) } #[derive(Deserialize, Debug)] diff --git a/src/api/notifications.rs b/src/api/notifications.rs @@ -4,7 +4,7 @@ use rocket::Route; use rocket_contrib::json::Json; use serde_json::Value as JsonValue; -use crate::{api::EmptyResult, auth::Headers, db::DbConn, Error, CONFIG}; +use crate::{api::EmptyResult, auth::Headers, Error, CONFIG}; pub fn routes() -> Vec<Route> { routes![negotiate, websockets_err] @@ -30,7 +30,7 @@ fn websockets_err() -> EmptyResult { } #[post("/hub/negotiate")] -fn negotiate(_headers: Headers, _conn: DbConn) -> Json<JsonValue> { +fn negotiate(_headers: Headers) -> Json<JsonValue> { use crate::crypto; use data_encoding::BASE64URL; diff --git a/src/auth.rs b/src/auth.rs @@ -165,7 +165,6 @@ pub fn generate_invite_claims( } } -// var token = _dataProtector.Protect($"EmergencyAccessInvite {emergencyAccess.Id} {emergencyAccess.Email} {nowMillis}"); #[derive(Debug, Serialize, Deserialize)] pub struct EmergencyAccessInviteJwtClaims { // Not before diff --git a/src/config.rs b/src/config.rs @@ -2,7 +2,6 @@ use std::process::exit; use std::sync::RwLock; use once_cell::sync::Lazy; -use regex::Regex; use reqwest::Url; use crate::{ @@ -23,21 +22,6 @@ pub static CONFIG: Lazy<Config> = Lazy::new(|| { }) }); -static PRIVACY_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"[\w]").unwrap()); -const PRIVACY_CONFIG: &[&str] = &[ - "allowed_iframe_ancestors", - "database_url", - "domain_origin", - "domain_path", - "domain", - "helo_name", - "org_creation_users", - "signups_domains_whitelist", - "smtp_from", - "smtp_host", - "smtp_username", -]; - pub type Pass = String; macro_rules! make_config { @@ -61,7 +45,7 @@ macro_rules! make_config { _overrides: Vec<String>, } - #[derive(Debug, Clone, Default, Deserialize, Serialize)] + #[derive(Clone, Default, Deserialize, Serialize)] pub struct ConfigBuilder { $($( #[serde(skip_serializing_if = "Option::is_none")] @@ -133,19 +117,6 @@ macro_rules! make_config { builder } - /// Returns a new builder with all the elements from self, - /// except those that are equal in both sides - fn _remove(&self, other: &Self) -> Self { - let mut builder = ConfigBuilder::default(); - $($( - if &self.$name != &other.$name { - builder.$name = self.$name.clone(); - } - - )+)+ - builder - } - fn build(&self) -> ConfigItems { let mut config = ConfigItems::default(); let _domain_set = self.domain.is_some(); @@ -161,7 +132,7 @@ macro_rules! make_config { } } - #[derive(Debug, Clone, Default)] + #[derive(Clone, Default)] struct ConfigItems { $($( $name: make_config!{@type $ty, $none_action}, )+)+ } #[allow(unused)] @@ -190,38 +161,91 @@ macro_rules! make_config { fn _get_doc(doc: &str) -> serde_json::Value { let mut split = doc.split("|>").map(str::trim); - json!({ - "name": split.next(), - "description": split.next() + + // We do not use the json!() macro here since that causes a lot of macro recursion. + // This slows down compile time and it also causes issues with rust-analyzer + serde_json::Value::Object({ + let mut doc_json = serde_json::Map::new(); + doc_json.insert("name".into(), serde_json::to_value(split.next()).unwrap()); + doc_json.insert("description".into(), serde_json::to_value(split.next()).unwrap()); + doc_json }) } - json!([ $({ - "group": stringify!($group), - "grouptoggle": stringify!($($group_enabled)?), - "groupdoc": make_config!{ @show $($groupdoc)? }, - "elements": [ - $( { - "editable": $editable, - "name": stringify!($name), - "value": cfg.$name, - "default": def.$name, - "type": _get_form_type(stringify!($ty)), - "doc": _get_doc(concat!($($doc),+)), - "overridden": overriden.contains(&stringify!($name).to_uppercase()), - }, )+ - ]}, )+ ]) + // We do not use the json!() macro here since that causes a lot of macro recursion. + // This slows down compile time and it also causes issues with rust-analyzer + serde_json::Value::Array(<[_]>::into_vec(Box::new([ + $( + serde_json::Value::Object({ + let mut group = serde_json::Map::new(); + group.insert("group".into(), (stringify!($group)).into()); + group.insert("grouptoggle".into(), (stringify!($($group_enabled)?)).into()); + group.insert("groupdoc".into(), (make_config!{ @show $($groupdoc)? }).into()); + + group.insert("elements".into(), serde_json::Value::Array(<[_]>::into_vec(Box::new([ + $( + serde_json::Value::Object({ + let mut element = serde_json::Map::new(); + element.insert("editable".into(), ($editable).into()); + element.insert("name".into(), (stringify!($name)).into()); + element.insert("value".into(), serde_json::to_value(cfg.$name).unwrap()); + element.insert("default".into(), serde_json::to_value(def.$name).unwrap()); + element.insert("type".into(), (_get_form_type(stringify!($ty))).into()); + element.insert("doc".into(), (_get_doc(concat!($($doc),+))).into()); + element.insert("overridden".into(), (overriden.contains(&stringify!($name).to_uppercase())).into()); + element + }), + )+ + ])))); + group + }), + )+ + ]))) } pub fn get_support_json(&self) -> serde_json::Value { + // Define which config keys need to be masked. + // Pass types will always be masked and no need to put them in the list. + // Besides Pass, only String types will be masked via _privacy_mask. + const PRIVACY_CONFIG: &[&str] = &[ + "allowed_iframe_ancestors", + "database_url", + "domain_origin", + "domain_path", + "domain", + "helo_name", + "org_creation_users", + "signups_domains_whitelist", + "smtp_from", + "smtp_host", + "smtp_username", + ]; + let cfg = { let inner = &self.inner.read().unwrap(); inner.config.clone() }; - json!({ $($( - stringify!($name): make_config!{ @supportstr $name, cfg.$name, $ty, $none_action }, - )+)+ }) + /// We map over the string and remove all alphanumeric, _ and - characters. + /// This is the fastest way (within micro-seconds) instead of using a regex (which takes mili-seconds) + fn _privacy_mask(value: &str) -> String { + value.chars().map(|c| + match c { + c if c.is_alphanumeric() => '*', + '_' => '*', + '-' => '*', + _ => c + } + ).collect::<String>() + } + + serde_json::Value::Object({ + let mut json = serde_json::Map::new(); + $($( + json.insert(stringify!($name).into(), make_config!{ @supportstr $name, cfg.$name, $ty, $none_action }); + )+)+; + json + }) } pub fn get_overrides(&self) -> Vec<String> { @@ -229,29 +253,30 @@ macro_rules! make_config { let inner = &self.inner.read().unwrap(); inner._overrides.clone() }; - overrides } } }; // Support string print - ( @supportstr $name:ident, $value:expr, Pass, option ) => { $value.as_ref().map(|_| String::from("***")) }; // Optional pass, we map to an Option<String> with "***" - ( @supportstr $name:ident, $value:expr, Pass, $none_action:ident ) => { String::from("***") }; // Required pass, we return "***" - ( @supportstr $name:ident, $value:expr, $ty:ty, option ) => { // Optional other value, we return as is or convert to string to apply the privacy config + ( @supportstr $name:ident, $value:expr, Pass, option ) => { serde_json::to_value($value.as_ref().map(|_| String::from("***"))).unwrap() }; // Optional pass, we map to an Option<String> with "***" + ( @supportstr $name:ident, $value:expr, Pass, $none_action:ident ) => { "***".into() }; // Required pass, we return "***" + ( @supportstr $name:ident, $value:expr, String, option ) => { // Optional other value, we return as is or convert to string to apply the privacy config if PRIVACY_CONFIG.contains(&stringify!($name)) { - json!($value.as_ref().map(|x| PRIVACY_REGEX.replace_all(&x.to_string(), "${1}*").to_string())) + serde_json::to_value($value.as_ref().map(|x| _privacy_mask(x) )).unwrap() } else { - json!($value) + serde_json::to_value($value).unwrap() } }; - ( @supportstr $name:ident, $value:expr, $ty:ty, $none_action:ident ) => { // Required other value, we return as is or convert to string to apply the privacy config + ( @supportstr $name:ident, $value:expr, String, $none_action:ident ) => { // Required other value, we return as is or convert to string to apply the privacy config if PRIVACY_CONFIG.contains(&stringify!($name)) { - json!(PRIVACY_REGEX.replace_all(&$value.to_string(), "${1}*").to_string()) - } else { - json!($value) - } + _privacy_mask(&$value).into() + } else { + ($value).into() + } }; + ( @supportstr $name:ident, $value:expr, $ty:ty, option ) => { serde_json::to_value($value).unwrap() }; // Optional other value, we return as is or convert to string to apply the privacy config + ( @supportstr $name:ident, $value:expr, $ty:ty, $none_action:ident ) => { ($value).into() }; // Required other value, we return as is or convert to string to apply the privacy config // Group or empty string ( @show ) => { "" }; @@ -627,7 +652,7 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { // Check if the icon blacklist regex is valid if let Some(ref r) = cfg.icon_blacklist_regex { - let validate_regex = Regex::new(r); + let validate_regex = regex::Regex::new(r); match validate_regex { Ok(_) => (), Err(e) => err!(format!("`ICON_BLACKLIST_REGEX` is invalid: {:#?}", e)), diff --git a/src/db/models/two_factor.rs b/src/db/models/two_factor.rs @@ -159,7 +159,6 @@ impl TwoFactor { use crate::api::core::two_factor::u2f::U2FRegistration; use crate::api::core::two_factor::webauthn::{get_webauthn_registrations, WebauthnRegistration}; - use std::convert::TryInto; use webauthn_rs::proto::*; for mut u2f in u2f_factors { diff --git a/src/error.rs b/src/error.rs @@ -73,7 +73,7 @@ make_error! { Serde(SerdeErr): _has_source, _api_error, JWt(JwtErr): _has_source, _api_error, Handlebars(HbErr): _has_source, _api_error, - //WsError(ws::Error): _has_source, _api_error, + Io(IoErr): _has_source, _api_error, Time(TimeErr): _has_source, _api_error, Req(ReqErr): _has_source, _api_error, diff --git a/src/mail.rs b/src/mail.rs @@ -505,10 +505,10 @@ fn send_email(address: &str, subject: &str, body_html: String, body_text: String Err(e) => { if e.is_client() { debug!("SMTP Client error: {:#?}", e); - err!(format!("SMTP Client error: {}", e.to_string())); + err!(format!("SMTP Client error: {}", e)); } else if e.is_transient() { debug!("SMTP 4xx error: {:#?}", e); - err!(format!("SMTP 4xx error: {}", e.to_string())); + err!(format!("SMTP 4xx error: {}", e)); } else if e.is_permanent() { debug!("SMTP 5xx error: {:#?}", e); let mut msg = e.to_string(); @@ -519,13 +519,13 @@ fn send_email(address: &str, subject: &str, body_html: String, body_text: String err!(format!("SMTP 5xx error: {}", msg)); } else if e.is_timeout() { debug!("SMTP timeout error: {:#?}", e); - err!(format!("SMTP timeout error: {}", e.to_string())); + err!(format!("SMTP timeout error: {}", e)); } else if e.is_tls() { debug!("SMTP Encryption error: {:#?}", e); - err!(format!("SMTP Encryption error: {}", e.to_string())); + err!(format!("SMTP Encryption error: {}", e)); } else { debug!("SMTP {:#?}", e); - err!(format!("SMTP {}", e.to_string())); + err!(format!("SMTP {}", e)); } } } diff --git a/src/main.rs b/src/main.rs @@ -1,6 +1,10 @@ #![forbid(unsafe_code)] #![cfg_attr(feature = "unstable", feature(ip))] -#![recursion_limit = "512"] +// The recursion_limit is mainly triggered by the json!() macro. +// The more key/value pairs there are the more recursion occurs. +// We want to keep this as low as possible, but not higher then 128. +// If you go above 128 it will cause rust-analyzer to fail, +#![recursion_limit = "87"] extern crate openssl; #[macro_use] diff --git a/src/util.rs b/src/util.rs @@ -282,9 +282,9 @@ pub fn delete_file(path: &str) -> IOResult<()> { res } -const UNITS: [&str; 6] = ["bytes", "KB", "MB", "GB", "TB", "PB"]; - pub fn get_display_size(size: i32) -> String { + const UNITS: [&str; 6] = ["bytes", "KB", "MB", "GB", "TB", "PB"]; + let mut size: f64 = size.into(); let mut unit_counter = 0; @@ -359,10 +359,10 @@ where try_parse_string(get_env_str_value(key)) } -const TRUE_VALUES: &[&str] = &["true", "t", "yes", "y", "1"]; -const FALSE_VALUES: &[&str] = &["false", "f", "no", "n", "0"]; - pub fn get_env_bool(key: &str) -> Option<bool> { + const TRUE_VALUES: &[&str] = &["true", "t", "yes", "y", "1"]; + const FALSE_VALUES: &[&str] = &["false", "f", "no", "n", "0"]; + match get_env_str_value(key) { Some(val) if TRUE_VALUES.contains(&val.to_lowercase().as_ref()) => Some(true), Some(val) if FALSE_VALUES.contains(&val.to_lowercase().as_ref()) => Some(false), @@ -375,7 +375,6 @@ pub fn get_env_bool(key: &str) -> Option<bool> { // use chrono::{DateTime, Local, NaiveDateTime, TimeZone}; -use chrono_tz::Tz; /// Formats a UTC-offset `NaiveDateTime` in the format used by Bitwarden API /// responses with "date" fields (`CreationDate`, `RevisionDate`, etc.). @@ -393,7 +392,7 @@ pub fn format_datetime_local(dt: &DateTime<Local>, fmt: &str) -> String { // Try parsing the `TZ` environment variable to enable formatting `%Z` as // a time zone abbreviation. if let Ok(tz) = env::var("TZ") { - if let Ok(tz) = tz.parse::<Tz>() { + if let Ok(tz) = tz.parse::<chrono_tz::Tz>() { return dt.with_timezone(&tz).format(fmt).to_string(); } } @@ -442,7 +441,7 @@ use serde_json::{self, Value}; pub type JsonMap = serde_json::Map<String, Value>; -#[derive(PartialEq, Serialize, Deserialize)] +#[derive(Serialize, Deserialize)] pub struct UpCase<T: DeserializeOwned> { #[serde(deserialize_with = "upcase_deserialize")] #[serde(flatten)] @@ -517,6 +516,8 @@ fn upcase_value(value: Value) -> Value { } } +// Inner function to handle some speciale case for the 'ssn' key. +// This key is part of the Identity Cipher (Social Security Number) fn _process_key(key: &str) -> String { match key.to_lowercase().as_ref() { "ssn" => "SSN".into(),