feat: enhance cipher update process with folder ownership validation and client data freshness checks
This commit is contained in:
parent
90b6058fb6
commit
51676af4a1
1 changed files with 39 additions and 1 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
use super::get_batch_size;
|
use super::get_batch_size;
|
||||||
use axum::{extract::State, Json};
|
use axum::{extract::State, Json};
|
||||||
use chrono::Utc;
|
use chrono::{DateTime, Utc};
|
||||||
|
use log; // Used for warning logs on parse failures
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
@ -116,6 +117,43 @@ pub async fn update_cipher(
|
||||||
.await?
|
.await?
|
||||||
.ok_or(AppError::NotFound("Cipher not found".to_string()))?;
|
.ok_or(AppError::NotFound("Cipher not found".to_string()))?;
|
||||||
|
|
||||||
|
// Validate folder ownership if provided
|
||||||
|
if let Some(ref folder_id) = payload.folder_id {
|
||||||
|
let folder_exists: Option<serde_json::Value> = db
|
||||||
|
.prepare("SELECT id FROM folders WHERE id = ?1 AND user_id = ?2")
|
||||||
|
.bind(&[folder_id.clone().into(), claims.sub.clone().into()])?
|
||||||
|
.first(None)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if folder_exists.is_none() {
|
||||||
|
return Err(AppError::BadRequest(
|
||||||
|
"Invalid folder: Folder does not exist or belongs to another user".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject updates based on stale client data when the last known revision is provided
|
||||||
|
if let Some(dt) = payload.last_known_revision_date.as_deref() {
|
||||||
|
match DateTime::parse_from_rfc3339(dt) {
|
||||||
|
Ok(client_dt) => match DateTime::parse_from_rfc3339(&existing_cipher.updated_at) {
|
||||||
|
Ok(server_dt) => {
|
||||||
|
if server_dt.signed_duration_since(client_dt).num_seconds() > 1 {
|
||||||
|
return Err(AppError::BadRequest(
|
||||||
|
"The client copy of this cipher is out of date. Resync the client and try again.".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => log::warn!(
|
||||||
|
"Error parsing server revisionDate '{}' for cipher {}: {}",
|
||||||
|
existing_cipher.updated_at,
|
||||||
|
existing_cipher.id,
|
||||||
|
err
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Err(err) => log::warn!("Error parsing lastKnownRevisionDate '{}': {}", dt, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let cipher_data_req = payload;
|
let cipher_data_req = payload;
|
||||||
|
|
||||||
let cipher_data = CipherData {
|
let cipher_data = CipherData {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue