Skip to content
Merged
Show file tree
Hide file tree
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
28 changes: 27 additions & 1 deletion lib/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,20 @@ protected function isBlockablePath(IStorage $storage, string $path): bool {
}

// '', admin, 'files', 'path/to/file.txt'
$segment = explode('/', $fullPath, 4);
// '', admin, 'files_trashbin', 'versions', 'path/to/file.txt'
$segment = explode('/', $fullPath, 5);

if (isset($segment[2]) && $segment[1] === '__groupfolders' && $segment[2] === 'trash') {
// Special case, a file was deleted inside a groupfolder
return true;
}

if (isset($segment[3]) && $segment[2] === 'files_trashbin'
&& ($segment[3] === 'keys' || !isset($segment[4]))) {
// Ignore encryption keys in trashbin and the files and version folder themselves
return false;
}

return isset($segment[2]) && in_array($segment[2], [
'files',
'thumbnails',
Expand All @@ -138,6 +145,25 @@ protected function translatePath(IStorage $storage, string $path): string {
// Remove trailing ".v{timestamp}"
$innerPath = substr($innerPath, 0, -12);
}
return 'files/' . $innerPath;
} elseif ($folder === 'files_trashbin') {
// 'files', 'path/to/file.txt'
// 'versions', 'path/to/file.txt'
$segments = explode('/', $innerPath, 2);
if (isset($segments[1])) {
$innerPath = $segments[1];
}

if (preg_match('/.+\.d\d{10}$/', basename($innerPath))) {
// Remove trailing ".d{timestamp}" of trashbin
$innerPath = substr($innerPath, 0, -12);
}

if ($folder === 'versions' && preg_match('/.+\.v\d{10}$/', basename($innerPath))) {
// Remove trailing ".v{timestamp}" of versions inside trashbin
$innerPath = substr($innerPath, 0, -12);
}

return 'files/' . $innerPath;
} elseif ($folder === 'thumbnails') {
[$fileId,] = explode('/', $innerPath, 2);
Expand Down
9 changes: 4 additions & 5 deletions tests/Integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,11 @@ public function createFlow(string $user, string $scope, int $statusCode, TableNo
$this->setCurrentUser($user);

$formData = $tableNode->getRowsHash();

$checks = [];
foreach ($formData as $key => $value) {
if (strpos($key, 'checks-') === 0) {
$value = str_replace('{{{FILES_ACCESSCONTROL_INTEGRATIONTEST_TAGID}}}', $this->tagId, $value);
$checks[] = json_decode($value, true);
$checks[] = json_decode($value, true, flags: JSON_THROW_ON_ERROR);
unset($formData[$key]);
}
}
Expand All @@ -118,7 +117,7 @@ public function createFlow(string $user, string $scope, int $statusCode, TableNo
$formData['events'] = [];

$this->sendingToWith('POST', '/apps/workflowengine/api/v1/workflows/' . $scope, $formData);
Assert::assertSame($statusCode, $this->response->getStatusCode(), 'HTTP status code mismatch');
Assert::assertSame($statusCode, $this->response->getStatusCode(), 'HTTP status code mismatch:' . "\n" . $this->response->getBody()->getContents());
}

/**
Expand All @@ -144,10 +143,10 @@ public function theWebdavResponseShouldHaveAStatusCode($statusCode) {
if (str_contains($statusCode, '|')) {
$statusCodes = array_map('intval', explode('|', $statusCode));
} else {
$statusCodes = [(int) $statusCode];
$statusCodes = [(int)$statusCode];
}
if (!in_array($this->response->getStatusCode(), $statusCodes, true)) {
throw new \Exception("Expected $statusCode, got ".$this->response->getStatusCode());
throw new \Exception("Expected $statusCode, got " . $this->response->getStatusCode());
}
}

Expand Down
13 changes: 13 additions & 0 deletions tests/Integration/features/mimetypes.feature
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,16 @@
And The webdav response should have a status code "403"
When User "test1" copies file "/hello" to "/hello.txt"
And The webdav response should have a status code "403"

Scenario: Blocking by mimetype works in trashbin
Given User "test1" uploads file "data/textfile.txt" to "/foobar.txt"
And user "admin" creates global flow with 200
| name | Admin flow |
| class | OCA\FilesAccessControl\Operation |
| entity | OCA\WorkflowEngine\Entity\File |
| events | [] |
| operation | deny |
| checks-0 | {"class":"OCA\\WorkflowEngine\\Check\\FileMimeType", "operator": "!is", "value": "httpd/unix-directory"} |
| checks-1 | {"class":"OCA\\WorkflowEngine\\Check\\FileMimeType", "operator": "!is", "value": "text/plain"} |
When User "test1" deletes file "/foobar.txt"
Then The webdav response should have a status code "204"