1 use serde::Deserialize; 2 use serde_json::Value; 3 4 use crate::api::EmptyResult; 5 use crate::db::DbConn; 6 use crate::error::MapResult; 7 use crate::util::UpCase; 8 9 use super::{Organization, UserOrgStatus, UserOrgType, UserOrganization}; 10 11 db_object! { 12 #[derive(Identifiable, Queryable, Insertable, Associations, AsChangeset)] 13 #[table_name = "org_policies"] 14 #[belongs_to(Organization, foreign_key = "org_uuid")] 15 #[primary_key(uuid)] 16 pub struct OrgPolicy { 17 pub uuid: String, 18 pub org_uuid: String, 19 pub atype: i32, 20 pub enabled: bool, 21 pub data: String, 22 } 23 } 24 25 #[derive(Copy, Clone, PartialEq, num_derive::FromPrimitive)] 26 pub enum OrgPolicyType { 27 TwoFactorAuthentication = 0, 28 MasterPassword = 1, 29 PasswordGenerator = 2, 30 SingleOrg = 3, 31 // RequireSso = 4, // Not currently supported. 32 PersonalOwnership = 5, 33 DisableSend = 6, 34 SendOptions = 7, 35 } 36 37 // https://github.com/bitwarden/server/blob/master/src/Core/Models/Data/SendOptionsPolicyData.cs 38 #[derive(Deserialize)] 39 #[allow(non_snake_case)] 40 pub struct SendOptionsPolicyData { 41 pub DisableHideEmail: bool, 42 } 43 44 /// Local methods 45 impl OrgPolicy { new(org_uuid: String, atype: OrgPolicyType, data: String) -> Self46 pub fn new(org_uuid: String, atype: OrgPolicyType, data: String) -> Self { 47 Self { 48 uuid: crate::util::get_uuid(), 49 org_uuid, 50 atype: atype as i32, 51 enabled: false, 52 data, 53 } 54 } 55 has_type(&self, policy_type: OrgPolicyType) -> bool56 pub fn has_type(&self, policy_type: OrgPolicyType) -> bool { 57 self.atype == policy_type as i32 58 } 59 to_json(&self) -> Value60 pub fn to_json(&self) -> Value { 61 let data_json: Value = serde_json::from_str(&self.data).unwrap_or(Value::Null); 62 json!({ 63 "Id": self.uuid, 64 "OrganizationId": self.org_uuid, 65 "Type": self.atype, 66 "Data": data_json, 67 "Enabled": self.enabled, 68 "Object": "policy", 69 }) 70 } 71 } 72 73 /// Database methods 74 impl OrgPolicy { save(&self, conn: &DbConn) -> EmptyResult75 pub fn save(&self, conn: &DbConn) -> EmptyResult { 76 db_run! { conn: 77 sqlite, mysql { 78 match diesel::replace_into(org_policies::table) 79 .values(OrgPolicyDb::to_db(self)) 80 .execute(conn) 81 { 82 Ok(_) => Ok(()), 83 // Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first. 84 Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => { 85 diesel::update(org_policies::table) 86 .filter(org_policies::uuid.eq(&self.uuid)) 87 .set(OrgPolicyDb::to_db(self)) 88 .execute(conn) 89 .map_res("Error saving org_policy") 90 } 91 Err(e) => Err(e.into()), 92 }.map_res("Error saving org_policy") 93 } 94 postgresql { 95 let value = OrgPolicyDb::to_db(self); 96 // We need to make sure we're not going to violate the unique constraint on org_uuid and atype. 97 // This happens automatically on other DBMS backends due to replace_into(). PostgreSQL does 98 // not support multiple constraints on ON CONFLICT clauses. 99 diesel::delete( 100 org_policies::table 101 .filter(org_policies::org_uuid.eq(&self.org_uuid)) 102 .filter(org_policies::atype.eq(&self.atype)), 103 ) 104 .execute(conn) 105 .map_res("Error deleting org_policy for insert")?; 106 107 diesel::insert_into(org_policies::table) 108 .values(&value) 109 .on_conflict(org_policies::uuid) 110 .do_update() 111 .set(&value) 112 .execute(conn) 113 .map_res("Error saving org_policy") 114 } 115 } 116 } 117 delete(self, conn: &DbConn) -> EmptyResult118 pub fn delete(self, conn: &DbConn) -> EmptyResult { 119 db_run! { conn: { 120 diesel::delete(org_policies::table.filter(org_policies::uuid.eq(self.uuid))) 121 .execute(conn) 122 .map_res("Error deleting org_policy") 123 }} 124 } 125 find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self>126 pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> { 127 db_run! { conn: { 128 org_policies::table 129 .filter(org_policies::uuid.eq(uuid)) 130 .first::<OrgPolicyDb>(conn) 131 .ok() 132 .from_db() 133 }} 134 } 135 find_by_org(org_uuid: &str, conn: &DbConn) -> Vec<Self>136 pub fn find_by_org(org_uuid: &str, conn: &DbConn) -> Vec<Self> { 137 db_run! { conn: { 138 org_policies::table 139 .filter(org_policies::org_uuid.eq(org_uuid)) 140 .load::<OrgPolicyDb>(conn) 141 .expect("Error loading org_policy") 142 .from_db() 143 }} 144 } 145 find_confirmed_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Self>146 pub fn find_confirmed_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Self> { 147 db_run! { conn: { 148 org_policies::table 149 .inner_join( 150 users_organizations::table.on( 151 users_organizations::org_uuid.eq(org_policies::org_uuid) 152 .and(users_organizations::user_uuid.eq(user_uuid))) 153 ) 154 .filter( 155 users_organizations::status.eq(UserOrgStatus::Confirmed as i32) 156 ) 157 .select(org_policies::all_columns) 158 .load::<OrgPolicyDb>(conn) 159 .expect("Error loading org_policy") 160 .from_db() 161 }} 162 } 163 find_by_org_and_type(org_uuid: &str, atype: i32, conn: &DbConn) -> Option<Self>164 pub fn find_by_org_and_type(org_uuid: &str, atype: i32, conn: &DbConn) -> Option<Self> { 165 db_run! { conn: { 166 org_policies::table 167 .filter(org_policies::org_uuid.eq(org_uuid)) 168 .filter(org_policies::atype.eq(atype)) 169 .first::<OrgPolicyDb>(conn) 170 .ok() 171 .from_db() 172 }} 173 } 174 delete_all_by_organization(org_uuid: &str, conn: &DbConn) -> EmptyResult175 pub fn delete_all_by_organization(org_uuid: &str, conn: &DbConn) -> EmptyResult { 176 db_run! { conn: { 177 diesel::delete(org_policies::table.filter(org_policies::org_uuid.eq(org_uuid))) 178 .execute(conn) 179 .map_res("Error deleting org_policy") 180 }} 181 } 182 183 /// Returns true if the user belongs to an org that has enabled the specified policy type, 184 /// and the user is not an owner or admin of that org. This is only useful for checking 185 /// applicability of policy types that have these particular semantics. is_applicable_to_user(user_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> bool186 pub fn is_applicable_to_user(user_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> bool { 187 // TODO: Should check confirmed and accepted users 188 for policy in OrgPolicy::find_confirmed_by_user(user_uuid, conn) { 189 if policy.enabled && policy.has_type(policy_type) { 190 let org_uuid = &policy.org_uuid; 191 if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, org_uuid, conn) { 192 if user.atype < UserOrgType::Admin { 193 return true; 194 } 195 } 196 } 197 } 198 false 199 } 200 201 /// Returns true if the user belongs to an org that has enabled the `DisableHideEmail` 202 /// option of the `Send Options` policy, and the user is not an owner or admin of that org. is_hide_email_disabled(user_uuid: &str, conn: &DbConn) -> bool203 pub fn is_hide_email_disabled(user_uuid: &str, conn: &DbConn) -> bool { 204 for policy in OrgPolicy::find_confirmed_by_user(user_uuid, conn) { 205 if policy.enabled && policy.has_type(OrgPolicyType::SendOptions) { 206 let org_uuid = &policy.org_uuid; 207 if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, org_uuid, conn) { 208 if user.atype < UserOrgType::Admin { 209 match serde_json::from_str::<UpCase<SendOptionsPolicyData>>(&policy.data) { 210 Ok(opts) => { 211 if opts.data.DisableHideEmail { 212 return true; 213 } 214 } 215 _ => error!("Failed to deserialize policy data: {}", policy.data), 216 } 217 } 218 } 219 } 220 } 221 false 222 } 223 224 /*pub fn delete_all_by_user(user_uuid: &str, conn: &DbConn) -> EmptyResult { 225 db_run! { conn: { 226 diesel::delete(twofactor::table.filter(twofactor::user_uuid.eq(user_uuid))) 227 .execute(conn) 228 .map_res("Error deleting twofactors") 229 }} 230 }*/ 231 } 232