Skip to content
Open
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
101 changes: 101 additions & 0 deletions apps/admin_audit/lib/Actions/Action.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,20 @@

namespace OCA\AdminAudit\Actions;

use OC\Files\Storage\FailedStorage;
use OC\Files\Storage\Local;
use OC\Files\Storage\Wrapper\Jail;
use OCA\AdminAudit\IAuditLogger;
use OCA\AdminAudit\Operation;
use OCP\Files\ForbiddenException;
use OCP\Files\IHomeStorage;
use OCP\Files\InvalidPathException;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\ISharedStorage;
use OCP\Files\Storage\IStorage;
use OCP\IConfig;
use OCP\Server;

class Action {

Expand Down Expand Up @@ -79,4 +91,93 @@ public function log(
$context,
);
}

/**
* Returns [$key => path] with the path of the node as seen by the owner of the
* share it was accessed through, or [] if it was not accessed through a share
*
* @return array<string, string>
*/
protected function getOwnerPathParam(string $key, Node $node): array {
$ownerPath = $this->resolveNodePath($node, static function (IStorage $storage, string $internalPath): ?string {
if (!$storage->instanceOfStorage(ISharedStorage::class)) {
return null;
}
/** @var ISharedStorage $storage */
$sharePath = $storage->getShare()->getNode()->getPath();
return $internalPath === '' ? $sharePath : $sharePath . '/' . $internalPath;
});
return $ownerPath === null ? [] : [$key => $ownerPath];
}

