diff --git a/src/api/admin.rs b/src/api/admin.rs index e8f762eb..7f5a9250 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -403,7 +403,7 @@ async fn delete_user(user_id: UserId, token: AdminToken, mut conn: DbConn) -> Em for membership in memberships { log_event( - EventType::OrganizationUserDeleted as i32, + EventType::OrganizationUserRemoved as i32, &membership.uuid, &membership.org_uuid, &ACTING_ADMIN_USER.into(), diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index dbaccdde..a959064b 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -303,11 +303,7 @@ async fn post_set_password(data: Json, headers: Headers, mut co Membership::accept_user_invitations(&user.uuid, &mut conn).await?; } - log_user_event(EventType::UserChangedPassword as i32, &user.uuid, headers.device.atype, &headers.ip.ip, &mut conn) - .await; - user.save(&mut conn).await?; - Ok(Json(json!({ "Object": "set-password", "CaptchaBypassToken": "", @@ -1299,15 +1295,6 @@ async fn post_auth_request( nt.send_auth_request(&user.uuid, &auth_request.uuid, &data.device_identifier, &mut conn).await; - log_user_event( - EventType::UserRequestedDeviceApproval as i32, - &user.uuid, - client_headers.device_type, - &client_headers.ip.ip, - &mut conn, - ) - .await; - Ok(Json(json!({ "id": auth_request.uuid, "publicKey": auth_request.public_key, @@ -1389,26 +1376,9 @@ async fn put_auth_request( ant.send_auth_response(&auth_request.user_uuid, &auth_request.uuid).await; nt.send_auth_response(&auth_request.user_uuid, &auth_request.uuid, &data.device_identifier, &mut conn).await; - - log_user_event( - EventType::OrganizationUserApprovedAuthRequest as i32, - &headers.user.uuid, - headers.device.atype, - &headers.ip.ip, - &mut conn, - ) - .await; } else { // If denied, there's no reason to keep the request auth_request.delete(&mut conn).await?; - log_user_event( - EventType::OrganizationUserRejectedAuthRequest as i32, - &headers.user.uuid, - headers.device.atype, - &headers.ip.ip, - &mut conn, - ) - .await; } Ok(Json(json!({ diff --git a/src/api/core/events.rs b/src/api/core/events.rs index 3a7d41f0..012f46cc 100644 --- a/src/api/core/events.rs +++ b/src/api/core/events.rs @@ -245,8 +245,8 @@ async fn _log_user_event( ip: &IpAddr, conn: &mut DbConn, ) { - let memberships = Membership::find_by_user(user_id, conn).await; - let mut events: Vec = Vec::with_capacity(memberships.len() + 1); // We need an event per org and one without an org + let orgs = Membership::get_orgs_by_user(user_id, conn).await; + let mut events: Vec = Vec::with_capacity(orgs.len() + 1); // We need an event per org and one without an org // Upstream saves the event also without any org_id. let mut event = Event::new(event_type, event_date); @@ -257,11 +257,10 @@ async fn _log_user_event( events.push(event); // For each org a user is a member of store these events per org - for membership in memberships { + for org_id in orgs { let mut event = Event::new(event_type, event_date); event.user_uuid = Some(user_id.clone()); - event.org_uuid = Some(membership.org_uuid); - event.org_user_uuid = Some(membership.uuid); + event.org_uuid = Some(org_id); event.act_user_uuid = Some(user_id.clone()); event.device_type = Some(device_type); event.ip_address = Some(ip.to_string()); diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 944e28d3..82656d88 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -254,7 +254,7 @@ async fn leave_organization(org_id: OrganizationId, headers: Headers, mut conn: } log_event( - EventType::OrganizationUserLeft as i32, + EventType::OrganizationUserRemoved as i32, &member.uuid, &org_id, &headers.user.uuid, diff --git a/src/auth.rs b/src/auth.rs index d7a5af35..37accb16 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -620,29 +620,10 @@ pub struct OrgHeaders { pub device: Device, pub user: User, pub membership_type: MembershipType, - pub membership_status: MembershipStatus, pub membership: Membership, pub ip: ClientIp, } -impl OrgHeaders { - fn is_member(&self) -> bool { - // NOTE: we don't care about MembershipStatus at the moment because this is only used - // where an invited, accepted or confirmed user is expected if this ever changes or - // if from_i32 is changed to return Some(Revoked) this check needs to be changed accordingly - self.membership_type >= MembershipType::User - } - fn is_confirmed_and_admin(&self) -> bool { - self.membership_status == MembershipStatus::Confirmed && self.membership_type >= MembershipType::Admin - } - fn is_confirmed_and_manager(&self) -> bool { - self.membership_status == MembershipStatus::Confirmed && self.membership_type >= MembershipType::Manager - } - fn is_confirmed_and_owner(&self) -> bool { - self.membership_status == MembershipStatus::Confirmed && self.membership_type == MembershipType::Owner - } -} - #[rocket::async_trait] impl<'r> FromRequest<'r> for OrgHeaders { type Error = &'static str; @@ -671,8 +652,15 @@ impl<'r> FromRequest<'r> for OrgHeaders { }; let user = headers.user; - let Some(membership) = Membership::find_by_user_and_org(&user.uuid, &org_id, &mut conn).await else { - err_handler!("The current user isn't member of the organization"); + let membership = match Membership::find_by_user_and_org(&user.uuid, &org_id, &mut conn).await { + Some(member) => { + if member.status == MembershipStatus::Confirmed as i32 { + member + } else { + err_handler!("The current user isn't confirmed member of the organization") + } + } + None => err_handler!("The current user isn't member of the organization"), }; Outcome::Success(Self { @@ -680,22 +668,13 @@ impl<'r> FromRequest<'r> for OrgHeaders { device: headers.device, user, membership_type: { - if let Some(member_type) = MembershipType::from_i32(membership.atype) { - member_type + if let Some(org_usr_type) = MembershipType::from_i32(membership.atype) { + org_usr_type } else { // This should only happen if the DB is corrupted err_handler!("Unknown user type in the database") } }, - membership_status: { - if let Some(member_status) = MembershipStatus::from_i32(membership.status) { - // NOTE: add additional check for revoked if from_i32 is ever changed - // to return Revoked status. - member_status - } else { - err_handler!("User status is either revoked or invalid.") - } - }, membership, ip: headers.ip, }) @@ -720,7 +699,7 @@ impl<'r> FromRequest<'r> for AdminHeaders { async fn from_request(request: &'r Request<'_>) -> Outcome { let headers = try_outcome!(OrgHeaders::from_request(request).await); - if headers.is_confirmed_and_admin() { + if headers.membership_type >= MembershipType::Admin { Outcome::Success(Self { host: headers.host, device: headers.device, @@ -782,7 +761,7 @@ impl<'r> FromRequest<'r> for ManagerHeaders { async fn from_request(request: &'r Request<'_>) -> Outcome { let headers = try_outcome!(OrgHeaders::from_request(request).await); - if headers.is_confirmed_and_manager() { + if headers.membership_type >= MembershipType::Manager { match get_col_id(request) { Some(col_id) => { let mut conn = match DbConn::from_request(request).await { @@ -837,7 +816,7 @@ impl<'r> FromRequest<'r> for ManagerHeadersLoose { async fn from_request(request: &'r Request<'_>) -> Outcome { let headers = try_outcome!(OrgHeaders::from_request(request).await); - if headers.is_confirmed_and_manager() { + if headers.membership_type >= MembershipType::Manager { Outcome::Success(Self { host: headers.host, device: headers.device, @@ -900,7 +879,7 @@ impl<'r> FromRequest<'r> for OwnerHeaders { async fn from_request(request: &'r Request<'_>) -> Outcome { let headers = try_outcome!(OrgHeaders::from_request(request).await); - if headers.is_confirmed_and_owner() { + if headers.membership_type == MembershipType::Owner { Outcome::Success(Self { device: headers.device, user: headers.user, @@ -925,7 +904,7 @@ impl<'r> FromRequest<'r> for OrgMemberHeaders { async fn from_request(request: &'r Request<'_>) -> Outcome { let headers = try_outcome!(OrgHeaders::from_request(request).await); - if headers.is_member() { + if headers.membership_type >= MembershipType::User { Outcome::Success(Self { host: headers.host, user: headers.user, diff --git a/src/db/models/auth_request.rs b/src/db/models/auth_request.rs index 7f406581..d8ca3fac 100644 --- a/src/db/models/auth_request.rs +++ b/src/db/models/auth_request.rs @@ -150,7 +150,6 @@ impl AuthRequest { auth_requests::table .filter(auth_requests::user_uuid.eq(user_uuid)) .filter(auth_requests::request_device_identifier.eq(device_uuid)) - .filter(auth_requests::approved.is_null()) .order_by(auth_requests::creation_date.desc()) .first::(conn).ok().from_db() }} diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index d9dbd28d..c751491e 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -142,7 +142,7 @@ impl Cipher { sync_type: CipherSyncType, conn: &mut DbConn, ) -> Value { - use crate::util::{format_date, validate_and_format_date}; + use crate::util::format_date; let mut attachments_json: Value = Value::Null; if let Some(cipher_sync_data) = cipher_sync_data { @@ -220,7 +220,7 @@ impl Cipher { }) .map(|mut d| match d.get("lastUsedDate").and_then(|l| l.as_str()) { Some(l) => { - d["lastUsedDate"] = json!(validate_and_format_date(l)); + d["lastUsedDate"] = json!(crate::util::validate_and_format_date(l)); d } _ => { @@ -261,11 +261,6 @@ impl Cipher { type_data_json["uri"] = uris[0]["uri"].clone(); } } - - // Check if `passwordRevisionDate` is a valid date, else convert it - if let Some(pw_revision) = type_data_json["passwordRevisionDate"].as_str() { - type_data_json["passwordRevisionDate"] = json!(validate_and_format_date(pw_revision)); - } } // Fix secure note issues when data is invalid diff --git a/src/db/models/event.rs b/src/db/models/event.rs index ed4582b1..5fea7160 100644 --- a/src/db/models/event.rs +++ b/src/db/models/event.rs @@ -49,8 +49,6 @@ pub enum EventType { UserClientExportedVault = 1007, // UserUpdatedTempPassword = 1008, // Not supported // UserMigratedKeyToKeyConnector = 1009, // Not supported - UserRequestedDeviceApproval = 1010, - // UserTdeOffboardingPasswordSet = 1011, // Not supported // Cipher CipherCreated = 1100, @@ -71,7 +69,6 @@ pub enum EventType { CipherSoftDeleted = 1115, CipherRestored = 1116, CipherClientToggledCardNumberVisible = 1117, - CipherClientToggledTOTPSeedVisible = 1118, // Collection CollectionCreated = 1300, @@ -97,10 +94,6 @@ pub enum EventType { // OrganizationUserFirstSsoLogin = 1510, // Not supported OrganizationUserRevoked = 1511, OrganizationUserRestored = 1512, - OrganizationUserApprovedAuthRequest = 1513, - OrganizationUserRejectedAuthRequest = 1514, - OrganizationUserDeleted = 1515, - OrganizationUserLeft = 1516, // Organization OrganizationUpdated = 1600, @@ -112,7 +105,6 @@ pub enum EventType { // OrganizationEnabledKeyConnector = 1606, // Not supported // OrganizationDisabledKeyConnector = 1607, // Not supported // OrganizationSponsorshipsSynced = 1608, // Not supported - // OrganizationCollectionManagementUpdated = 1609, // Not supported // Policy PolicyUpdated = 1700, @@ -125,13 +117,6 @@ pub enum EventType { // ProviderOrganizationAdded = 1901, // Not supported // ProviderOrganizationRemoved = 1902, // Not supported // ProviderOrganizationVaultAccessed = 1903, // Not supported - - // OrganizationDomainAdded = 2000, // Not supported - // OrganizationDomainRemoved = 2001, // Not supported - // OrganizationDomainVerified = 2002, // Not supported - // OrganizationDomainNotVerified = 2003, // Not supported - - // SecretRetrieved = 2100, // Not supported } /// Local methods diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index e9635fd7..9d12b26c 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -55,7 +55,6 @@ db_object! { } // https://github.com/bitwarden/server/blob/b86a04cef9f1e1b82cf18e49fc94e017c641130c/src/Core/Enums/OrganizationUserStatusType.cs -#[derive(PartialEq)] pub enum MembershipStatus { Revoked = -1, Invited = 0, @@ -63,19 +62,6 @@ pub enum MembershipStatus { Confirmed = 2, } -impl MembershipStatus { - pub fn from_i32(status: i32) -> Option { - match status { - 0 => Some(Self::Invited), - 1 => Some(Self::Accepted), - 2 => Some(Self::Confirmed), - // NOTE: we don't care about revoked members where this is used - // if this ever changes also adapt the OrgHeaders check. - _ => None, - } - } -} - #[derive(Copy, Clone, PartialEq, Eq, num_derive::FromPrimitive)] pub enum MembershipType { Owner = 0, diff --git a/src/util.rs b/src/util.rs index 995077ab..99626cc3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -55,10 +55,7 @@ impl Fairing for AppHeaders { res.set_raw_header("Referrer-Policy", "same-origin"); res.set_raw_header("X-Content-Type-Options", "nosniff"); res.set_raw_header("X-Robots-Tag", "noindex, nofollow"); - - if !res.headers().get_one("Content-Type").is_some_and(|v| v.starts_with("image/")) { - res.set_raw_header("Cross-Origin-Resource-Policy", "same-origin"); - } + res.set_raw_header("Cross-Origin-Resource-Policy", "same-origin"); // Obsolete in modern browsers, unsafe (XS-Leak), and largely replaced by CSP res.set_raw_header("X-XSS-Protection", "0");