|
|
@ -6,6 +6,7 @@ use rocket::{ |
|
|
Route, |
|
|
Route, |
|
|
form::{Form, FromForm}, |
|
|
form::{Form, FromForm}, |
|
|
fs::TempFile, |
|
|
fs::TempFile, |
|
|
|
|
|
http::Status, |
|
|
serde::json::Json, |
|
|
serde::json::Json, |
|
|
}; |
|
|
}; |
|
|
use serde_json::Value; |
|
|
use serde_json::Value; |
|
|
@ -21,8 +22,8 @@ use crate::{ |
|
|
DbConn, DbPool, |
|
|
DbConn, DbPool, |
|
|
models::{ |
|
|
models::{ |
|
|
Archive, Attachment, AttachmentId, Cipher, CipherId, Collection, CollectionCipher, CollectionGroup, |
|
|
Archive, Attachment, AttachmentId, Cipher, CipherId, Collection, CollectionCipher, CollectionGroup, |
|
|
CollectionId, CollectionUser, EventType, Favorite, Folder, FolderCipher, FolderId, Group, Membership, |
|
|
CollectionId, CollectionUser, EventType, Favorite, Folder, FolderCipher, FolderId, Group, KeyId, |
|
|
MembershipType, OrgPolicy, OrgPolicyType, OrganizationId, RepromptType, Send, UserId, |
|
|
Membership, MembershipType, OrgPolicy, OrgPolicyType, OrganizationId, RepromptType, Send, UserId, |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
util::{NumberOrString, deser_opt_nonempty_str, save_temp_file}, |
|
|
util::{NumberOrString, deser_opt_nonempty_str, save_temp_file}, |
|
|
@ -198,6 +199,7 @@ async fn sync(data: SyncData, headers: Headers, client_version: Option<ClientVer |
|
|
"sends": sends_json, |
|
|
"sends": sends_json, |
|
|
"userDecryption": { |
|
|
"userDecryption": { |
|
|
"masterPasswordUnlock": master_password_unlock, |
|
|
"masterPasswordUnlock": master_password_unlock, |
|
|
|
|
|
"userKeyId": headers.user.key_id, |
|
|
}, |
|
|
}, |
|
|
"object": "sync" |
|
|
"object": "sync" |
|
|
}))) |
|
|
}))) |
|
|
@ -260,6 +262,10 @@ pub struct CipherData { |
|
|
|
|
|
|
|
|
key: Option<String>, |
|
|
key: Option<String>, |
|
|
|
|
|
|
|
|
|
|
|
pub encrypted_for: UserId, // Added in web-v2025.6.0
|
|
|
|
|
|
// Added in web-v2025.8.1, Optional for compat
|
|
|
|
|
|
pub encrypted_by_key_id: Option<KeyId>, |
|
|
|
|
|
|
|
|
/* |
|
|
/* |
|
|
Login = 1, |
|
|
Login = 1, |
|
|
SecureNote = 2, |
|
|
SecureNote = 2, |
|
|
@ -333,6 +339,10 @@ async fn post_ciphers_create( |
|
|
) -> JsonResult { |
|
|
) -> JsonResult { |
|
|
let mut data: ShareCipherData = data.into_inner(); |
|
|
let mut data: ShareCipherData = data.into_inner(); |
|
|
|
|
|
|
|
|
|
|
|
if data.cipher.encrypted_for != headers.user.uuid { |
|
|
|
|
|
err_code!("Invalid user cipher", Status::UnprocessableEntity.code); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// This check is usually only needed in update_cipher_from_data(), but we
|
|
|
// This check is usually only needed in update_cipher_from_data(), but we
|
|
|
// need it here as well to avoid creating an empty cipher in the call to
|
|
|
// need it here as well to avoid creating an empty cipher in the call to
|
|
|
// cipher.save() below.
|
|
|
// cipher.save() below.
|
|
|
@ -362,6 +372,17 @@ async fn post_ciphers_create( |
|
|
async fn post_ciphers(data: Json<CipherData>, headers: Headers, conn: DbConn, nt: Notify<'_>) -> JsonResult { |
|
|
async fn post_ciphers(data: Json<CipherData>, headers: Headers, conn: DbConn, nt: Notify<'_>) -> JsonResult { |
|
|
let mut data: CipherData = data.into_inner(); |
|
|
let mut data: CipherData = data.into_inner(); |
|
|
|
|
|
|
|
|
|
|
|
if data.encrypted_for != headers.user.uuid { |
|
|
|
|
|
err_code!("Invalid user cipher", Status::UnprocessableEntity.code); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if let Some(cipher_key_id) = &data.encrypted_by_key_id |
|
|
|
|
|
&& let Some(user_key_id) = &headers.user.key_id |
|
|
|
|
|
&& cipher_key_id != user_key_id |
|
|
|
|
|
{ |
|
|
|
|
|
err_code!("Invalid key cipher", Status::UnprocessableEntity.code); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// The web/browser clients set this field to null as expected, but the
|
|
|
// The web/browser clients set this field to null as expected, but the
|
|
|
// mobile clients seem to set the invalid value `0001-01-01T00:00:00`,
|
|
|
// mobile clients seem to set the invalid value `0001-01-01T00:00:00`,
|
|
|
// which results in a warning message being logged. This field isn't
|
|
|
// which results in a warning message being logged. This field isn't
|
|
|
|