security(public link): require share permission
issue was: a user can reshare publicly a resource
on owner revocation, the attacker keep it's own share
request now share permission
This commit is contained in:
@@ -6,7 +6,7 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use crate::domain::repositories::drive_repository::DriveRepository;
|
use crate::domain::repositories::drive_repository::DriveRepository;
|
||||||
use crate::domain::repositories::folder_repository::FolderRepository;
|
use crate::domain::repositories::folder_repository::FolderRepository;
|
||||||
use crate::domain::services::authorization::{Resource, Role, Subject};
|
use crate::domain::services::authorization::{Permission, Resource, Role, Subject};
|
||||||
use crate::infrastructure::repositories::pg::DrivePgRepository;
|
use crate::infrastructure::repositories::pg::DrivePgRepository;
|
||||||
use crate::infrastructure::repositories::pg::SharePgRepository;
|
use crate::infrastructure::repositories::pg::SharePgRepository;
|
||||||
use crate::infrastructure::repositories::pg::file_blob_read_repository::FileBlobReadRepository;
|
use crate::infrastructure::repositories::pg::file_blob_read_repository::FileBlobReadRepository;
|
||||||
@@ -243,6 +243,28 @@ impl ShareUseCase for ShareService {
|
|||||||
|
|
||||||
self.verify_item_exists(&dto.item_id, &item_type).await?;
|
self.verify_item_exists(&dto.item_id, &item_type).await?;
|
||||||
|
|
||||||
|
// AuthZ: only callers with `Share` on the resource may mint a
|
||||||
|
// public link. Without this gate, an ex-Viewer who kept a
|
||||||
|
// guessed UUID could launder a temporary read into a
|
||||||
|
// permanent anonymous URL that survives their own grant
|
||||||
|
// revocation. `Permission::Share` is bundled with the
|
||||||
|
// `owner` and `editor` role_grants only. `require` returns
|
||||||
|
// `not_found` on denial (anti-enum, matches the shape used
|
||||||
|
// by every other share route). See `docs/plan/authz_audit/`.
|
||||||
|
let item_uuid_for_authz = Uuid::parse_str(&dto.item_id)
|
||||||
|
.map_err(|_| ShareServiceError::Validation("Invalid item UUID".to_string()))?;
|
||||||
|
let resource_for_authz = match item_type {
|
||||||
|
ShareItemType::File => Resource::File(item_uuid_for_authz),
|
||||||
|
ShareItemType::Folder => Resource::Folder(item_uuid_for_authz),
|
||||||
|
};
|
||||||
|
self.authorization
|
||||||
|
.require(
|
||||||
|
Subject::User(user_id),
|
||||||
|
Permission::Share,
|
||||||
|
resource_for_authz,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// D5: `forbid_public_links` policy gate. The drive owner can
|
// D5: `forbid_public_links` policy gate. The drive owner can
|
||||||
// disable anonymous-link creation on every resource in their
|
// disable anonymous-link creation on every resource in their
|
||||||
// drive without per-resource intervention. Lookup is one JOIN
|
// drive without per-resource intervention. Lookup is one JOIN
|
||||||
|
|||||||
Reference in New Issue
Block a user