diff options
author | skjnldsv <skjnldsv@protonmail.com> | 2025-03-25 11:24:43 +0100 |
---|---|---|
committer | skjnldsv <skjnldsv@protonmail.com> | 2025-03-25 11:50:36 +0100 |
commit | 903971fddcdaa850d00edeec5927a3591767efdd (patch) | |
tree | 3b738d84c88012e9b1a249e1e1b96c4b6fa88883 | |
parent | a55519268fafdd21c834a705c64ff2a27369aae7 (diff) | |
download | nextcloud-server-fix/tag-fileid-check.tar.gz nextcloud-server-fix/tag-fileid-check.zip |
fix(dav): filter user files when updating tagsfix/tag-fileid-check
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
4 files changed, 70 insertions, 2 deletions
diff --git a/apps/dav/lib/SystemTag/SystemTagPlugin.php b/apps/dav/lib/SystemTag/SystemTagPlugin.php index d70eff17ac1..cbc9c6c1882 100644 --- a/apps/dav/lib/SystemTag/SystemTagPlugin.php +++ b/apps/dav/lib/SystemTag/SystemTagPlugin.php @@ -11,6 +11,8 @@ use OCA\DAV\Connector\Sabre\Directory; use OCA\DAV\Connector\Sabre\FilesPlugin; use OCA\DAV\Connector\Sabre\Node; use OCP\AppFramework\Http; +use OCP\Constants; +use OCP\Files\IRootFolder; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserSession; @@ -68,7 +70,8 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { protected ISystemTagManager $tagManager, protected IGroupManager $groupManager, protected IUserSession $userSession, - private ISystemTagObjectMapper $tagMapper, + protected IRootFolder $rootFolder, + protected ISystemTagObjectMapper $tagMapper, ) { } @@ -387,6 +390,11 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { } if (isset($props[self::OBJECTIDS_PROPERTYNAME])) { + $user = $this->userSession->getUser(); + if (!$user) { + throw new Forbidden('You don’t have permissions to update tags'); + } + $propValue = $props[self::OBJECTIDS_PROPERTYNAME]; if (!$propValue instanceof SystemTagsObjectList || count($propValue->getObjects()) === 0) { throw new BadRequest('Invalid object-ids property'); @@ -399,10 +407,35 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { throw new BadRequest('Invalid object-ids property. All object types must be of the same type: ' . $node->getName()); } + // Only files are supported at the moment + // Also see SystemTagsRelationsCollection file + if ($objectTypes[0] !== 'files') { + throw new BadRequest('Invalid object-ids property type. Only files are supported'); + } + + // Get all current tagged objects + $taggedObjects = $this->tagMapper->getObjectIdsForTags([$node->getSystemTag()->getId()], 'files'); + $toAddObjects = array_map(fn ($value) => (string)$value, array_keys($objects)); + + // Compute the tags to add and remove + $addedObjects = array_values(array_diff($toAddObjects, $taggedObjects)); + $removedObjects = array_values(array_diff($taggedObjects, $toAddObjects)); + + // Check permissions for each object to be freshly tagged or untagged + if (!$this->canUpdateTagForFileIds(array_merge($addedObjects, $removedObjects))) { + throw new Forbidden('You don’t have permissions to update tags'); + } + $this->tagMapper->setObjectIdsForTag($node->getSystemTag()->getId(), $node->getName(), array_keys($objects)); } if ($props[self::OBJECTIDS_PROPERTYNAME] === null) { + // Check the user have permissions to remove the tag from all currently tagged objects + $taggedObjects = $this->tagMapper->getObjectIdsForTags([$node->getSystemTag()->getId()], 'files'); + if (!$this->canUpdateTagForFileIds($taggedObjects)) { + throw new Forbidden('You don’t have permissions to update tags'); + } + $this->tagMapper->setObjectIdsForTag($node->getSystemTag()->getId(), $node->getName(), []); } @@ -483,4 +516,22 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { return true; }); } + + /** + * Check if the user can update the tag for the given file ids + * + * @param list<string> $fileIds + * @return bool + */ + private function canUpdateTagForFileIds(array $fileIds): bool { + $user = $this->userSession->getUser(); + $userFolder = $this->rootFolder->getUserFolder($user->getUID()); + foreach ($fileIds as $fileId) { + $userNode = $userFolder->getFirstNodeById((int)$fileId); + if (empty($userNode) || !(($userNode->getPermissions() & Constants::PERMISSION_UPDATE) === Constants::PERMISSION_UPDATE)) { + return false; + } + } + return true; + } } diff --git a/apps/dav/lib/SystemTag/SystemTagsObjectList.php b/apps/dav/lib/SystemTag/SystemTagsObjectList.php index 0743b8d8130..5ccc924eb53 100644 --- a/apps/dav/lib/SystemTag/SystemTagsObjectList.php +++ b/apps/dav/lib/SystemTag/SystemTagsObjectList.php @@ -31,6 +31,11 @@ class SystemTagsObjectList implements XmlSerializable, XmlDeserializable { ) { } + /** + * Get the object ids and their types. + * + * @return array<string, string> + */ public function getObjects(): array { return $this->objects; } @@ -55,7 +60,7 @@ class SystemTagsObjectList implements XmlSerializable, XmlDeserializable { } } if ($id !== '' && $type !== '') { - $objects[$id] = $type; + $objects[(string)$id] = (string)$type; } } } diff --git a/apps/dav/lib/SystemTag/SystemTagsRelationsCollection.php b/apps/dav/lib/SystemTag/SystemTagsRelationsCollection.php index dc0f1bc5d36..0839a5bc995 100644 --- a/apps/dav/lib/SystemTag/SystemTagsRelationsCollection.php +++ b/apps/dav/lib/SystemTag/SystemTagsRelationsCollection.php @@ -28,6 +28,8 @@ class SystemTagsRelationsCollection extends SimpleCollection { IRootFolder $rootFolder, ) { $children = [ + // Only files are supported at the moment + // Also see SystemTagPlugin::OBJECTIDS_PROPERTYNAME supported types new SystemTagsObjectTypeCollection( 'files', $tagManager, diff --git a/apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php b/apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php index e1517eec425..ab5253147a7 100644 --- a/apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php +++ b/apps/dav/tests/unit/SystemTag/SystemTagPluginTest.php @@ -12,6 +12,7 @@ use OCA\DAV\SystemTag\SystemTagNode; use OCA\DAV\SystemTag\SystemTagPlugin; use OCA\DAV\SystemTag\SystemTagsByIdCollection; use OCA\DAV\SystemTag\SystemTagsObjectMappingCollection; +use OCP\Files\IRootFolder; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserSession; @@ -57,6 +58,11 @@ class SystemTagPluginTest extends \Test\TestCase { private $userSession; /** + * @var IRootFolder + */ + private $rootFolder; + + /** * @var IUser */ private $user; @@ -95,13 +101,17 @@ class SystemTagPluginTest extends \Test\TestCase { ->expects($this->any()) ->method('isLoggedIn') ->willReturn(true); + $this->tagMapper = $this->getMockBuilder(ISystemTagObjectMapper::class) ->getMock(); + $this->rootFolder = $this->getMockBuilder(IRootFolder::class) + ->getMock(); $this->plugin = new SystemTagPlugin( $this->tagManager, $this->groupManager, $this->userSession, + $this->rootFolder, $this->tagMapper ); $this->plugin->initialize($this->server); |