|
@ -100,24 +100,18 @@ fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> Json<Value> { |
|
|
let folders_json: Vec<Value> = folders.iter().map(Folder::to_json).collect(); |
|
|
let folders_json: Vec<Value> = folders.iter().map(Folder::to_json).collect(); |
|
|
|
|
|
|
|
|
let collections = Collection::find_by_user_uuid(&headers.user.uuid, &conn); |
|
|
let collections = Collection::find_by_user_uuid(&headers.user.uuid, &conn); |
|
|
let collections_json: Vec<Value> = collections.iter() |
|
|
let collections_json: Vec<Value> = |
|
|
.map(|c| c.to_json_details(&headers.user.uuid, &conn)) |
|
|
collections.iter().map(|c| c.to_json_details(&headers.user.uuid, &conn)).collect(); |
|
|
.collect(); |
|
|
|
|
|
|
|
|
|
|
|
let policies = OrgPolicy::find_by_user(&headers.user.uuid, &conn); |
|
|
let policies = OrgPolicy::find_by_user(&headers.user.uuid, &conn); |
|
|
let policies_json: Vec<Value> = policies.iter().map(OrgPolicy::to_json).collect(); |
|
|
let policies_json: Vec<Value> = policies.iter().map(OrgPolicy::to_json).collect(); |
|
|
|
|
|
|
|
|
let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn); |
|
|
let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn); |
|
|
let ciphers_json: Vec<Value> = ciphers |
|
|
let ciphers_json: Vec<Value> = |
|
|
.iter() |
|
|
ciphers.iter().map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)).collect(); |
|
|
.map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)) |
|
|
|
|
|
.collect(); |
|
|
|
|
|
|
|
|
|
|
|
let sends = Send::find_by_user(&headers.user.uuid, &conn); |
|
|
let sends = Send::find_by_user(&headers.user.uuid, &conn); |
|
|
let sends_json: Vec<Value> = sends |
|
|
let sends_json: Vec<Value> = sends.iter().map(|s| s.to_json()).collect(); |
|
|
.iter() |
|
|
|
|
|
.map(|s| s.to_json()) |
|
|
|
|
|
.collect(); |
|
|
|
|
|
|
|
|
|
|
|
let domains_json = if data.exclude_domains { |
|
|
let domains_json = if data.exclude_domains { |
|
|
Value::Null |
|
|
Value::Null |
|
@ -142,10 +136,8 @@ fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> Json<Value> { |
|
|
fn get_ciphers(headers: Headers, conn: DbConn) -> Json<Value> { |
|
|
fn get_ciphers(headers: Headers, conn: DbConn) -> Json<Value> { |
|
|
let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn); |
|
|
let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn); |
|
|
|
|
|
|
|
|
let ciphers_json: Vec<Value> = ciphers |
|
|
let ciphers_json: Vec<Value> = |
|
|
.iter() |
|
|
ciphers.iter().map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)).collect(); |
|
|
.map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)) |
|
|
|
|
|
.collect(); |
|
|
|
|
|
|
|
|
|
|
|
Json(json!({ |
|
|
Json(json!({ |
|
|
"Data": ciphers_json, |
|
|
"Data": ciphers_json, |
|
@ -288,17 +280,12 @@ fn post_ciphers(data: JsonUpcase<CipherData>, headers: Headers, conn: DbConn, nt |
|
|
/// allowed to delete or share such ciphers to an org, however.
|
|
|
/// allowed to delete or share such ciphers to an org, however.
|
|
|
///
|
|
|
///
|
|
|
/// Ref: https://bitwarden.com/help/article/policies/#personal-ownership
|
|
|
/// Ref: https://bitwarden.com/help/article/policies/#personal-ownership
|
|
|
fn enforce_personal_ownership_policy( |
|
|
fn enforce_personal_ownership_policy(data: &CipherData, headers: &Headers, conn: &DbConn) -> EmptyResult { |
|
|
data: &CipherData, |
|
|
|
|
|
headers: &Headers, |
|
|
|
|
|
conn: &DbConn |
|
|
|
|
|
) -> EmptyResult { |
|
|
|
|
|
if data.OrganizationId.is_none() { |
|
|
if data.OrganizationId.is_none() { |
|
|
let user_uuid = &headers.user.uuid; |
|
|
let user_uuid = &headers.user.uuid; |
|
|
let policy_type = OrgPolicyType::PersonalOwnership; |
|
|
let policy_type = OrgPolicyType::PersonalOwnership; |
|
|
if OrgPolicy::is_applicable_to_user(user_uuid, policy_type, conn) { |
|
|
if OrgPolicy::is_applicable_to_user(user_uuid, policy_type, conn) { |
|
|
err!("Due to an Enterprise Policy, you are restricted from \ |
|
|
err!("Due to an Enterprise Policy, you are restricted from saving items to your personal vault.") |
|
|
saving items to your personal vault.") |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
Ok(()) |
|
|
Ok(()) |
|
@ -317,11 +304,12 @@ pub fn update_cipher_from_data( |
|
|
|
|
|
|
|
|
// Check that the client isn't updating an existing cipher with stale data.
|
|
|
// Check that the client isn't updating an existing cipher with stale data.
|
|
|
if let Some(dt) = data.LastKnownRevisionDate { |
|
|
if let Some(dt) = data.LastKnownRevisionDate { |
|
|
match NaiveDateTime::parse_from_str(&dt, "%+") { // ISO 8601 format
|
|
|
match NaiveDateTime::parse_from_str(&dt, "%+") { |
|
|
Err(err) => |
|
|
// ISO 8601 format
|
|
|
warn!("Error parsing LastKnownRevisionDate '{}': {}", dt, err), |
|
|
Err(err) => warn!("Error parsing LastKnownRevisionDate '{}': {}", dt, err), |
|
|
Ok(dt) if cipher.updated_at.signed_duration_since(dt).num_seconds() > 1 => |
|
|
Ok(dt) if cipher.updated_at.signed_duration_since(dt).num_seconds() > 1 => { |
|
|
err!("The client copy of this cipher is out of date. Resync the client and try again."), |
|
|
err!("The client copy of this cipher is out of date. Resync the client and try again.") |
|
|
|
|
|
} |
|
|
Ok(_) => (), |
|
|
Ok(_) => (), |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -394,10 +382,7 @@ pub fn update_cipher_from_data( |
|
|
// But, we at least know we do not need to store and return this specific key.
|
|
|
// But, we at least know we do not need to store and return this specific key.
|
|
|
fn _clean_cipher_data(mut json_data: Value) -> Value { |
|
|
fn _clean_cipher_data(mut json_data: Value) -> Value { |
|
|
if json_data.is_array() { |
|
|
if json_data.is_array() { |
|
|
json_data.as_array_mut() |
|
|
json_data.as_array_mut().unwrap().iter_mut().for_each(|ref mut f| { |
|
|
.unwrap() |
|
|
|
|
|
.iter_mut() |
|
|
|
|
|
.for_each(|ref mut f| { |
|
|
|
|
|
f.as_object_mut().unwrap().remove("Response"); |
|
|
f.as_object_mut().unwrap().remove("Response"); |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
@ -421,7 +406,7 @@ pub fn update_cipher_from_data( |
|
|
data["Uris"] = _clean_cipher_data(data["Uris"].clone()); |
|
|
data["Uris"] = _clean_cipher_data(data["Uris"].clone()); |
|
|
} |
|
|
} |
|
|
data |
|
|
data |
|
|
}, |
|
|
} |
|
|
None => err!("Data missing"), |
|
|
None => err!("Data missing"), |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@ -602,11 +587,8 @@ fn post_collections_admin( |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let posted_collections: HashSet<String> = data.CollectionIds.iter().cloned().collect(); |
|
|
let posted_collections: HashSet<String> = data.CollectionIds.iter().cloned().collect(); |
|
|
let current_collections: HashSet<String> = cipher |
|
|
let current_collections: HashSet<String> = |
|
|
.get_collections(&headers.user.uuid, &conn) |
|
|
cipher.get_collections(&headers.user.uuid, &conn).iter().cloned().collect(); |
|
|
.iter() |
|
|
|
|
|
.cloned() |
|
|
|
|
|
.collect(); |
|
|
|
|
|
|
|
|
|
|
|
for collection in posted_collections.symmetric_difference(¤t_collections) { |
|
|
for collection in posted_collections.symmetric_difference(¤t_collections) { |
|
|
match Collection::find_by_uuid(&collection, &conn) { |
|
|
match Collection::find_by_uuid(&collection, &conn) { |
|
@ -842,7 +824,8 @@ fn post_attachment( |
|
|
let file_name = HEXLOWER.encode(&crypto::get_random(vec![0; 10])); |
|
|
let file_name = HEXLOWER.encode(&crypto::get_random(vec![0; 10])); |
|
|
let path = base_path.join(&file_name); |
|
|
let path = base_path.join(&file_name); |
|
|
|
|
|
|
|
|
let size = match field.data.save().memory_threshold(0).size_limit(size_limit).with_path(path.clone()) { |
|
|
let size = |
|
|
|
|
|
match field.data.save().memory_threshold(0).size_limit(size_limit).with_path(path.clone()) { |
|
|
SaveResult::Full(SavedData::File(_, size)) => size as i32, |
|
|
SaveResult::Full(SavedData::File(_, size)) => size as i32, |
|
|
SaveResult::Full(other) => { |
|
|
SaveResult::Full(other) => { |
|
|
std::fs::remove_file(path).ok(); |
|
|
std::fs::remove_file(path).ok(); |
|
@ -994,12 +977,22 @@ fn delete_cipher_selected_admin(data: JsonUpcase<Value>, headers: Headers, conn: |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[post("/ciphers/delete-admin", data = "<data>")] |
|
|
#[post("/ciphers/delete-admin", data = "<data>")] |
|
|
fn delete_cipher_selected_post_admin(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult { |
|
|
fn delete_cipher_selected_post_admin( |
|
|
|
|
|
data: JsonUpcase<Value>, |
|
|
|
|
|
headers: Headers, |
|
|
|
|
|
conn: DbConn, |
|
|
|
|
|
nt: Notify, |
|
|
|
|
|
) -> EmptyResult { |
|
|
delete_cipher_selected_post(data, headers, conn, nt) |
|
|
delete_cipher_selected_post(data, headers, conn, nt) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[put("/ciphers/delete-admin", data = "<data>")] |
|
|
#[put("/ciphers/delete-admin", data = "<data>")] |
|
|
fn delete_cipher_selected_put_admin(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult { |
|
|
fn delete_cipher_selected_put_admin( |
|
|
|
|
|
data: JsonUpcase<Value>, |
|
|
|
|
|
headers: Headers, |
|
|
|
|
|
conn: DbConn, |
|
|
|
|
|
nt: Notify, |
|
|
|
|
|
) -> EmptyResult { |
|
|
delete_cipher_selected_put(data, headers, conn, nt) |
|
|
delete_cipher_selected_put(data, headers, conn, nt) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1150,7 +1143,13 @@ fn _delete_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &DbConn, soft_del |
|
|
Ok(()) |
|
|
Ok(()) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fn _delete_multiple_ciphers(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, soft_delete: bool, nt: Notify) -> EmptyResult { |
|
|
fn _delete_multiple_ciphers( |
|
|
|
|
|
data: JsonUpcase<Value>, |
|
|
|
|
|
headers: Headers, |
|
|
|
|
|
conn: DbConn, |
|
|
|
|
|
soft_delete: bool, |
|
|
|
|
|
nt: Notify, |
|
|
|
|
|
) -> EmptyResult { |
|
|
let data: Value = data.into_inner().data; |
|
|
let data: Value = data.into_inner().data; |
|
|
|
|
|
|
|
|
let uuids = match data.get("Ids") { |
|
|
let uuids = match data.get("Ids") { |
|
@ -1202,7 +1201,7 @@ fn _restore_multiple_ciphers(data: JsonUpcase<Value>, headers: &Headers, conn: & |
|
|
for uuid in uuids { |
|
|
for uuid in uuids { |
|
|
match _restore_cipher_by_uuid(uuid, headers, conn, nt) { |
|
|
match _restore_cipher_by_uuid(uuid, headers, conn, nt) { |
|
|
Ok(json) => ciphers.push(json.into_inner()), |
|
|
Ok(json) => ciphers.push(json.into_inner()), |
|
|
err => return err |
|
|
err => return err, |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|