fix(security): patch 3 vulnerabilities — IDOR, ownership bypass, XSS

V1: Add owner-scoped folder pagination (list_folders_by_owner_paginated)
  - New method in FolderRepository trait, PG implementation, service & handler
  - Prevents IDOR by filtering folder listings to authenticated user

V2: Enforce ownership checks on folder mutations
  - rename_folder, move_folder, delete_folder now require caller_id
  - Service verifies folder.owner_id == caller_id (returns 404 on mismatch)
  - Propagated to folder_handler, batch_handler, batch_operations, webdav_handler
  - delete_folder_with_trash upgraded from OptionalAuthUser to AuthUser
  - download_folder_zip now checks ownership before streaming

V3: Fix XSS in frontend via DOM APIs
  - sharedView.js: innerHTML → createElement + textContent
  - contextMenus.js: innerHTML → DOM construction for share dialog

Cleanup: removed unused OptionalAuthUser import, updated all stubs/mocks
This commit is contained in:
Dionisio
2026-02-16 00:22:42 +01:00
parent 66b4acd9d6
commit 5a679dfc90
25 changed files with 684 additions and 269 deletions
@@ -645,9 +645,10 @@ async fn handle_delete(
let folder_result = folder_service.get_folder_by_path(&path).await;
if let Ok(folder) = folder_result {
// Delete folder
// Delete folder — use the folder's own owner as caller_id
let caller_id = folder.owner_id.as_deref().unwrap_or("webdav");
folder_service
.delete_folder(&folder.id)
.delete_folder(&folder.id, caller_id)
.await
.map_err(|e| AppError::internal_error(format!("Failed to delete folder: {}", e)))?;
} else {
@@ -761,7 +762,7 @@ async fn handle_move(
};
folder_service
.move_folder(&folder.id, move_dto)
.move_folder(&folder.id, move_dto, folder.owner_id.as_deref().unwrap_or("webdav"))
.await
.map_err(|e| AppError::internal_error(format!("Failed to move folder: {}", e)))?;
@@ -771,7 +772,7 @@ async fn handle_move(
};
folder_service
.rename_folder(&folder.id, rename_dto)
.rename_folder(&folder.id, rename_dto, folder.owner_id.as_deref().unwrap_or("webdav"))
.await
.map_err(|e| AppError::internal_error(format!("Failed to rename folder: {}", e)))?;
}