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 8defb7539802dd914644908d2444cfbaab88764a
parent 0dadd7b31887706d3653243742b87a9221b7ff50
Author: Zack Newman <zack@philomathiclife.com>
Date:   Wed, 21 Aug 2024 18:56:05 -0600

update deps. handle lints. remove attestation

Diffstat:
MCargo.toml | 37+++++++++++++++++++++----------------
Mconfig.toml | 1-
Msrc/api/core/accounts.rs | 6+++---
Msrc/api/core/two_factor/authenticator.rs | 6+++++-
Msrc/api/core/two_factor/webauthn.rs | 60++++--------------------------------------------------------
Msrc/auth.rs | 15+++++++++++----
Msrc/config.rs | 5++---
Msrc/main.rs | 2++
8 files changed, 48 insertions(+), 84 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -8,36 +8,41 @@ keywords = ["password", "vaultwarden"] license = "AGPL-3.0-only" name = "vw_small" publish = false +readme = "README.md" repository = "https://git.philomathiclife.com/repos/vw_small/" -version = "2.0.1" +rust-version = "1.78.0" +version = "3.0.0" -[features] -priv_sep = ["dep:priv_sep"] +[badges] +maintenance = { status = "actively-developed" } [target.'cfg(target_os = "openbsd")'.dependencies] -priv_sep = { version = "1.0.1", default-features = false, features = ["openbsd"], optional = true } +priv_sep = { version = "2.0.0", default-features = false, features = ["openbsd"], optional = true } [dependencies] chrono = { version = "0.4.38", default-features = false, features = ["serde"] } data-encoding = { version = "2.6.0", default-features = false } -diesel = { version = "2.1.6", default-features = false, features = ["32-column-tables", "chrono", "r2d2", "sqlite"] } +diesel = { version = "2.2.2", default-features = false, features = ["32-column-tables", "chrono", "r2d2", "sqlite"] } jsonwebtoken = { version = "9.3.0", default-features = false, features = ["use_pem"] } -libsqlite3-sys = { version = "0.28.0", default-features = false, features = ["bundled"] } -openssl = { version = "0.10.64", default-features = false } -paste = { version = "1.0.14", default-features = false } +libsqlite3-sys = { version = "0.29.0", default-features = false, features = ["bundled"] } +openssl = { version = "0.10.66", default-features = false } +paste = { version = "1.0.15", default-features = false } rand = { version = "0.8.5", default-features = false, features = ["small_rng"] } ring = { version = "0.17.8", default-features = false } -rocket = { version = "0.5.0", default-features = false, features = ["json", "tls"] } -semver = { version = "1.0.22", default-features = false } -serde = { version = "1.0.200", default-features = false } -serde_json = { version = "1.0.116", default-features = false } -tokio = { version = "1.37.0", default-features = false } -toml = { version = "0.8.12", default-features = false, features = ["parse"] } +rocket = { version = "0.5.1", default-features = false, features = ["json", "tls"] } +semver = { version = "1.0.23", default-features = false } +serde = { version = "1.0.208", default-features = false } +serde_json = { version = "1.0.125", default-features = false } +tokio = { version = "1.39.3", default-features = false } +toml = { version = "0.8.19", default-features = false, features = ["parse"] } totp-lite = { version = "2.0.1", default-features = false } -url = { version = "2.5.0", default-features = false } -uuid = { version = "1.8.0", default-features = false, features = ["v4"] } +url = { version = "2.5.2", default-features = false } +uuid = { version = "1.10.0", default-features = false, features = ["v4"] } webauthn-rs = { version = "0.4.8", default-features = false, features = ["danger-allow-state-serialisation", "danger-user-presence-only-security-keys"] } +[features] +priv_sep = ["dep:priv_sep"] + [patch.crates-io] webauthn-rs-core = { git = "https://git.philomathiclife.com/repos/webauthn-rs-core", tag = "v0.4.10" } webauthn-rs-proto = { git = "https://git.philomathiclife.com/repos/webauthn-rs-proto", tag = "v0.4.10" } diff --git a/config.toml b/config.toml @@ -6,7 +6,6 @@ ip="fdb5:d87:ae42:1::1" #password_iterations=600000 port=8443 #web_vault_enabled=true -webauthn_require_yubi=true workers=4 [tls] cert="/etc/ssl/pmd.philomathiclife.com.fullchain" diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs @@ -580,8 +580,8 @@ struct KnownDevice { #[rocket::async_trait] impl<'r> FromRequest<'r> for KnownDevice { type Error = &'static str; - async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> { - let email = if let Some(email_b64) = req.headers().get_one("X-Request-Email") { + async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { + let email = if let Some(email_b64) = request.headers().get_one("X-Request-Email") { let Ok(email_bytes) = data_encoding::BASE64URL_NOPAD.decode(email_b64.as_bytes()) else { return Outcome::Error(( @@ -602,7 +602,7 @@ impl<'r> FromRequest<'r> for KnownDevice { return Outcome::Error((Status::BadRequest, "X-Request-Email value is required")); }; - let uuid = if let Some(uuid) = req.headers().get_one("X-Device-Identifier") { + let uuid = if let Some(uuid) = request.headers().get_one("X-Device-Identifier") { uuid.to_owned() } else { return Outcome::Error((Status::BadRequest, "X-Device-Identifier value is required")); diff --git a/src/api/core/two_factor/authenticator.rs b/src/api/core/two_factor/authenticator.rs @@ -100,7 +100,11 @@ pub async fn validate_totp_code_str( } validate_totp_code(user_uuid, totp_code, secret, ip, conn).await } -#[allow(clippy::integer_division, clippy::redundant_else)] +#[allow( + clippy::integer_division, + clippy::integer_division_remainder_used, + clippy::redundant_else +)] async fn validate_totp_code( user_uuid: String, totp_code: &str, diff --git a/src/api/core/two_factor/webauthn.rs b/src/api/core/two_factor/webauthn.rs @@ -12,8 +12,8 @@ use rocket::serde::json::Json; use rocket::Route; use url::Url; use webauthn_rs::prelude::{ - AttestationCa, AttestationCaList, AuthenticatorAttachment, PublicKeyCredential, - RegisterPublicKeyCredential, Uuid, Webauthn, WebauthnBuilder, WebauthnError, + PublicKeyCredential, RegisterPublicKeyCredential, Uuid, Webauthn, WebauthnBuilder, + WebauthnError, }; pub fn routes() -> Vec<Route> { @@ -49,54 +49,6 @@ async fn get_webauthn( "Object": "twoFactorWebAuthn" }))) } -// When YubiKey enforcement is enabled, we generate the allowed list of attestation CAs. -fn get_attestation_list() -> Option<AttestationCaList> { - config::get_config().webauthn_require_yubi.then(|| { - let mut attest_list = AttestationCaList::default(); - let mut ca = AttestationCa::yubico_u2f_root_ca_serial_457200631(); - ca.aaguids.clear(); - // We only allow FIDO2 YubiKeys with firmware 5.2.a, 5.4.b, 5.5.c, or 5.6.d (https://support.yubico.com/hc/en-us/articles/360016648959-YubiKey-Hardware-FIDO2-AAGUIDs). - // YubiKey 5 (USB-A, No NFC), YubiKey 5 Nano, YubiKey 5 Nano CSPN, YubiKey 5C, YubiKey 5C CSPN, - // YubiKey 5C Nano, and YubiKey 5C Nano CSPN. - ca.aaguids - .insert(Uuid::try_parse("ee882879-721c-4913-9775-3dfcce97072a").expect("invaild UUID")); - // YubiKey 5 NFC, YubiKey 5 NFC CSPN, YubiKey 5C NFC, and YubiKey 5C NFC CSPN. - ca.aaguids - .insert(Uuid::try_parse("2fc0579f-8113-47ea-b116-bb5a8db9202a").expect("invaild UUID")); - // YubiKey 5 NFC FIPS and YubiKey 5C NFC FIPS. - ca.aaguids - .insert(Uuid::try_parse("c1f9a0bc-1dd2-404a-b27f-8e29047a43fd").expect("invaild UUID")); - // YubiKey 5 Nano FIPS, YubiKey 5C FIPS, and YubiKey 5C Nano FIPS. - ca.aaguids - .insert(Uuid::try_parse("73bb0cd4-e502-49b8-9c6f-b59445bf720b").expect("invaild UUID")); - // YubiKey 5Ci and YubiKey 5Ci CSPN. - ca.aaguids - .insert(Uuid::try_parse("c5ef55ff-ad9a-4b9f-b580-adebafe026d0").expect("invaild UUID")); - // YubiKey 5Ci FIPS. - ca.aaguids - .insert(Uuid::try_parse("85203421-48f9-4355-9bc8-8a53846e5083").expect("invaild UUID")); - // Security Key By Yubico. - ca.aaguids - .insert(Uuid::try_parse("b92c3f9a-c014-4056-887f-140a2501163b").expect("invaild UUID")); - // Security Key NFC (USB-A, USB-C). - ca.aaguids - .insert(Uuid::try_parse("149a2021-8ef6-4133-96b8-81f8d5b7f1f5").expect("invaild UUID")); - // YubiKey Bio Series. - ca.aaguids - .insert(Uuid::try_parse("d8522d9f-575b-4866-88a9-ba99fa02f35b").expect("invaild UUID")); - // Security Key NFC Black (USB-A, USB-C). - ca.aaguids - .insert(Uuid::try_parse("a4e9fc6d-4cbe-4758-b8ba-37598bb5bbaa").expect("invaild UUID")); - // Security Key NFC - Enterprise Edition (USB-A, USB-C). - ca.aaguids - .insert(Uuid::try_parse("0bb43545-fd2c-4185-87dd-feb0b2916ace").expect("invaild UUID")); - attest_list - .insert(ca) - .expect("unable to add attestation CAs"); - attest_list - }) -} - #[post("/two-factor/get-webauthn-challenge", data = "<data>")] async fn generate_webauthn_challenge( data: JsonUpcase<PasswordOrOtpData>, @@ -106,17 +58,13 @@ async fn generate_webauthn_challenge( let data: PasswordOrOtpData = data.into_inner().data; let user = headers.user; data.validate(&user)?; - let (attest_list, auth_plat) = get_attestation_list().map_or_else( - || (None, None), - |attest| (Some(attest), Some(AuthenticatorAttachment::CrossPlatform)), - ); let (challenge, registration) = build_webauthn()?.start_securitykey_registration( Uuid::try_parse(user.uuid.as_str()).expect("unable to create UUID"), user.email.as_str(), user.name.as_str(), Some(WebAuthn::get_all_credentials_by_user(&user.uuid, &conn).await?), - attest_list, - auth_plat, + None, + None, )?; WebAuthnChallenge::Reg(WebAuthnReg::new(user.uuid, &registration)?) .replace(&conn) diff --git a/src/auth.rs b/src/auth.rs @@ -289,9 +289,10 @@ impl<'r> FromRequest<'r> for Host { }) } } - pub struct ClientHeaders { + #[allow(dead_code)] pub host: String, + #[allow(dead_code)] pub device_type: i32, pub ip: ClientIp, } @@ -407,6 +408,7 @@ pub struct OrgHeaders { user: User, org_user_type: UserOrgType, org_user: UserOrganization, + #[allow(dead_code)] pub org_id: String, ip: ClientIp, } @@ -547,6 +549,7 @@ pub struct ManagerHeaders { host: String, device: Device, pub user: User, + #[allow(dead_code)] pub org_user_type: UserOrgType, ip: ClientIp, } @@ -666,9 +669,12 @@ impl ManagerHeaders { } pub struct OwnerHeaders { + #[allow(dead_code)] pub host: String, + #[allow(dead_code)] pub device: Device, pub user: User, + #[allow(dead_code)] pub ip: ClientIp, } @@ -703,8 +709,8 @@ pub struct ClientIp { impl<'r> FromRequest<'r> for ClientIp { type Error = (); #[allow(clippy::map_err_ignore, clippy::string_slice)] - async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> { - let ip = req.headers().get_one("X-Real-IP").and_then(|ip| { + async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { + let ip = request.headers().get_one("X-Real-IP").and_then(|ip| { ip.find(',') .map_or(ip, |idx| &ip[..idx]) .parse() @@ -712,13 +718,14 @@ impl<'r> FromRequest<'r> for ClientIp { .ok() }); let ip = ip - .or_else(|| req.remote().map(|r| r.ip())) + .or_else(|| request.remote().map(|r| r.ip())) .unwrap_or_else(|| "0.0.0.0".parse().unwrap()); Outcome::Success(Self { ip }) } } pub struct WsAccessTokenHeader { + #[allow(dead_code)] pub access_token: Option<String>, } diff --git a/src/config.rs b/src/config.rs @@ -66,6 +66,7 @@ impl From<ParseError> for ConfigErr { } } #[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] struct Tls { ciphers: Option<Vec<CipherSuite>>, cert: String, @@ -73,6 +74,7 @@ struct Tls { prefer_server_cipher_order: Option<bool>, } #[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] struct ConfigFile { database_max_conns: Option<NonZeroU8>, database_timeout: Option<u16>, @@ -82,7 +84,6 @@ struct ConfigFile { password_iterations: Option<u32>, port: u16, tls: Tls, - webauthn_require_yubi: Option<bool>, web_vault_enabled: Option<bool>, workers: Option<NonZeroU8>, } @@ -95,7 +96,6 @@ pub struct Config { pub password_iterations: u32, pub rocket: rocket::Config, pub web_vault_enabled: bool, - pub webauthn_require_yubi: bool, } impl Config { #[inline] @@ -172,7 +172,6 @@ impl Config { }, rocket, web_vault_enabled: config_file.web_vault_enabled.unwrap_or(true), - webauthn_require_yubi: config_file.webauthn_require_yubi.unwrap_or(false), }) } } diff --git a/src/main.rs b/src/main.rs @@ -1,7 +1,9 @@ #![deny( + unknown_lints, future_incompatible, let_underscore, nonstandard_style, + refining_impl_trait, rust_2018_compatibility, rust_2018_idioms, rust_2021_compatibility,