diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 5c1ccedb..46f827a4 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -646,6 +646,19 @@ fn accept_invite(_org_id: String, _org_user_id: String, data: JsonUpcase p.enabled, + None => false, + }; + + if org_twofactor_policy_enabled && user_twofactor_disabled { + err!("You cannot join this organization until you enable two-step login on your user account.") + } + user_org.status = UserOrgStatus::Accepted as i32; user_org.save(&conn)?; } @@ -998,6 +1011,24 @@ fn put_policy( None => err!("Invalid policy type"), }; + if pol_type_enum == OrgPolicyType::TwoFactorAuthentication && data.enabled { + let org_list = UserOrganization::find_by_org(&org_id, &conn); + + for user_org in org_list.into_iter() { + let user_twofactor_disabled = TwoFactor::find_by_user(&user_org.user_uuid, &conn).is_empty(); + + if user_twofactor_disabled && user_org.atype < UserOrgType::Admin { + if CONFIG.mail_enabled() { + let org = Organization::find_by_uuid(&user_org.org_uuid, &conn).unwrap(); + let user = User::find_by_uuid(&user_org.user_uuid, &conn).unwrap(); + + mail::send_2fa_removed_from_org(&user.email, &org.name)?; + } + user_org.delete(&conn)?; + } + } + } + let mut policy = match OrgPolicy::find_by_org_and_type(&org_id, pol_type, &conn) { Some(p) => p, None => OrgPolicy::new(org_id, pol_type_enum, "{}".to_string()), diff --git a/src/api/core/two_factor/mod.rs b/src/api/core/two_factor/mod.rs index 83661e37..d8448f45 100644 --- a/src/api/core/two_factor/mod.rs +++ b/src/api/core/two_factor/mod.rs @@ -7,10 +7,8 @@ use crate::{ api::{JsonResult, JsonUpcase, NumberOrString, PasswordData}, auth::Headers, crypto, - db::{ - models::{TwoFactor, User}, - DbConn, - }, + db::{models::*, DbConn}, + mail, CONFIG, }; pub mod authenticator; @@ -130,6 +128,23 @@ fn disable_twofactor(data: JsonUpcase, headers: Headers, c twofactor.delete(&conn)?; } + let twofactor_disabled = TwoFactor::find_by_user(&user.uuid, &conn).is_empty(); + + if twofactor_disabled { + let policy_type = OrgPolicyType::TwoFactorAuthentication; + let org_list = UserOrganization::find_by_user_and_policy(&user.uuid, policy_type, &conn); + + for user_org in org_list.into_iter() { + if user_org.atype < UserOrgType::Admin { + if CONFIG.mail_enabled() { + let org = Organization::find_by_uuid(&user_org.org_uuid, &conn).unwrap(); + mail::send_2fa_removed_from_org(&user.email, &org.name)?; + } + user_org.delete(&conn)?; + } + } + } + Ok(Json(json!({ "Enabled": false, "Type": type_, diff --git a/src/config.rs b/src/config.rs index 6eea8c67..6e0c9f65 100644 --- a/src/config.rs +++ b/src/config.rs @@ -858,6 +858,7 @@ where reg!("email/new_device_logged_in", ".html"); reg!("email/pw_hint_none", ".html"); reg!("email/pw_hint_some", ".html"); + reg!("email/send_2fa_removed_from_org", ".html"); reg!("email/send_org_invite", ".html"); reg!("email/twofactor_email", ".html"); reg!("email/verify_email", ".html"); diff --git a/src/db/models/org_policy.rs b/src/db/models/org_policy.rs index 06d7a5fd..34eaedb1 100644 --- a/src/db/models/org_policy.rs +++ b/src/db/models/org_policy.rs @@ -22,7 +22,7 @@ db_object! { } } -#[derive(Copy, Clone, num_derive::FromPrimitive)] +#[derive(Copy, Clone, PartialEq, num_derive::FromPrimitive)] pub enum OrgPolicyType { TwoFactorAuthentication = 0, MasterPassword = 1, diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index e0c87977..a4fefd8f 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -2,7 +2,7 @@ use num_traits::FromPrimitive; use serde_json::Value; use std::cmp::Ordering; -use super::{CollectionUser, OrgPolicy, User}; +use super::{CollectionUser, OrgPolicy, OrgPolicyType, User}; db_object! { #[derive(Identifiable, Queryable, Insertable, AsChangeset)] @@ -535,6 +535,25 @@ impl UserOrganization { }} } + pub fn find_by_user_and_policy(user_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> Vec { + db_run! { conn: { + users_organizations::table + .inner_join( + org_policies::table.on( + org_policies::org_uuid.eq(users_organizations::org_uuid) + .and(users_organizations::user_uuid.eq(user_uuid)) + .and(org_policies::atype.eq(policy_type as i32)) + .and(org_policies::enabled.eq(true))) + ) + .filter( + users_organizations::status.eq(UserOrgStatus::Confirmed as i32) + ) + .select(users_organizations::all_columns) + .load::(conn) + .unwrap_or_default().from_db() + }} + } + pub fn find_by_cipher_and_org(cipher_uuid: &str, org_uuid: &str, conn: &DbConn) -> Vec { db_run! { conn: { users_organizations::table diff --git a/src/error.rs b/src/error.rs index f441f55f..f829ec63 100644 --- a/src/error.rs +++ b/src/error.rs @@ -166,7 +166,7 @@ fn _serialize(e: &impl serde::Serialize, _msg: &str) -> String { fn _api_error(_: &impl std::any::Any, msg: &str) -> String { let json = json!({ - "Message": "", + "Message": msg, "error": "", "error_description": "", "ValidationErrors": {"": [ msg ]}, diff --git a/src/mail.rs b/src/mail.rs index 1cd875b8..094f5125 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -180,6 +180,18 @@ pub fn send_welcome_must_verify(address: &str, uuid: &str) -> EmptyResult { send_email(address, &subject, body_html, body_text) } +pub fn send_2fa_removed_from_org(address: &str, org_name: &str) -> EmptyResult { + let (subject, body_html, body_text) = get_text( + "email/send_2fa_removed_from_org", + json!({ + "url": CONFIG.domain(), + "org_name": org_name, + }), + )?; + + send_email(address, &subject, body_html, body_text) +} + pub fn send_invite( address: &str, uuid: &str, diff --git a/src/static/templates/email/send_2fa_removed_from_org.hbs b/src/static/templates/email/send_2fa_removed_from_org.hbs new file mode 100644 index 00000000..95d41b97 --- /dev/null +++ b/src/static/templates/email/send_2fa_removed_from_org.hbs @@ -0,0 +1,9 @@ +Removed from {{{org_name}}} + +You have been removed from organization *{{org_name}}* because your account does not have Two-step Login enabled. + + +You can enable Two-step Login in your account settings. + +=== +Github: https://github.com/dani-garcia/vaultwarden diff --git a/src/static/templates/email/send_2fa_removed_from_org.html.hbs b/src/static/templates/email/send_2fa_removed_from_org.html.hbs new file mode 100644 index 00000000..e881fd99 --- /dev/null +++ b/src/static/templates/email/send_2fa_removed_from_org.html.hbs @@ -0,0 +1,129 @@ +Removed from {{{org_name}}} + + + + + + Vaultwarden + + + + + + + + + + +
+ + + + +
+ + + + +
+ + + + + + + +
+ You have been removed from organization {{org_name}} because your account does not have Two-step Login enabled. +
+ You can enable Two-step Login in your account settings. +
+
+ + + + + +
+
+ +