/**
* Returns [$key => path] with the location of the node in the storage that holds it,
* or [] if it is held in a home storage or the storage is not available. On local
* storage this is the path relative to the data directory
* (e.g. "__groupfolders/1/files/a.txt"), otherwise the storage id followed by the
* path in that storage.
*
* @return array<string, string>
*/
protected function getRealPathParam(string $key, Node $node): array {
$realPath = $this->resolveNodePath($node, static function (IStorage $storage, string $internalPath): ?string {
while ($storage->instanceOfStorage(Jail::class)) {
/** @var Jail $storage */
$internalPath = $storage->getUnjailedPath($internalPath);
$storage = $storage->getUnjailedStorage();
}
if ($storage->instanceOfStorage(IHomeStorage::class) || $storage->instanceOfStorage(FailedStorage::class)) {
return null;
}
if (!$storage->instanceOfStorage(Local::class)) {
return rtrim($storage->getId(), '/') . '/' . $internalPath;
}
/** @var Local $storage */
$sourcePath = rtrim($storage->getSourcePath($internalPath), '/');
$dataDirectory = rtrim(Server::get(IConfig::class)->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data'), '/') . '/';
return str_starts_with($sourcePath, $dataDirectory) ? substr($sourcePath, strlen($dataDirectory)) : $sourcePath;
});
return $realPath === null ? [] : [$key => $realPath];
}

/**
* Appends placeholders for the real path parameters in $params to $text.
* They must directly follow the parameters used by $text.
*/
protected function appendRealPathText(string $text, array $params): string {
if (isset($params['realPath'])) {
return $text . ' (real path = "%s")';
}
$old = isset($params['oldRealPath']);
$new = isset($params['newRealPath']);
if ($old && $new) {
return $text . ' (real path from "%s" to "%s")';
}
if ($old) {
return $text . ' (real path from "%s")';
}
if ($new) {
return $text . ' (real path to "%s")';
}
return $text;
}

/**
* @param callable(IStorage, string): ?string $resolve
*/
private function resolveNodePath(Node $node, callable $resolve): ?string {
try {
try {
$storage = $node->getStorage();
$internalPath = $node->getInternalPath();
} catch (NotFoundException) {
// Nodes that no longer exist, like the source of a rename, are resolved through their parent
$parentPath = $this->resolveNodePath($node->getParent(), $resolve);
return $parentPath === null ? null : $parentPath . '/' . $node->getName();
}
return $resolve($storage, $internalPath);
} catch (InvalidPathException|NotFoundException|ForbiddenException) {
return null;
}
}
}
34 changes: 22 additions & 12 deletions apps/admin_audit/lib/Actions/Files.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public function read(BeforeNodeReadEvent $event): void {
$params = [
'id' => $node instanceof NonExistingFile ? 'not-yet-assigned' : $node->getId(),
'path' => $node->getPath(),
];
] + $this->getRealPathParam('realPath', $node)
+ $this->getOwnerPathParam('ownerPath', $node);
} catch (InvalidPathException|NotFoundException $e) {
Server::get(LoggerInterface::class)->error(
'Exception thrown in file read: ' . $e->getMessage(), ['app' => 'admin_audit', 'exception' => $e]
Expand All @@ -45,7 +46,7 @@ public function read(BeforeNodeReadEvent $event): void {
}
$this->log(
Operation::FileRead,
'File with id "%s" accessed: "%s"',
$this->appendRealPathText('File with id "%s" accessed: "%s"', $params),
$params,
array_keys($params)
);
Expand All @@ -62,7 +63,10 @@ public function afterRename(NodeRenamedEvent $event): void {
'newid' => $target->getId(),
'oldpath' => $source->getPath(),
'newpath' => $target->getPath(),
];
] + $this->getRealPathParam('oldRealPath', $source)
+ $this->getRealPathParam('newRealPath', $target)
+ $this->getOwnerPathParam('oldOwnerPath', $source)
+ $this->getOwnerPathParam('newOwnerPath', $target);
} catch (InvalidPathException|NotFoundException $e) {
Server::get(LoggerInterface::class)->error(
'Exception thrown in file rename: ' . $e->getMessage(), ['app' => 'admin_audit', 'exception' => $e]
Expand All @@ -72,7 +76,7 @@ public function afterRename(NodeRenamedEvent $event): void {

$this->log(
Operation::FileRenamed,
'File renamed with id "%s" from "%s" to "%s"',
$this->appendRealPathText('File renamed with id "%s" from "%s" to "%s"', $params),
$params,
array_keys($params)
);
Expand All @@ -87,7 +91,8 @@ public function create(NodeCreatedEvent $event): void {
$params = [
'id' => $node->getId(),
'path' => $node->getPath(),
];
] + $this->getRealPathParam('realPath', $node)
+ $this->getOwnerPathParam('ownerPath', $node);
} catch (InvalidPathException|NotFoundException $e) {
Server::get(LoggerInterface::class)->error(
'Exception thrown in file create: ' . $e->getMessage(), ['app' => 'admin_audit', 'exception' => $e]
Expand All @@ -99,7 +104,7 @@ public function create(NodeCreatedEvent $event): void {
}
$this->log(
Operation::FileCreated,
'File with id "%s" created: "%s"',
$this->appendRealPathText('File with id "%s" created: "%s"', $params),
$params,
array_keys($params)
);
Expand All @@ -117,7 +122,10 @@ public function copy(NodeCopiedEvent $event): void {
'newid' => $target->getId(),
'oldpath' => $source->getPath(),
'newpath' => $target->getPath(),
];
] + $this->getRealPathParam('oldRealPath', $source)
+ $this->getRealPathParam('newRealPath', $target)
+ $this->getOwnerPathParam('oldOwnerPath', $source)
+ $this->getOwnerPathParam('newOwnerPath', $target);
} catch (InvalidPathException|NotFoundException $e) {
Server::get(LoggerInterface::class)->error(
'Exception thrown in file copy: ' . $e->getMessage(), ['app' => 'admin_audit', 'exception' => $e]
Expand All @@ -126,7 +134,7 @@ public function copy(NodeCopiedEvent $event): void {
}
$this->log(
Operation::FileCopied,
'File id copied from: "%s" to "%s", path from "%s" to "%s"',
$this->appendRealPathText('File id copied from: "%s" to "%s", path from "%s" to "%s"', $params),
$params,
array_keys($params)
);
Expand All @@ -141,7 +149,8 @@ public function write(NodeWrittenEvent $event): void {
$params = [
'id' => $node->getId(),
'path' => $node->getPath(),
];
] + $this->getRealPathParam('realPath', $node)
+ $this->getOwnerPathParam('ownerPath', $node);
} catch (InvalidPathException|NotFoundException $e) {
Server::get(LoggerInterface::class)->error(
'Exception thrown in file write: ' . $e->getMessage(), ['app' => 'admin_audit', 'exception' => $e]
Expand All @@ -154,7 +163,7 @@ public function write(NodeWrittenEvent $event): void {

$this->log(
Operation::FileWritten,
'File with id "%s" written to: "%s"',
$this->appendRealPathText('File with id "%s" written to: "%s"', $params),
$params,
array_keys($params)
);
Expand All @@ -169,7 +178,8 @@ public function delete(BeforeNodeDeletedEvent $event): void {
$params = [
'id' => $node->getId(),
'path' => $node->getPath(),
];
] + $this->getRealPathParam('realPath', $node)
+ $this->getOwnerPathParam('ownerPath', $node);
} catch (InvalidPathException|NotFoundException $e) {
Server::get(LoggerInterface::class)->error(
'Exception thrown in file delete: ' . $e->getMessage(), ['app' => 'admin_audit', 'exception' => $e]
Expand All @@ -178,7 +188,7 @@ public function delete(BeforeNodeDeletedEvent $event): void {
}
$this->log(
Operation::FileDeleted,
'File with id "%s" deleted: "%s"',
$this->appendRealPathText('File with id "%s" deleted: "%s"', $params),
$params,
array_keys($params)
);
Expand Down
5 changes: 3 additions & 2 deletions apps/admin_audit/lib/Listener/FileEventListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ private function beforePreviewFetched(BeforePreviewFetchedEvent $event): void {
'crop' => $event->isCrop(),
'mode' => $event->getMode(),
'path' => $file->getPath(),
];
] + $this->getRealPathParam('realPath', $file)
+ $this->getOwnerPathParam('ownerPath', $file);
$this->log(
Operation::PreviewAccessed,
'Preview accessed: (id: "%s", width: "%s", height: "%s" crop: "%s", mode: "%s", path: "%s")',
$this->appendRealPathText('Preview accessed: (id: "%s", width: "%s", height: "%s" crop: "%s", mode: "%s", path: "%s")', $params),
$params,
array_keys($params)
);
Expand Down
Loading
Loading