Skip to content

fix(secure-view): ZIP download silently broken when folder contains watermarked files #5588

@chrip

Description

@chrip

Describe the bug

When downloading a folder as ZIP that contains at least one Office file subject to Secure View watermarking, the resulting archive is silently corrupted. The server responds 200 OK and begins streaming the ZIP, but SecureViewWrapper::checkFileAccess() throws a ForbiddenException mid-stream once a secured file is reached. Because the HTTP response is already committed at that point, no error is surfaced to the user — they receive a broken, unextractable archive.

This bug was discovered while working on #5577 and #5587.

To Reproduce

  1. Enable Secure View watermarking (any rule: watermark_shareAll, tag-based, or group-based)
  2. Place at least one eligible Office file (.docx, .odt, etc.) inside a folder alongside other files
  3. Select the folder in the Files UI and choose "Download"
  4. Attempt to extract the downloaded ZIP → extraction fails with a corrupt archive error

Expected behavior

Either the download is blocked before it starts with a clear user-visible error, or secured files are excluded from the archive with a human-readable explanation.

Screenshots

N/A

Server details

Operating system: any

Web server: any

Database: any

PHP version: any

Nextcloud version: any

Version of the richdocuments app: any

Version of Collabora Online: any

Configuration of the richdocuments app
Any configuration with watermark_enabled = yes and at least one watermark rule active.

Notes for implementors

Three fix strategies:

A — Block before ZIP creation (BeforeZipCreatedEvent listener): scan the folder tree and reject the download if any watermarked file is found. Main concern: fully recursive tree walk with per-file shouldWatermark() calls degenerates into one getTagIdsForObjects() DB query per file when tag-based rules are active — O(n) queries before a single byte is written. Requires batched tag lookups and a rule-level pre-flight check to be safe for large folders.

B — Graceful degradation during streaming: catch the ForbiddenException at the ZIP-assembly layer in core, skip the secured file, and inject a DOWNLOAD_INCOMPLETE.txt into the archive. User gets a usable partial ZIP with a clear explanation. Requires a Nextcloud core change.

C — Verify existing error surfacing: confirm whether Nextcloud core already checks BeforeZipCreatedEvent::getErrorMessage() and aborts with a user-visible response before any ZIP data is written. If so, strategy A (with the performance fixes above) may be sufficient.

Metadata

Metadata

Assignees

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions