mirror of
https://github.com/dani-garcia/vaultwarden.wiki.git
synced 2026-11-04 21:45:11 +02:00
Gate v2 logins on upstream's v2 encryption check
This commit is contained in:
2 files changed
+35
-5
No files matched your search
+5
-5
@@ -518,13 +518,13 @@ async fn password_login(
|
|||||||
authenticated_response(&user, &mut device, auth_tokens, twofactor_token, conn, ip).await
|
authenticated_response(&user, &mut device, auth_tokens, twofactor_token, conn, ip).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like upstream's `ClientVersionValidator`, a V2 account logs in only from a client that sends its version and is at
|
/// Like upstream's `ClientVersionValidator`, a V2 account ([`User::has_v2_encryption`]) logs in only from a client that
|
||||||
/// least 2025.11.0 (upstream also refuses a missing header for V1 accounts). Called right after the credentials are
|
/// sends its version and is at least 2025.11.0 (upstream also refuses a missing header for V1 accounts). Called right
|
||||||
/// checked, like upstream, so that it doesn't tell anyone else which accounts are V2.
|
/// after the credentials are checked, like upstream, so that it doesn't tell anyone else which accounts are V2.
|
||||||
///
|
///
|
||||||
/// Ref: <https://github.com/bitwarden/server/blob/2028f0a5cc9d8ab8ff8475029085f29f81483598/src/Identity/IdentityServer/RequestValidators/ClientVersionValidator.cs#L42-L69>
|
/// Ref: <https://github.com/bitwarden/server/blob/8da186ad73f80d37157fe6fd42323e4284e83ec1/src/Identity/IdentityServer/RequestValidators/ClientVersionValidator.cs#L31-L72>
|
||||||
fn check_client_version(user: &User, client_version: Option<&semver::Version>, ip: &ClientIp) -> EmptyResult {
|
fn check_client_version(user: &User, client_version: Option<&semver::Version>, ip: &ClientIp) -> EmptyResult {
|
||||||
let Some((error, description)) = client_version_error(user.is_v2(), client_version) else {
|
let Some((error, description)) = client_version_error(user.has_v2_encryption(), client_version) else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
Err(crate::error::Error::from((
|
Err(crate::error::Error::from((
|
||||||
|
|||||||
@@ -194,6 +194,19 @@ impl User {
|
|||||||
self.signed_public_key.is_some() && self.security_state.is_some() && self.security_version.is_some()
|
self.signed_public_key.is_some() && self.security_state.is_some() && self.security_version.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Upstream's `HasV2Encryption`: a private key wrapped as `CoseEncrypt0B64` (type 7) and security version 2.
|
||||||
|
/// Upstream only uses it to decide which accounts need a v2-capable client.
|
||||||
|
///
|
||||||
|
/// Ref: <https://github.com/bitwarden/server/blob/8da186ad73f80d37157fe6fd42323e4284e83ec1/src/Core/Entities/User.cs#L245-L278>
|
||||||
|
pub fn has_v2_encryption(&self) -> bool {
|
||||||
|
self.security_version == Some(2)
|
||||||
|
&& self
|
||||||
|
.private_key
|
||||||
|
.as_deref()
|
||||||
|
.and_then(|private_key| private_key.split_once('.'))
|
||||||
|
.is_some_and(|(enc_type, _)| enc_type.parse::<u8>() == Ok(7))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_valid_password(&self, password: &str) -> bool {
|
pub fn check_valid_password(&self, password: &str) -> bool {
|
||||||
crypto::verify_password_hash(
|
crypto::verify_password_hash(
|
||||||
password.as_bytes(),
|
password.as_bytes(),
|
||||||
@@ -751,4 +764,21 @@ mod tests {
|
|||||||
// An absent key id stays optional
|
// An absent key id stays optional
|
||||||
assert_eq!(serde_json::from_str::<Option<KeyId>>("null").unwrap(), None);
|
assert_eq!(serde_json::from_str::<Option<KeyId>>("null").unwrap(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_has_v2_encryption() {
|
||||||
|
let user = |private_key: Option<&str>, security_version: Option<i32>| {
|
||||||
|
let mut user = User::new("user@example.com", None);
|
||||||
|
user.private_key = private_key.map(String::from);
|
||||||
|
user.security_version = security_version;
|
||||||
|
user
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(user(Some("7.cose"), Some(2)).has_v2_encryption());
|
||||||
|
assert!(!user(Some("7.cose"), Some(1)).has_v2_encryption());
|
||||||
|
assert!(!user(Some("7.cose"), None).has_v2_encryption());
|
||||||
|
assert!(!user(Some("2.iv|data|mac"), Some(2)).has_v2_encryption());
|
||||||
|
assert!(!user(Some("7"), Some(2)).has_v2_encryption());
|
||||||
|
assert!(!user(None, Some(2)).has_v2_encryption());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user