1
0
Fork 0
mirror of https://github.com/dani-garcia/vaultwarden.git synced 2025-07-02 18:44:59 +00:00

Update crates, web-vault and fixes (#4823)

* Update crates, web-vault and fixes

- Updated crates
- Updated web-vault to v2024.6.2
  This version is currently the latest version compatible with our API implementation.
  For newer versions we need more code updates to make it compatible.
  Thanks to @stefan0xC this version fixes #4628
- Added a small fix to prevent errors in the Vaultwarden and Client logs.
  The v2024.6.2 web-vault calls an endpoint with invalid arguments.
  If this happens we ignore the call and just return an Ok.
- Added the bulk-collection endpoint (Though not yet available in v2024.6.2)

Fixes #4628

* Prevent bulk remove collections to work
This commit is contained in:
Mathijs van Veluw 2024-08-07 22:46:03 +02:00 committed by GitHub
parent e7d5c17ff7
commit 2e6a6fa39f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 166 additions and 69 deletions

View file

@ -190,6 +190,8 @@ fn config() -> Json<Value> {
parse_experimental_client_feature_flags(&crate::CONFIG.experimental_client_feature_flags());
// Force the new key rotation feature
feature_states.insert("key-rotation-improvements".to_string(), true);
feature_states.insert("flexible-collections-v-1".to_string(), false);
Json(json!({
// Note: The clients use this version to handle backwards compatibility concerns
// This means they expect a version that closely matches the Bitwarden server version

View file

@ -2,6 +2,7 @@ use num_traits::FromPrimitive;
use rocket::serde::json::Json;
use rocket::Route;
use serde_json::Value;
use std::collections::{HashMap, HashSet};
use crate::{
api::{
@ -39,6 +40,7 @@ pub fn routes() -> Vec<Route> {
delete_organization_collection,
post_organization_collection_delete,
bulk_delete_organization_collections,
post_bulk_collections,
get_org_details,
get_org_users,
send_invite,
@ -1631,6 +1633,66 @@ async fn post_org_import(
user.update_revision(&mut conn).await
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
#[allow(dead_code)]
struct BulkCollectionsData {
organization_id: String,
cipher_ids: Vec<String>,
collection_ids: HashSet<String>,
remove_collections: bool,
}
// This endpoint is only reachable via the organization view, therefor this endpoint is located here
// Also Bitwarden does not send out Notifications for these changes, it only does this for individual cipher collection updates
#[post("/ciphers/bulk-collections", data = "<data>")]
async fn post_bulk_collections(data: Json<BulkCollectionsData>, headers: Headers, mut conn: DbConn) -> EmptyResult {
let data: BulkCollectionsData = data.into_inner();
// This feature does not seem to be active on all the clients
// To prevent future issues, add a check to block a call when this is set to true
if data.remove_collections {
err!("Bulk removing of collections is not yet implemented")
}
// Get all the collection available to the user in one query
// Also filter based upon the provided collections
let user_collections: HashMap<String, Collection> =
Collection::find_by_organization_and_user_uuid(&data.organization_id, &headers.user.uuid, &mut conn)
.await
.into_iter()
.filter_map(|c| {
if data.collection_ids.contains(&c.uuid) {
Some((c.uuid.clone(), c))
} else {
None
}
})
.collect();
// Verify if all the collections requested exists and are writeable for the user, else abort
for collection_uuid in &data.collection_ids {
match user_collections.get(collection_uuid) {
Some(collection) if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await => (),
_ => err_code!("Resource not found", "User does not have access to a collection", 404),
}
}
for cipher_id in data.cipher_ids.iter() {
// Only act on existing cipher uuid's
// Do not abort the operation just ignore it, it could be a cipher was just deleted for example
if let Some(cipher) = Cipher::find_by_uuid_and_org(cipher_id, &data.organization_id, &mut conn).await {
if cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
for collection in &data.collection_ids {
CollectionCipher::save(&cipher.uuid, collection, &mut conn).await?;
}
}
};
}
Ok(())
}
#[get("/organizations/<org_id>/policies")]
async fn list_policies(org_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> Json<Value> {
let policies = OrgPolicy::find_by_org(org_id, &mut conn).await;
@ -1645,6 +1707,13 @@ async fn list_policies(org_id: &str, _headers: AdminHeaders, mut conn: DbConn) -
#[get("/organizations/<org_id>/policies/token?<token>")]
async fn list_policies_token(org_id: &str, token: &str, mut conn: DbConn) -> JsonResult {
// web-vault 2024.6.2 seems to send these values and cause logs to output errors
// Catch this and prevent errors in the logs
// TODO: CleanUp after 2024.6.x is not used anymore.
if org_id == "undefined" && token == "undefined" {
return Ok(Json(json!({})));
}
let invite = crate::auth::decode_invite(token)?;
let invite_org_id = match invite.org_id {

View file

@ -620,6 +620,17 @@ impl Cipher {
}}
}
pub async fn find_by_uuid_and_org(cipher_uuid: &str, org_uuid: &str, conn: &mut DbConn) -> Option<Self> {
db_run! {conn: {
ciphers::table
.filter(ciphers::uuid.eq(cipher_uuid))
.filter(ciphers::organization_uuid.eq(org_uuid))
.first::<CipherDb>(conn)
.ok()
.from_db()
}}
}
// Find all ciphers accessible or visible to the specified user.
//
// "Accessible" means the user has read access to the cipher, either via