Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 40 additions & 7 deletions lib/Service/SecureViewService.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,66 @@ public function isEnabled(): bool {
}

/**
* @throws NotFoundException
* Prepares metadata and context needed to decide if SecureView restrictions (such as watermarking or
* download blocking) may apply to a given file or folder. Ensures filecache metadata is available by
* triggering backend cache updates for files if requested, and supports external storages. Delegates
* the actual policy decision to shouldWatermark().
*
* @param string $path Relative storage path to check.
* @param IStorage $storage Storage backend instance.
* @param bool $tryOpen Whether to attempt opening files to force/cache refresh file metadata.
* @return bool True if SecureView restrictions may apply (per shouldWatermark()), false otherwise.
* @throws NotFoundException If neither the file nor its parent are present in the filecache/remote storage.
*/
public function shouldSecure(string $path, IStorage $storage, bool $tryOpen = true): bool {
if ($tryOpen) {
// pity… fopen() does not document any possible Exceptions
// First: try to get the cache entry for $path
$cacheEntry = $storage->getCache()->get($path);

$isDir = false;
// Prefer cache for fast directory check; fall back to (potentially slower) is_dir() if needed
if ($cacheEntry && !empty($cacheEntry['mimetype']) && $cacheEntry['mimetype'] === 'httpd/unix-directory') {
$isDir = true;
} elseif (!$cacheEntry && method_exists($storage, 'is_dir') && $storage->is_dir($path)) {
$isDir = true;
}

if ($tryOpen && !$isDir) {
// Attempt to open the file to potentially trigger cache entry creation
$fp = $storage->fopen($path, 'r');
fclose($fp);
if ($fp !== false && is_resource($fp)) {
fclose($fp);
}
// Re-fetch the cache entry after the 'poke'
$cacheEntry = $storage->getCache()->get($path);
}

$cacheEntry = $storage->getCache()->get($path);
// Fallback to parent *only if cache entry still missing after poke*
if (!$cacheEntry) {
$parent = dirname($path);
if ($parent === '.') {
$parent = '';
}
$cacheEntry = $storage->getCache()->get($parent);
if (!$cacheEntry) {
throw new NotFoundException(sprintf('Could not find cache entry for path and parent of %s within storage %s ', $path, $storage->getId()));
throw new NotFoundException(sprintf(
'Could not find cache entry for path and parent of %s within storage %s',
$path, $storage->getId()
));
}
}

// Now carry on with original SecureView logic...
$isSharedStorage = $storage->instanceOfStorage(ISharedStorage::class);
/** @noinspection PhpPossiblePolymorphicInvocationInspection */
/** @psalm-suppress UndefinedMethod **/
$share = $isSharedStorage ? $storage->getShare() : null;
$userId = $this->userSession->getUser()?->getUID();

return $this->permissionManager->shouldWatermark($cacheEntry, $userId, $share, $storage->getOwner($path) ?: null);
return $this->permissionManager->shouldWatermark(
$cacheEntry,
$userId,
$share,
$storage->getOwner($path) ?: null
);
}
}
Loading