fix(contact): use Permission::Create for creations

This commit is contained in:
Edouard Vanbelle
2026-07-17 00:37:45 +02:00
parent 38abe6766c
commit eb884f6c8f
2 changed files with 61 additions and 6 deletions
+15 -6
View File
@@ -535,10 +535,16 @@ impl ContactUseCase for ContactService {
let address_book_id = Uuid::parse_str(&dto.address_book_id)
.map_err(|_| DomainError::validation_error("Invalid address book ID format"))?;
// Check if user has write access to the address book
// AuthZ audit #19 (2026-07-12): previously required
// `Permission::Update`, which is NOT in the Contributor bundle
// (Read + Create) — Contributor grantees on a shared address
// book couldn't add contacts via REST or CardDAV PUT despite
// holding the intended Create permission. `Delete` uses Delete
// (audit #13, above); creation must use Create. Same fix
// applied to `create_contact_from_vcard` + `create_group`.
let caller_id = Uuid::parse_str(&dto.user_id)
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?;
self.require_address_book_perm(&address_book_id, &caller_id, Permission::Update)
self.require_address_book_perm(&address_book_id, &caller_id, Permission::Create)
.await?;
// Convert DTOs to domain entities
@@ -614,10 +620,13 @@ impl ContactUseCase for ContactService {
let address_book_id = Uuid::parse_str(&dto.address_book_id)
.map_err(|_| DomainError::validation_error("Invalid address book ID format"))?;
// Check if user has write access to the address book
// AuthZ audit #19 — see the sibling `create_contact` above.
// This is the CardDAV `PUT contact.vcf` entry point; the fix
// unblocks Contributor grantees creating contacts through the
// CardDAV protocol as well as the REST surface.
let caller_id = Uuid::parse_str(&dto.user_id)
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?;
self.require_address_book_perm(&address_book_id, &caller_id, Permission::Update)
self.require_address_book_perm(&address_book_id, &caller_id, Permission::Create)
.await?;
// Parse vCard data
@@ -889,10 +898,10 @@ impl ContactUseCase for ContactService {
let address_book_id = Uuid::parse_str(&dto.address_book_id)
.map_err(|_| DomainError::validation_error("Invalid address book ID format"))?;
// Check if user has write access to the address book
// AuthZ audit #19 — see the sibling `create_contact` above.
let caller_id = Uuid::parse_str(&dto.user_id)
.map_err(|_| DomainError::validation_error("Invalid user ID format"))?;
self.require_address_book_perm(&address_book_id, &caller_id, Permission::Update)
self.require_address_book_perm(&address_book_id, &caller_id, Permission::Create)
.await?;
let group = ContactGroup::new(address_book_id, dto.name);