From c2150bd0795ba05e1ec94734b12350f544b08ad4 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 13 Mar 2023 09:58:31 +0100 Subject: [PATCH 1/8] feat: Add mimetype into BeforePreviewFetchedEvent event Signed-off-by: Thomas Citharel --- lib/private/Preview/Generator.php | 1 + .../Preview/BeforePreviewFetchedEvent.php | 17 +++++++++++++---- tests/lib/Preview/GeneratorTest.php | 12 ++++++------ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php index 460637c9a99ca..c7eb312182501 100644 --- a/lib/private/Preview/Generator.php +++ b/lib/private/Preview/Generator.php @@ -80,6 +80,7 @@ public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $height, $crop, $mode, + $mimeType, )); // since we only ask for one preview, and the generate method return the last one it created, it returns the one we want diff --git a/lib/public/Preview/BeforePreviewFetchedEvent.php b/lib/public/Preview/BeforePreviewFetchedEvent.php index 398358d59054f..6aed6bcc7044e 100644 --- a/lib/public/Preview/BeforePreviewFetchedEvent.php +++ b/lib/public/Preview/BeforePreviewFetchedEvent.php @@ -17,6 +17,7 @@ * * @since 25.0.1 * @since 28.0.0 the constructor arguments ``$width``, ``$height``, ``$crop`` and ``$mode`` are no longer nullable. + * @since 31.0.0 the constructor arguments ``$mimeType`` was added */ class BeforePreviewFetchedEvent extends \OCP\EventDispatcher\Event { /** @@ -24,14 +25,15 @@ class BeforePreviewFetchedEvent extends \OCP\EventDispatcher\Event { */ public function __construct( private Node $node, - /** @deprecated 28.0.0 null deprecated **/ + /** @deprecated 28.0.0 passing null is deprecated **/ private ?int $width = null, - /** @deprecated 28.0.0 null deprecated **/ + /** @deprecated 28.0.0 passing null is null deprecated **/ private ?int $height = null, - /** @deprecated 28.0.0 null deprecated **/ + /** @deprecated 28.0.0 passing null is null deprecated **/ private ?bool $crop = null, - /** @deprecated 28.0.0 null deprecated **/ + /** @deprecated 28.0.0 passing null is null deprecated **/ private ?string $mode = null, + private ?string $mimeType = null, ) { parent::__construct(); } @@ -71,4 +73,11 @@ public function isCrop(): ?bool { public function getMode(): ?string { return $this->mode; } + + /** + * @since 31.0.0 + */ + public function getMimeType(): ?string { + return $this->mimeType; + } } diff --git a/tests/lib/Preview/GeneratorTest.php b/tests/lib/Preview/GeneratorTest.php index caac15c353227..d458062f5615a 100644 --- a/tests/lib/Preview/GeneratorTest.php +++ b/tests/lib/Preview/GeneratorTest.php @@ -91,7 +91,7 @@ public function testGetCachedPreview() { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped') - ->with(new BeforePreviewFetchedEvent($file, 100, 100, false, IPreview::MODE_FILL)); + ->with(new BeforePreviewFetchedEvent($file, 100, 100, false, IPreview::MODE_FILL, null)); $result = $this->generator->getPreview($file, 100, 100); $this->assertSame($previewFile, $result); @@ -219,7 +219,7 @@ public function testGetNewPreview() { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped') - ->with(new BeforePreviewFetchedEvent($file, 100, 100, false, IPreview::MODE_FILL)); + ->with(new BeforePreviewFetchedEvent($file, 100, 100, false, IPreview::MODE_FILL, null)); $result = $this->generator->getPreview($file, 100, 100); $this->assertSame($previewFile, $result); @@ -258,7 +258,7 @@ public function testInvalidMimeType() { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped') - ->with(new BeforePreviewFetchedEvent($file, 1024, 512, true, IPreview::MODE_COVER)); + ->with(new BeforePreviewFetchedEvent($file, 1024, 512, true, IPreview::MODE_COVER, 'invalidType')); $this->generator->getPreview($file, 1024, 512, true, IPreview::MODE_COVER, 'invalidType'); } @@ -295,7 +295,7 @@ public function testReturnCachedPreviewsWithoutCheckingSupportedMimetype() { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped') - ->with(new BeforePreviewFetchedEvent($file, 1024, 512, true, IPreview::MODE_COVER)); + ->with(new BeforePreviewFetchedEvent($file, 1024, 512, true, IPreview::MODE_COVER, 'invalidType')); $result = $this->generator->getPreview($file, 1024, 512, true, IPreview::MODE_COVER, 'invalidType'); $this->assertSame($preview, $result); @@ -323,7 +323,7 @@ public function testNoProvider() { $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped') - ->with(new BeforePreviewFetchedEvent($file, 100, 100, false, IPreview::MODE_FILL)); + ->with(new BeforePreviewFetchedEvent($file, 100, 100, false, IPreview::MODE_FILL, null)); $this->expectException(NotFoundException::class); $this->generator->getPreview($file, 100, 100); @@ -448,7 +448,7 @@ public function testCorrectSize($maxX, $maxY, $reqX, $reqY, $crop, $mode, $expec $this->eventDispatcher->expects($this->once()) ->method('dispatchTyped') - ->with(new BeforePreviewFetchedEvent($file, $reqX, $reqY, $crop, $mode)); + ->with(new BeforePreviewFetchedEvent($file, $reqX, $reqY, $crop, $mode, null)); $result = $this->generator->getPreview($file, $reqX, $reqY, $crop, $mode); if ($expectedX === $maxX && $expectedY === $maxY) { From 82ba7d763bb5fe2fea67df0475ba2516389575ae Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 13 Mar 2023 11:05:52 +0100 Subject: [PATCH 2/8] chore: Code cleanup in lib/private/Console/Application Signed-off-by: Thomas Citharel --- lib/private/Console/Application.php | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php index 16ed889438626..22dc8d0c65eb3 100644 --- a/lib/private/Console/Application.php +++ b/lib/private/Console/Application.php @@ -7,14 +7,18 @@ */ namespace OC\Console; +use ArgumentCountError; use OC\MemoryInfo; use OC\NeedsUpdateException; +use OC\SystemConfig; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; use OCP\Console\ConsoleEvent; +use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IRequest; +use OCP\Server; use Psr\Container\ContainerExceptionInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Application as SymfonyApplication; @@ -33,8 +37,8 @@ public function __construct( private LoggerInterface $logger, private MemoryInfo $memoryInfo, private IAppManager $appManager, + private Defaults $defaults, ) { - $defaults = \OC::$server->get('ThemingDefaults'); $this->application = new SymfonyApplication($defaults->getName(), \OC_Util::getVersionString()); } @@ -44,7 +48,7 @@ public function __construct( public function loadCommands( InputInterface $input, ConsoleOutputInterface $output - ) { + ): void { // $application is required to be defined in the register_command scripts $application = $this->application; $inputDefinition = $application->getDefinition(); @@ -118,7 +122,7 @@ public function loadCommands( $errorOutput = $output->getErrorOutput(); $errorOutput->writeln('Nextcloud is not installed - only a limited number of commands are available'); } - } catch (NeedsUpdateException $e) { + } catch (NeedsUpdateException) { if ($input->getArgument('command') !== '_completion') { $errorOutput = $output->getErrorOutput(); $errorOutput->writeln('Nextcloud or one of the apps require upgrade - only a limited number of commands are available'); @@ -127,7 +131,7 @@ public function loadCommands( } if ($input->getFirstArgument() !== 'check') { - $errors = \OC_Util::checkServer(\OC::$server->getSystemConfig()); + $errors = \OC_Util::checkServer(Server::get(SystemConfig::class)); if (!empty($errors)) { foreach ($errors as $error) { $output->writeln((string)$error['error']); @@ -163,13 +167,11 @@ private function writeMaintenanceModeInfo(InputInterface $input, ConsoleOutputIn * * @param bool $boolean Whether to automatically exit after a command execution or not */ - public function setAutoExit($boolean) { + public function setAutoExit(bool $boolean): void { $this->application->setAutoExit($boolean); } /** - * @param InputInterface $input - * @param OutputInterface $output * @return int * @throws \Exception */ @@ -183,15 +185,18 @@ public function run(?InputInterface $input = null, ?OutputInterface $output = nu return $this->application->run($input, $output); } - private function loadCommandsFromInfoXml($commands) { + /** + * @throws \Exception + */ + private function loadCommandsFromInfoXml(iterable $commands): void { foreach ($commands as $command) { try { - $c = \OCP\Server::get($command); + $c = Server::get($command); } catch (ContainerExceptionInterface $e) { if (class_exists($command)) { try { $c = new $command(); - } catch (\ArgumentCountError $e2) { + } catch (ArgumentCountError) { throw new \Exception("Failed to construct console command '$command': " . $e->getMessage(), 0, $e); } } else { From 986a3d45f8fab60c8e7dddc7015bd60c6ee356d4 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 13 Mar 2023 18:46:30 +0100 Subject: [PATCH 3/8] feat(user_ldap): Introduce user id assigned typed events for LDAP usage Based on work from https://github.com/nextcloud/server/pull/32019 Signed-off-by: Thomas Citharel --- apps/user_ldap/ajax/clearMappings.php | 15 +- apps/user_ldap/lib/Access.php | 19 +- apps/user_ldap/lib/AccessFactory.php | 8 +- apps/user_ldap/lib/Jobs/Sync.php | 172 +++++------------- apps/user_ldap/tests/AccessTest.php | 44 +++-- apps/user_ldap/tests/Jobs/SyncTest.php | 71 ++++---- lib/composer/composer/autoload_classmap.php | 3 + lib/composer/composer/autoload_static.php | 3 + .../Events/BeforeUserIdUnassignedEvent.php | 33 ++++ .../User/Events/UserIdAssignedEvent.php | 33 ++++ .../User/Events/UserIdUnassignedEvent.php | 33 ++++ 11 files changed, 241 insertions(+), 193 deletions(-) create mode 100644 lib/public/User/Events/BeforeUserIdUnassignedEvent.php create mode 100644 lib/public/User/Events/UserIdAssignedEvent.php create mode 100644 lib/public/User/Events/UserIdUnassignedEvent.php diff --git a/apps/user_ldap/ajax/clearMappings.php b/apps/user_ldap/ajax/clearMappings.php index 0616281b41503..bd866769cc844 100644 --- a/apps/user_ldap/ajax/clearMappings.php +++ b/apps/user_ldap/ajax/clearMappings.php @@ -5,8 +5,13 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + use OCA\User_LDAP\Mapping\GroupMapping; use OCA\User_LDAP\Mapping\UserMapping; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Server; +use OCP\User\Events\BeforeUserIdUnassignedEvent; +use OCP\User\Events\UserIdUnassignedEvent; // Check user and app status \OC_JSON::checkAdminUser(); @@ -17,12 +22,16 @@ $mapping = null; try { if ($subject === 'user') { - $mapping = \OCP\Server::get(UserMapping::class); + $mapping = Server::get(UserMapping::class); + /** @var IEventDispatcher $dispatcher */ + $dispatcher = Server::get(IEventDispatcher::class); $result = $mapping->clearCb( - function ($uid) { + function (string $uid) use ($dispatcher): void { + $dispatcher->dispatchTyped(new BeforeUserIdUnassignedEvent($uid)); \OC::$server->getUserManager()->emit('\OC\User', 'preUnassignedUserId', [$uid]); }, - function ($uid) { + function (string $uid) use ($dispatcher): void { + $dispatcher->dispatchTyped(new UserIdUnassignedEvent($uid)); \OC::$server->getUserManager()->emit('\OC\User', 'postUnassignedUserId', [$uid]); } ); diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index 66d1e7d6c1414..6a93534a00a6a 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -15,10 +15,12 @@ use OCA\User_LDAP\Mapping\AbstractMapping; use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; +use OCP\EventDispatcher\IEventDispatcher; use OCP\HintException; use OCP\IAppConfig; use OCP\IConfig; use OCP\IUserManager; +use OCP\User\Events\UserIdAssignedEvent; use Psr\Log\LoggerInterface; use function strlen; use function substr; @@ -42,6 +44,7 @@ class Access extends LDAPUtility { /** @var ?AbstractMapping */ protected $groupMapper; + private string $lastCookie = ''; public function __construct( @@ -53,15 +56,10 @@ public function __construct( private IUserManager $ncUserManager, private LoggerInterface $logger, private IAppConfig $appConfig, + private IEventDispatcher $dispatcher, ) { parent::__construct($ldap); - $this->connection = $connection; - $this->userManager = $userManager; $this->userManager->setLdapAccess($this); - $this->helper = $helper; - $this->config = $config; - $this->ncUserManager = $ncUserManager; - $this->logger = $logger; } /** @@ -630,10 +628,13 @@ public function mapAndAnnounceIfApplicable( bool $isUser ): bool { if ($mapper->map($fdn, $name, $uuid)) { - if ($this->ncUserManager instanceof PublicEmitter && $isUser) { + if ($isUser) { $this->cacheUserExists($name); - $this->ncUserManager->emit('\OC\User', 'assignedUserId', [$name]); - } elseif (!$isUser) { + $this->dispatcher->dispatchTyped(new UserIdAssignedEvent($name)); + if ($this->ncUserManager instanceof PublicEmitter) { + $this->ncUserManager->emit('\OC\User', 'assignedUserId', [$name]); + } + } else { $this->cacheGroupExists($name); } return true; diff --git a/apps/user_ldap/lib/AccessFactory.php b/apps/user_ldap/lib/AccessFactory.php index 28f88e3c4e91b..c5c8ca17e417d 100644 --- a/apps/user_ldap/lib/AccessFactory.php +++ b/apps/user_ldap/lib/AccessFactory.php @@ -6,6 +6,7 @@ namespace OCA\User_LDAP; use OCA\User_LDAP\User\Manager; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAppConfig; use OCP\IConfig; use OCP\IUserManager; @@ -21,12 +22,8 @@ public function __construct( private IAppConfig $appConfig, private IUserManager $ncUserManager, private LoggerInterface $logger, + private IEventDispatcher $dispatcher, ) { - $this->ldap = $ldap; - $this->helper = $helper; - $this->config = $config; - $this->ncUserManager = $ncUserManager; - $this->logger = $logger; } public function get(Connection $connection): Access { @@ -40,6 +37,7 @@ public function get(Connection $connection): Access { $this->ncUserManager, $this->logger, $this->appConfig, + $this->dispatcher, ); } } diff --git a/apps/user_ldap/lib/Jobs/Sync.php b/apps/user_ldap/lib/Jobs/Sync.php index b8b792181448f..26888ae96aeb1 100644 --- a/apps/user_ldap/lib/Jobs/Sync.php +++ b/apps/user_ldap/lib/Jobs/Sync.php @@ -1,8 +1,10 @@ setInterval( - (int)\OC::$server->getConfig()->getAppValue( + (int)$this->config->getAppValue( 'user_ldap', 'background_sync_interval', (string)self::MIN_INTERVAL ) ); + $this->ldap = new LDAP($this->config->getSystemValueString('ldap_log_file')); } /** - * updates the interval + * Updates the interval * - * the idea is to adjust the interval depending on the amount of known users + * The idea is to adjust the interval depending on the amount of known users * and the attempt to update each user one day. At most it would run every * 30 minutes, and at least every 12 hours. */ @@ -79,9 +76,8 @@ public function updateInterval() { /** * returns the smallest configured paging size - * @return int */ - protected function getMinPagingSize() { + protected function getMinPagingSize(): int { $configKeys = $this->config->getAppKeys('user_ldap'); $configKeys = array_filter($configKeys, function ($key) { return str_contains($key, 'ldap_paging_size'); @@ -98,8 +94,6 @@ protected function getMinPagingSize() { * @param array $argument */ public function run($argument) { - $this->setArgument($argument); - $isBackgroundJobModeAjax = $this->config ->getAppValue('core', 'backgroundjobs_mode', 'ajax') === 'ajax'; if ($isBackgroundJobModeAjax) { @@ -134,10 +128,10 @@ public function run($argument) { } /** - * @param array $cycleData + * @param array{offset: int, prefix: string} $cycleData * @return bool whether more results are expected from the same configuration */ - public function runCycle($cycleData) { + public function runCycle(array $cycleData): bool { $connection = $this->connectionFactory->get($cycleData['prefix']); $access = $this->accessFactory->get($connection); $access->setUserMapper($this->mapper); @@ -162,24 +156,22 @@ public function runCycle($cycleData) { } /** - * returns the info about the current cycle that should be run, if any, + * Returns the info about the current cycle that should be run, if any, * otherwise null - * - * @return array|null */ - public function getCycle() { + public function getCycle(): ?array { $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true); if (count($prefixes) === 0) { return null; } $cycleData = [ - 'prefix' => $this->config->getAppValue('user_ldap', 'background_sync_prefix', null), + 'prefix' => $this->config->getAppValue('user_ldap', 'background_sync_prefix', 'none'), 'offset' => (int)$this->config->getAppValue('user_ldap', 'background_sync_offset', '0'), ]; if ( - $cycleData['prefix'] !== null + $cycleData['prefix'] !== 'none' && in_array($cycleData['prefix'], $prefixes) ) { return $cycleData; @@ -191,21 +183,21 @@ public function getCycle() { /** * Save the provided cycle information in the DB * - * @param array $cycleData + * @param array{prefix: ?string, offset: int} $cycleData */ - public function setCycle(array $cycleData) { + public function setCycle(array $cycleData): void { $this->config->setAppValue('user_ldap', 'background_sync_prefix', $cycleData['prefix']); - $this->config->setAppValue('user_ldap', 'background_sync_offset', $cycleData['offset']); + $this->config->setAppValue('user_ldap', 'background_sync_offset', (string)$cycleData['offset']); } /** * returns data about the next cycle that should run, if any, otherwise * null. It also always goes for the next LDAP configuration! * - * @param array|null $cycleData the old cycle - * @return array|null + * @param ?array{prefix: string, offset: int} $cycleData the old cycle + * @return ?array{prefix: string, offset: int} */ - public function determineNextCycle(?array $cycleData = null) { + public function determineNextCycle(?array $cycleData = null): ?array { $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true); if (count($prefixes) === 0) { return null; @@ -225,13 +217,12 @@ public function determineNextCycle(?array $cycleData = null) { } /** - * Checks whether the provided cycle should be run. Currently only the + * Checks whether the provided cycle should be run. Currently, only the * last configuration change goes into account (at least one hour). * - * @param $cycleData - * @return bool + * @param array{prefix: string} $cycleData */ - public function qualifiesToRun($cycleData) { + public function qualifiesToRun(array $cycleData): bool { $lastChange = (int)$this->config->getAppValue('user_ldap', $cycleData['prefix'] . '_lastChange', '0'); if ((time() - $lastChange) > 60 * 30) { return true; @@ -240,23 +231,20 @@ public function qualifiesToRun($cycleData) { } /** - * increases the offset of the current cycle for the next run + * Increases the offset of the current cycle for the next run * - * @param $cycleData + * @param array{prefix: string, offset: int} $cycleData */ - protected function increaseOffset($cycleData) { + protected function increaseOffset(array $cycleData): void { $ldapConfig = new Configuration($cycleData['prefix']); $cycleData['offset'] += (int)$ldapConfig->ldapPagingSize; $this->setCycle($cycleData); } /** - * determines the next configuration prefix based on the last one (if any) - * - * @param string|null $lastPrefix - * @return string|null + * Determines the next configuration prefix based on the last one (if any) */ - protected function getNextPrefix($lastPrefix) { + protected function getNextPrefix(?string $lastPrefix): ?string { $prefixes = $this->ldapHelper->getServerConfigurationPrefixes(true); $noOfPrefixes = count($prefixes); if ($noOfPrefixes === 0) { @@ -276,73 +264,9 @@ protected function getNextPrefix($lastPrefix) { } /** - * "fixes" DI + * Only used in tests */ - public function setArgument($argument) { - if (isset($argument['config'])) { - $this->config = $argument['config']; - } else { - $this->config = \OC::$server->getConfig(); - } - - if (isset($argument['helper'])) { - $this->ldapHelper = $argument['helper']; - } else { - $this->ldapHelper = new Helper($this->config, \OC::$server->getDatabaseConnection()); - } - - if (isset($argument['ldapWrapper'])) { - $this->ldap = $argument['ldapWrapper']; - } else { - $this->ldap = new LDAP($this->config->getSystemValueString('ldap_log_file')); - } - - if (isset($argument['avatarManager'])) { - $this->avatarManager = $argument['avatarManager']; - } else { - $this->avatarManager = \OC::$server->get(IAvatarManager::class); - } - - if (isset($argument['dbc'])) { - $this->dbc = $argument['dbc']; - } else { - $this->dbc = \OC::$server->getDatabaseConnection(); - } - - if (isset($argument['ncUserManager'])) { - $this->ncUserManager = $argument['ncUserManager']; - } else { - $this->ncUserManager = \OC::$server->getUserManager(); - } - - if (isset($argument['logger'])) { - $this->logger = $argument['logger']; - } else { - $this->logger = \OC::$server->get(LoggerInterface::class); - } - - if (isset($argument['notificationManager'])) { - $this->notificationManager = $argument['notificationManager']; - } else { - $this->notificationManager = \OC::$server->getNotificationManager(); - } - - if (isset($argument['mapper'])) { - $this->mapper = $argument['mapper']; - } else { - $this->mapper = \OCP\Server::get(UserMapping::class); - } - - if (isset($argument['connectionFactory'])) { - $this->connectionFactory = $argument['connectionFactory']; - } else { - $this->connectionFactory = new ConnectionFactory($this->ldap); - } - - if (isset($argument['accessFactory'])) { - $this->accessFactory = $argument['accessFactory']; - } else { - $this->accessFactory = \OCP\Server::get(AccessFactory::class); - } + public function overwritePropertiesForTest(LDAP $ldapWrapper): void { + $this->ldap = $ldapWrapper; } } diff --git a/apps/user_ldap/tests/AccessTest.php b/apps/user_ldap/tests/AccessTest.php index 62c508fdb0925..b04a9f69e0be0 100644 --- a/apps/user_ldap/tests/AccessTest.php +++ b/apps/user_ldap/tests/AccessTest.php @@ -18,6 +18,7 @@ use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User\OfflineUser; use OCA\User_LDAP\User\User; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAppConfig; use OCP\IAvatarManager; use OCP\IConfig; @@ -37,29 +38,31 @@ * @package OCA\User_LDAP\Tests */ class AccessTest extends TestCase { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ + /** @var UserMapping|MockObject */ protected $userMapper; - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IManager|MockObject */ protected $shareManager; - /** @var GroupMapping|\PHPUnit\Framework\MockObject\MockObject */ + /** @var GroupMapping|MockObject */ protected $groupMapper; - /** @var Connection|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Connection|MockObject */ private $connection; - /** @var LDAP|\PHPUnit\Framework\MockObject\MockObject */ + /** @var LDAP|MockObject */ private $ldap; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Manager|MockObject */ private $userManager; - /** @var Helper|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Helper|MockObject */ private $helper; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IConfig|MockObject */ private $config; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IUserManager|MockObject */ private $ncUserManager; private LoggerInterface&MockObject $logger; private IAppConfig&MockObject $appConfig; + /** @var IEventDispatcher|MockObject */ + private $dispatcher; private Access $access; protected function setUp(): void { @@ -74,6 +77,7 @@ protected function setUp(): void { $this->shareManager = $this->createMock(IManager::class); $this->logger = $this->createMock(LoggerInterface::class); $this->appConfig = $this->createMock(IAppConfig::class); + $this->dispatcher = $this->createMock(IEventDispatcher::class); $this->access = new Access( $this->ldap, @@ -84,7 +88,9 @@ protected function setUp(): void { $this->ncUserManager, $this->logger, $this->appConfig, + $this->dispatcher, ); + $this->dispatcher->expects($this->any())->method('dispatchTyped'); $this->access->setUserMapper($this->userMapper); $this->access->setGroupMapper($this->groupMapper); } @@ -227,9 +233,9 @@ public function dnInputDataProvider() { */ public function testStringResemblesDN($case) { [$lw, $con, $um, $helper] = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ + /** @var IConfig|MockObject $config */ $config = $this->createMock(IConfig::class); - $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig); + $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig, $this->dispatcher); $lw->expects($this->exactly(1)) ->method('explodeDN') @@ -249,10 +255,10 @@ public function testStringResemblesDN($case) { */ public function testStringResemblesDNLDAPmod($case) { [, $con, $um, $helper] = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ + /** @var IConfig|MockObject $config */ $config = $this->createMock(IConfig::class); $lw = new LDAP(); - $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig); + $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig, $this->dispatcher); if (!function_exists('ldap_explode_dn')) { $this->markTestSkipped('LDAP Module not available'); @@ -282,7 +288,7 @@ public function testBatchApplyUserAttributes() { ->method('getAttributes') ->willReturn(['displayname' => ['bar', 'count' => 1]]); - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ + /** @var UserMapping|MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') @@ -327,7 +333,7 @@ public function testBatchApplyUserAttributes() { } public function testBatchApplyUserAttributesSkipped() { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ + /** @var UserMapping|MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') @@ -368,7 +374,7 @@ public function testBatchApplyUserAttributesSkipped() { } public function testBatchApplyUserAttributesDontSkip() { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ + /** @var UserMapping|MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') @@ -424,7 +430,7 @@ public function dNAttributeProvider() { */ public function testSanitizeDN($attribute) { [$lw, $con, $um, $helper] = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ + /** @var IConfig|MockObject $config */ $config = $this->createMock(IConfig::class); $dnFromServer = 'cn=Mixed Cases,ou=Are Sufficient To,ou=Test,dc=example,dc=org'; @@ -438,7 +444,7 @@ public function testSanitizeDN($attribute) { $attribute => ['count' => 1, $dnFromServer] ]); - $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig); + $access = new Access($lw, $con, $um, $helper, $config, $this->ncUserManager, $this->logger, $this->appConfig, $this->dispatcher); $values = $access->readAttribute('uid=whoever,dc=example,dc=org', $attribute); $this->assertSame($values[0], strtolower($dnFromServer)); } @@ -744,7 +750,7 @@ public function testUserStateUpdate() { ->with('detta') ->willReturnOnConsecutiveCalls($offlineUserMock, $regularUserMock); - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ + /** @var UserMapping|MockObject $mapperMock */ $mapperMock = $this->createMock(UserMapping::class); $mapperMock->expects($this->any()) ->method('getNameByDN') diff --git a/apps/user_ldap/tests/Jobs/SyncTest.php b/apps/user_ldap/tests/Jobs/SyncTest.php index 0f5f045ac7fdc..379402166e36f 100644 --- a/apps/user_ldap/tests/Jobs/SyncTest.php +++ b/apps/user_ldap/tests/Jobs/SyncTest.php @@ -15,39 +15,42 @@ use OCA\User_LDAP\Mapping\UserMapping; use OCA\User_LDAP\User\Manager; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAvatarManager; use OCP\IConfig; use OCP\IDBConnection; use OCP\IUserManager; use OCP\Notification\IManager; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; class SyncTest extends TestCase { /** @var array */ protected $arguments; - /** @var Helper|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Helper|MockObject */ protected $helper; - /** @var LDAP|\PHPUnit\Framework\MockObject\MockObject */ + /** @var LDAP|MockObject */ protected $ldapWrapper; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var Manager|MockObject */ protected $userManager; - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ + /** @var UserMapping|MockObject */ protected $mapper; - /** @var Sync */ - protected $sync; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ + protected Sync $sync; + /** @var IConfig|MockObject */ protected $config; - /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IAvatarManager|MockObject */ protected $avatarManager; - /** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IDBConnection|MockObject */ protected $dbc; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IUserManager|MockObject */ protected $ncUserManager; - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ + /** @var IManager|MockObject */ protected $notificationManager; - /** @var ConnectionFactory|\PHPUnit\Framework\MockObject\MockObject */ + /** @var ConnectionFactory|MockObject */ protected $connectionFactory; - /** @var AccessFactory|\PHPUnit\Framework\MockObject\MockObject */ + /** @var AccessFactory|MockObject */ protected $accessFactory; protected function setUp(): void { @@ -65,23 +68,25 @@ protected function setUp(): void { $this->connectionFactory = $this->createMock(ConnectionFactory::class); $this->accessFactory = $this->createMock(AccessFactory::class); - $this->arguments = [ - 'helper' => $this->helper, - 'ldapWrapper' => $this->ldapWrapper, - 'mapper' => $this->mapper, - 'config' => $this->config, - 'avatarManager' => $this->avatarManager, - 'dbc' => $this->dbc, - 'ncUserManager' => $this->ncUserManager, - 'notificationManager' => $this->notificationManager, - 'connectionFactory' => $this->connectionFactory, - 'accessFactory' => $this->accessFactory, - ]; - - $this->sync = new Sync($this->createMock(ITimeFactory::class)); + $this->sync = new Sync( + Server::get(ITimeFactory::class), + Server::get(IEventDispatcher::class), + $this->config, + $this->dbc, + $this->avatarManager, + $this->ncUserManager, + Server::get(LoggerInterface::class), + $this->notificationManager, + $this->mapper, + $this->helper, + $this->connectionFactory, + $this->accessFactory, + ); + + $this->sync->overwritePropertiesForTest($this->ldapWrapper); } - public function intervalDataProvider() { + public function intervalDataProvider(): array { return [ [ 0, 1000, 750 @@ -104,7 +109,7 @@ public function intervalDataProvider() { /** * @dataProvider intervalDataProvider */ - public function testUpdateInterval($userCount, $pagingSize1, $pagingSize2) { + public function testUpdateInterval(int $userCount, int $pagingSize1, int $pagingSize2): void { $this->config->expects($this->once()) ->method('setAppValue') ->with('user_ldap', 'background_sync_interval', $this->anything()) @@ -161,7 +166,7 @@ public function testMoreResults($pagingSize, $results, $expected) { return null; }); - /** @var Access|\PHPUnit\Framework\MockObject\MockObject $access */ + /** @var Access|MockObject $access */ $access = $this->createMock(Access::class); $this->accessFactory->expects($this->any()) ->method('get') @@ -231,7 +236,7 @@ public function testDetermineNextCycle($cycleData, $prefixes, $expectedCycle) { } } - public function testQualifiesToRun() { + public function testQualifiesToRun(): void { $cycleData = ['prefix' => 's01']; $this->config->expects($this->exactly(2)) @@ -243,7 +248,7 @@ public function testQualifiesToRun() { $this->assertFalse($this->sync->qualifiesToRun($cycleData)); } - public function runDataProvider() { + public function runDataProvider(): array { return [ #0 - one LDAP server, reset [[ @@ -335,7 +340,7 @@ public function testRun($runData) { return null; }); - /** @var Access|\PHPUnit\Framework\MockObject\MockObject $access */ + /** @var Access|MockObject $access */ $access = $this->createMock(Access::class); $this->accessFactory->expects($this->any()) ->method('get') diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 4bd8f96454e25..1da6c7994fe88 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -854,6 +854,7 @@ 'OCP\\User\\Events\\BeforePasswordUpdatedEvent' => $baseDir . '/lib/public/User/Events/BeforePasswordUpdatedEvent.php', 'OCP\\User\\Events\\BeforeUserCreatedEvent' => $baseDir . '/lib/public/User/Events/BeforeUserCreatedEvent.php', 'OCP\\User\\Events\\BeforeUserDeletedEvent' => $baseDir . '/lib/public/User/Events/BeforeUserDeletedEvent.php', + 'OCP\\User\\Events\\BeforeUserIdUnassignedEvent' => $baseDir . '/lib/public/User/Events/BeforeUserIdUnassignedEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedInEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInWithCookieEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedInWithCookieEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedOutEvent' => $baseDir . '/lib/public/User/Events/BeforeUserLoggedOutEvent.php', @@ -868,6 +869,8 @@ 'OCP\\User\\Events\\UserCreatedEvent' => $baseDir . '/lib/public/User/Events/UserCreatedEvent.php', 'OCP\\User\\Events\\UserDeletedEvent' => $baseDir . '/lib/public/User/Events/UserDeletedEvent.php', 'OCP\\User\\Events\\UserFirstTimeLoggedInEvent' => $baseDir . '/lib/public/User/Events/UserFirstTimeLoggedInEvent.php', + 'OCP\\User\\Events\\UserIdAssignedEvent' => $baseDir . '/lib/public/User/Events/UserIdAssignedEvent.php', + 'OCP\\User\\Events\\UserIdUnassignedEvent' => $baseDir . '/lib/public/User/Events/UserIdUnassignedEvent.php', 'OCP\\User\\Events\\UserLiveStatusEvent' => $baseDir . '/lib/public/User/Events/UserLiveStatusEvent.php', 'OCP\\User\\Events\\UserLoggedInEvent' => $baseDir . '/lib/public/User/Events/UserLoggedInEvent.php', 'OCP\\User\\Events\\UserLoggedInWithCookieEvent' => $baseDir . '/lib/public/User/Events/UserLoggedInWithCookieEvent.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index a9737d27c8373..a4b1ec64c37a9 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -887,6 +887,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\User\\Events\\BeforePasswordUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforePasswordUpdatedEvent.php', 'OCP\\User\\Events\\BeforeUserCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserCreatedEvent.php', 'OCP\\User\\Events\\BeforeUserDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserDeletedEvent.php', + 'OCP\\User\\Events\\BeforeUserIdUnassignedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserIdUnassignedEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedInEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedInWithCookieEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedInWithCookieEvent.php', 'OCP\\User\\Events\\BeforeUserLoggedOutEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/BeforeUserLoggedOutEvent.php', @@ -901,6 +902,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\User\\Events\\UserCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserCreatedEvent.php', 'OCP\\User\\Events\\UserDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserDeletedEvent.php', 'OCP\\User\\Events\\UserFirstTimeLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserFirstTimeLoggedInEvent.php', + 'OCP\\User\\Events\\UserIdAssignedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserIdAssignedEvent.php', + 'OCP\\User\\Events\\UserIdUnassignedEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserIdUnassignedEvent.php', 'OCP\\User\\Events\\UserLiveStatusEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLiveStatusEvent.php', 'OCP\\User\\Events\\UserLoggedInEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLoggedInEvent.php', 'OCP\\User\\Events\\UserLoggedInWithCookieEvent' => __DIR__ . '/../../..' . '/lib/public/User/Events/UserLoggedInWithCookieEvent.php', diff --git a/lib/public/User/Events/BeforeUserIdUnassignedEvent.php b/lib/public/User/Events/BeforeUserIdUnassignedEvent.php new file mode 100644 index 0000000000000..744ecd8909fd6 --- /dev/null +++ b/lib/public/User/Events/BeforeUserIdUnassignedEvent.php @@ -0,0 +1,33 @@ +userId; + } +} diff --git a/lib/public/User/Events/UserIdAssignedEvent.php b/lib/public/User/Events/UserIdAssignedEvent.php new file mode 100644 index 0000000000000..63daca098203c --- /dev/null +++ b/lib/public/User/Events/UserIdAssignedEvent.php @@ -0,0 +1,33 @@ +userId; + } +} diff --git a/lib/public/User/Events/UserIdUnassignedEvent.php b/lib/public/User/Events/UserIdUnassignedEvent.php new file mode 100644 index 0000000000000..db8861b98a4d9 --- /dev/null +++ b/lib/public/User/Events/UserIdUnassignedEvent.php @@ -0,0 +1,33 @@ +userId; + } +} From f532d3b2861642b0bc7b70aed8b7f95706b24bb0 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 13 Mar 2023 09:57:55 +0100 Subject: [PATCH 4/8] feat(admin_audit): Move admin_audit hooks to modern event listeners Signed-off-by: Thomas Citharel --- .../composer/composer/autoload_classmap.php | 13 +- .../composer/composer/autoload_static.php | 13 +- .../admin_audit/lib/Actions/AppManagement.php | 42 --- apps/admin_audit/lib/Actions/Auth.php | 45 --- apps/admin_audit/lib/Actions/Console.php | 28 -- .../lib/Actions/GroupManagement.php | 87 ----- apps/admin_audit/lib/Actions/Security.php | 60 ---- .../lib/Actions/UserManagement.php | 80 ----- apps/admin_audit/lib/AppInfo/Application.php | 181 +++++------ apps/admin_audit/lib/AuditLogger.php | 3 + .../Listener/AppManagementEventListener.php | 76 +++++ .../lib/Listener/AuthEventListener.php | 83 +++++ .../lib/Listener/ConsoleEventListener.php | 42 +++ .../lib/Listener/FileEventListener.php | 64 ++++ .../Listener/GroupManagementEventListener.php | 97 ++++++ .../lib/Listener/SecurityEventListener.php | 77 +++++ .../lib/Listener/SharingEventListener.php | 307 ++++++++++++++++++ .../Listener/UserManagementEventListener.php | 142 ++++++++ .../SecurityEventListenerTest.php} | 35 +- 19 files changed, 998 insertions(+), 477 deletions(-) delete mode 100644 apps/admin_audit/lib/Actions/AppManagement.php delete mode 100644 apps/admin_audit/lib/Actions/Auth.php delete mode 100644 apps/admin_audit/lib/Actions/Console.php delete mode 100644 apps/admin_audit/lib/Actions/GroupManagement.php delete mode 100644 apps/admin_audit/lib/Actions/Security.php create mode 100644 apps/admin_audit/lib/Listener/AppManagementEventListener.php create mode 100644 apps/admin_audit/lib/Listener/AuthEventListener.php create mode 100644 apps/admin_audit/lib/Listener/ConsoleEventListener.php create mode 100644 apps/admin_audit/lib/Listener/FileEventListener.php create mode 100644 apps/admin_audit/lib/Listener/GroupManagementEventListener.php create mode 100644 apps/admin_audit/lib/Listener/SecurityEventListener.php create mode 100644 apps/admin_audit/lib/Listener/SharingEventListener.php create mode 100644 apps/admin_audit/lib/Listener/UserManagementEventListener.php rename apps/admin_audit/tests/{Actions/SecurityTest.php => Listener/SecurityEventListenerTest.php} (56%) diff --git a/apps/admin_audit/composer/composer/autoload_classmap.php b/apps/admin_audit/composer/composer/autoload_classmap.php index 8bfa01ccfdc8a..b73c4b9b3a541 100644 --- a/apps/admin_audit/composer/composer/autoload_classmap.php +++ b/apps/admin_audit/composer/composer/autoload_classmap.php @@ -8,12 +8,7 @@ return array( 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'OCA\\AdminAudit\\Actions\\Action' => $baseDir . '/../lib/Actions/Action.php', - 'OCA\\AdminAudit\\Actions\\AppManagement' => $baseDir . '/../lib/Actions/AppManagement.php', - 'OCA\\AdminAudit\\Actions\\Auth' => $baseDir . '/../lib/Actions/Auth.php', - 'OCA\\AdminAudit\\Actions\\Console' => $baseDir . '/../lib/Actions/Console.php', 'OCA\\AdminAudit\\Actions\\Files' => $baseDir . '/../lib/Actions/Files.php', - 'OCA\\AdminAudit\\Actions\\GroupManagement' => $baseDir . '/../lib/Actions/GroupManagement.php', - 'OCA\\AdminAudit\\Actions\\Security' => $baseDir . '/../lib/Actions/Security.php', 'OCA\\AdminAudit\\Actions\\Sharing' => $baseDir . '/../lib/Actions/Sharing.php', 'OCA\\AdminAudit\\Actions\\TagManagement' => $baseDir . '/../lib/Actions/TagManagement.php', 'OCA\\AdminAudit\\Actions\\Trashbin' => $baseDir . '/../lib/Actions/Trashbin.php', @@ -23,5 +18,13 @@ 'OCA\\AdminAudit\\AuditLogger' => $baseDir . '/../lib/AuditLogger.php', 'OCA\\AdminAudit\\BackgroundJobs\\Rotate' => $baseDir . '/../lib/BackgroundJobs/Rotate.php', 'OCA\\AdminAudit\\IAuditLogger' => $baseDir . '/../lib/IAuditLogger.php', + 'OCA\\AdminAudit\\Listener\\AppManagementEventListener' => $baseDir . '/../lib/Listener/AppManagementEventListener.php', + 'OCA\\AdminAudit\\Listener\\AuthEventListener' => $baseDir . '/../lib/Listener/AuthEventListener.php', + 'OCA\\AdminAudit\\Listener\\ConsoleEventListener' => $baseDir . '/../lib/Listener/ConsoleEventListener.php', 'OCA\\AdminAudit\\Listener\\CriticalActionPerformedEventListener' => $baseDir . '/../lib/Listener/CriticalActionPerformedEventListener.php', + 'OCA\\AdminAudit\\Listener\\FileEventListener' => $baseDir . '/../lib/Listener/FileEventListener.php', + 'OCA\\AdminAudit\\Listener\\GroupManagementEventListener' => $baseDir . '/../lib/Listener/GroupManagementEventListener.php', + 'OCA\\AdminAudit\\Listener\\SecurityEventListener' => $baseDir . '/../lib/Listener/SecurityEventListener.php', + 'OCA\\AdminAudit\\Listener\\SharingEventListener' => $baseDir . '/../lib/Listener/SharingEventListener.php', + 'OCA\\AdminAudit\\Listener\\UserManagementEventListener' => $baseDir . '/../lib/Listener/UserManagementEventListener.php', ); diff --git a/apps/admin_audit/composer/composer/autoload_static.php b/apps/admin_audit/composer/composer/autoload_static.php index 506e7fad22646..ec5d6b67011d8 100644 --- a/apps/admin_audit/composer/composer/autoload_static.php +++ b/apps/admin_audit/composer/composer/autoload_static.php @@ -23,12 +23,7 @@ class ComposerStaticInitAdminAudit public static $classMap = array ( 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', 'OCA\\AdminAudit\\Actions\\Action' => __DIR__ . '/..' . '/../lib/Actions/Action.php', - 'OCA\\AdminAudit\\Actions\\AppManagement' => __DIR__ . '/..' . '/../lib/Actions/AppManagement.php', - 'OCA\\AdminAudit\\Actions\\Auth' => __DIR__ . '/..' . '/../lib/Actions/Auth.php', - 'OCA\\AdminAudit\\Actions\\Console' => __DIR__ . '/..' . '/../lib/Actions/Console.php', 'OCA\\AdminAudit\\Actions\\Files' => __DIR__ . '/..' . '/../lib/Actions/Files.php', - 'OCA\\AdminAudit\\Actions\\GroupManagement' => __DIR__ . '/..' . '/../lib/Actions/GroupManagement.php', - 'OCA\\AdminAudit\\Actions\\Security' => __DIR__ . '/..' . '/../lib/Actions/Security.php', 'OCA\\AdminAudit\\Actions\\Sharing' => __DIR__ . '/..' . '/../lib/Actions/Sharing.php', 'OCA\\AdminAudit\\Actions\\TagManagement' => __DIR__ . '/..' . '/../lib/Actions/TagManagement.php', 'OCA\\AdminAudit\\Actions\\Trashbin' => __DIR__ . '/..' . '/../lib/Actions/Trashbin.php', @@ -38,7 +33,15 @@ class ComposerStaticInitAdminAudit 'OCA\\AdminAudit\\AuditLogger' => __DIR__ . '/..' . '/../lib/AuditLogger.php', 'OCA\\AdminAudit\\BackgroundJobs\\Rotate' => __DIR__ . '/..' . '/../lib/BackgroundJobs/Rotate.php', 'OCA\\AdminAudit\\IAuditLogger' => __DIR__ . '/..' . '/../lib/IAuditLogger.php', + 'OCA\\AdminAudit\\Listener\\AppManagementEventListener' => __DIR__ . '/..' . '/../lib/Listener/AppManagementEventListener.php', + 'OCA\\AdminAudit\\Listener\\AuthEventListener' => __DIR__ . '/..' . '/../lib/Listener/AuthEventListener.php', + 'OCA\\AdminAudit\\Listener\\ConsoleEventListener' => __DIR__ . '/..' . '/../lib/Listener/ConsoleEventListener.php', 'OCA\\AdminAudit\\Listener\\CriticalActionPerformedEventListener' => __DIR__ . '/..' . '/../lib/Listener/CriticalActionPerformedEventListener.php', + 'OCA\\AdminAudit\\Listener\\FileEventListener' => __DIR__ . '/..' . '/../lib/Listener/FileEventListener.php', + 'OCA\\AdminAudit\\Listener\\GroupManagementEventListener' => __DIR__ . '/..' . '/../lib/Listener/GroupManagementEventListener.php', + 'OCA\\AdminAudit\\Listener\\SecurityEventListener' => __DIR__ . '/..' . '/../lib/Listener/SecurityEventListener.php', + 'OCA\\AdminAudit\\Listener\\SharingEventListener' => __DIR__ . '/..' . '/../lib/Listener/SharingEventListener.php', + 'OCA\\AdminAudit\\Listener\\UserManagementEventListener' => __DIR__ . '/..' . '/../lib/Listener/UserManagementEventListener.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/apps/admin_audit/lib/Actions/AppManagement.php b/apps/admin_audit/lib/Actions/AppManagement.php deleted file mode 100644 index 44907c856daff..0000000000000 --- a/apps/admin_audit/lib/Actions/AppManagement.php +++ /dev/null @@ -1,42 +0,0 @@ -log('App "%s" enabled', - ['app' => $appName], - ['app'] - ); - } - - /** - * @param string $appName - * @param string[] $groups - */ - public function enableAppForGroups(string $appName, array $groups): void { - $this->log('App "%1$s" enabled for groups: %2$s', - ['app' => $appName, 'groups' => implode(', ', $groups)], - ['app', 'groups'] - ); - } - - /** - * @param string $appName - */ - public function disableApp(string $appName): void { - $this->log('App "%s" disabled', - ['app' => $appName], - ['app'] - ); - } -} diff --git a/apps/admin_audit/lib/Actions/Auth.php b/apps/admin_audit/lib/Actions/Auth.php deleted file mode 100644 index 55a87cf170f03..0000000000000 --- a/apps/admin_audit/lib/Actions/Auth.php +++ /dev/null @@ -1,45 +0,0 @@ -log( - 'Login attempt: "%s"', - $params, - [ - 'uid', - ], - true - ); - } - - public function loginSuccessful(array $params): void { - $this->log( - 'Login successful: "%s"', - $params, - [ - 'uid', - ], - true - ); - } - - public function logout(array $params): void { - $this->log( - 'Logout occurred', - [], - [] - ); - } -} diff --git a/apps/admin_audit/lib/Actions/Console.php b/apps/admin_audit/lib/Actions/Console.php deleted file mode 100644 index a41fa88bdad2f..0000000000000 --- a/apps/admin_audit/lib/Actions/Console.php +++ /dev/null @@ -1,28 +0,0 @@ -log('Console command executed: %s', - ['arguments' => implode(' ', $arguments)], - ['arguments'] - ); - } -} diff --git a/apps/admin_audit/lib/Actions/GroupManagement.php b/apps/admin_audit/lib/Actions/GroupManagement.php deleted file mode 100644 index 8fb6a037fbf8b..0000000000000 --- a/apps/admin_audit/lib/Actions/GroupManagement.php +++ /dev/null @@ -1,87 +0,0 @@ -log('User "%s" added to group "%s"', - [ - 'group' => $group->getGID(), - 'user' => $user->getUID() - ], - [ - 'user', 'group' - ] - ); - } - - /** - * log remove user from group event - * - * @param IGroup $group - * @param IUser $user - */ - public function removeUser(IGroup $group, IUser $user): void { - $this->log('User "%s" removed from group "%s"', - [ - 'group' => $group->getGID(), - 'user' => $user->getUID() - ], - [ - 'user', 'group' - ] - ); - } - - /** - * log create group to group event - * - * @param IGroup $group - */ - public function createGroup(IGroup $group): void { - $this->log('Group created: "%s"', - [ - 'group' => $group->getGID() - ], - [ - 'group' - ] - ); - } - - /** - * log delete group to group event - * - * @param IGroup $group - */ - public function deleteGroup(IGroup $group): void { - $this->log('Group deleted: "%s"', - [ - 'group' => $group->getGID() - ], - [ - 'group' - ] - ); - } -} diff --git a/apps/admin_audit/lib/Actions/Security.php b/apps/admin_audit/lib/Actions/Security.php deleted file mode 100644 index 203090795fbc4..0000000000000 --- a/apps/admin_audit/lib/Actions/Security.php +++ /dev/null @@ -1,60 +0,0 @@ - $user->getDisplayName(), - 'uid' => $user->getUID(), - 'provider' => $provider->getDisplayName(), - ]; - - $this->log( - 'Failed two factor attempt by user %s (%s) with provider %s', - $params, - [ - 'displayName', - 'uid', - 'provider', - ] - ); - } - - /** - * Logs successful twofactor challenge - */ - public function twofactorSuccess(IUser $user, IProvider $provider): void { - $params = [ - 'displayName' => $user->getDisplayName(), - 'uid' => $user->getUID(), - 'provider' => $provider->getDisplayName(), - ]; - - $this->log( - 'Successful two factor attempt by user %s (%s) with provider %s', - $params, - [ - 'displayName', - 'uid', - 'provider', - ] - ); - } -} diff --git a/apps/admin_audit/lib/Actions/UserManagement.php b/apps/admin_audit/lib/Actions/UserManagement.php index 25960197847be..5b8b11f196b50 100644 --- a/apps/admin_audit/lib/Actions/UserManagement.php +++ b/apps/admin_audit/lib/Actions/UserManagement.php @@ -7,28 +7,12 @@ */ namespace OCA\AdminAudit\Actions; -use OCP\IUser; - /** * Class UserManagement logs all user management related actions. * * @package OCA\AdminAudit\Actions */ class UserManagement extends Action { - /** - * Log creation of users - * - * @param array $params - */ - public function create(array $params): void { - $this->log( - 'User created: "%s"', - $params, - [ - 'uid', - ] - ); - } /** * Log assignments of users (typically user backends) @@ -43,21 +27,6 @@ public function assign(string $uid): void { ); } - /** - * Log deletion of users - * - * @param array $params - */ - public function delete(array $params): void { - $this->log( - 'User deleted: "%s"', - $params, - [ - 'uid', - ] - ); - } - /** * Log unassignments of users (typically user backends, no data removed) * @@ -70,53 +39,4 @@ public function unassign(string $uid): void { [ 'uid' ] ); } - - /** - * Log enabling of users - * - * @param array $params - */ - public function change(array $params): void { - switch ($params['feature']) { - case 'enabled': - $this->log( - $params['value'] === true - ? 'User enabled: "%s"' - : 'User disabled: "%s"', - ['user' => $params['user']->getUID()], - [ - 'user', - ] - ); - break; - case 'eMailAddress': - $this->log( - 'Email address changed for user %s', - ['user' => $params['user']->getUID()], - [ - 'user', - ] - ); - break; - } - } - - /** - * Logs changing of the user scope - * - * @param IUser $user - */ - public function setPassword(IUser $user): void { - if ($user->getBackendClassName() === 'Database') { - $this->log( - 'Password of user "%s" has been changed', - [ - 'user' => $user->getUID(), - ], - [ - 'user', - ] - ); - } - } } diff --git a/apps/admin_audit/lib/AppInfo/Application.php b/apps/admin_audit/lib/AppInfo/Application.php index 79c6640e2e223..b6af8dbed04c2 100644 --- a/apps/admin_audit/lib/AppInfo/Application.php +++ b/apps/admin_audit/lib/AppInfo/Application.php @@ -1,29 +1,35 @@ registerEventListener(CriticalActionPerformedEvent::class, CriticalActionPerformedEventListener::class); + + // User management events + $context->registerEventListener(UserCreatedEvent::class, UserManagementEventListener::class); + $context->registerEventListener(UserDeletedEvent::class, UserManagementEventListener::class); + $context->registerEventListener(UserChangedEvent::class, UserManagementEventListener::class); + $context->registerEventListener(PasswordUpdatedEvent::class, UserManagementEventListener::class); + $context->registerEventListener(UserIdAssignedEvent::class, UserManagementEventListener::class); + $context->registerEventListener(UserIdUnassignedEvent::class, UserManagementEventListener::class); + + // Group management events + $context->registerEventListener(UserAddedEvent::class, GroupManagementEventListener::class); + $context->registerEventListener(UserRemovedEvent::class, GroupManagementEventListener::class); + $context->registerEventListener(GroupCreatedEvent::class, GroupManagementEventListener::class); + $context->registerEventListener(GroupDeletedEvent::class, GroupManagementEventListener::class); + + // Sharing events + $context->registerEventListener(ShareCreatedEvent::class, SharingEventListener::class); + $context->registerEventListener(ShareDeletedEvent::class, SharingEventListener::class); + + // Auth events + $context->registerEventListener(BeforeUserLoggedInEvent::class, AuthEventListener::class); + $context->registerEventListener(UserLoggedInWithCookieEvent::class, AuthEventListener::class); + $context->registerEventListener(UserLoggedInEvent::class, AuthEventListener::class); + $context->registerEventListener(BeforeUserLoggedOutEvent::class, AuthEventListener::class); + + // File events + $context->registerEventListener(BeforePreviewFetchedEvent::class, FileEventListener::class); + + // Security events + $context->registerEventListener(TwoFactorProviderChallengePassed::class, SecurityEventListener::class); + $context->registerEventListener(TwoFactorProviderChallengeFailed::class, SecurityEventListener::class); + + // App management events + $context->registerEventListener(AppEnableEvent::class, AppManagementEventListener::class); + $context->registerEventListener(AppDisableEvent::class, AppManagementEventListener::class); + $context->registerEventListener(AppUpdateEvent::class, AppManagementEventListener::class); + + // Console events + $context->registerEventListener(ConsoleEvent::class, ConsoleEventListener::class); } public function boot(IBootContext $context): void { @@ -75,102 +130,31 @@ public function boot(IBootContext $context): void { * TODO: once the hooks are migrated to lazy events, this should be done * in \OCA\AdminAudit\AppInfo\Application::register */ - $this->registerHooks($logger, $context->getServerContainer()); + $this->registerLegacyHooks($logger, $context->getServerContainer()); } /** * Register hooks in order to log them */ - private function registerHooks(IAuditLogger $logger, - ContainerInterface $serverContainer): void { - $this->userManagementHooks($logger, $serverContainer->get(IUserSession::class)); - $this->groupHooks($logger, $serverContainer->get(IGroupManager::class)); - $this->authHooks($logger); - - + private function registerLegacyHooks(IAuditLogger $logger, ContainerInterface $serverContainer): void { /** @var IEventDispatcher $eventDispatcher */ $eventDispatcher = $serverContainer->get(IEventDispatcher::class); - $this->consoleHooks($logger, $eventDispatcher); - $this->appHooks($logger, $eventDispatcher); - - $this->sharingHooks($logger); - + $this->sharingLegacyHooks($logger); $this->fileHooks($logger, $eventDispatcher); $this->trashbinHooks($logger); $this->versionsHooks($logger); - - $this->securityHooks($logger, $eventDispatcher); $this->tagHooks($logger, $eventDispatcher); } - private function userManagementHooks(IAuditLogger $logger, - IUserSession $userSession): void { - $userActions = new UserManagement($logger); - - Util::connectHook('OC_User', 'post_createUser', $userActions, 'create'); - Util::connectHook('OC_User', 'post_deleteUser', $userActions, 'delete'); - Util::connectHook('OC_User', 'changeUser', $userActions, 'change'); - - assert($userSession instanceof UserSession); - $userSession->listen('\OC\User', 'postSetPassword', [$userActions, 'setPassword']); - $userSession->listen('\OC\User', 'assignedUserId', [$userActions, 'assign']); - $userSession->listen('\OC\User', 'postUnassignedUserId', [$userActions, 'unassign']); - } - - private function groupHooks(IAuditLogger $logger, - IGroupManager $groupManager): void { - $groupActions = new GroupManagement($logger); - - assert($groupManager instanceof GroupManager); - $groupManager->listen('\OC\Group', 'postRemoveUser', [$groupActions, 'removeUser']); - $groupManager->listen('\OC\Group', 'postAddUser', [$groupActions, 'addUser']); - $groupManager->listen('\OC\Group', 'postDelete', [$groupActions, 'deleteGroup']); - $groupManager->listen('\OC\Group', 'postCreate', [$groupActions, 'createGroup']); - } - - private function sharingHooks(IAuditLogger $logger): void { + private function sharingLegacyHooks(IAuditLogger $logger): void { $shareActions = new Sharing($logger); - Util::connectHook(Share::class, 'post_shared', $shareActions, 'shared'); - Util::connectHook(Share::class, 'post_unshare', $shareActions, 'unshare'); - Util::connectHook(Share::class, 'post_unshareFromSelf', $shareActions, 'unshare'); Util::connectHook(Share::class, 'post_update_permissions', $shareActions, 'updatePermissions'); Util::connectHook(Share::class, 'post_update_password', $shareActions, 'updatePassword'); Util::connectHook(Share::class, 'post_set_expiration_date', $shareActions, 'updateExpirationDate'); Util::connectHook(Share::class, 'share_link_access', $shareActions, 'shareAccessed'); } - private function authHooks(IAuditLogger $logger): void { - $authActions = new Auth($logger); - - Util::connectHook('OC_User', 'pre_login', $authActions, 'loginAttempt'); - Util::connectHook('OC_User', 'post_login', $authActions, 'loginSuccessful'); - Util::connectHook('OC_User', 'logout', $authActions, 'logout'); - } - - private function appHooks(IAuditLogger $logger, - IEventDispatcher $eventDispatcher): void { - $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function (ManagerEvent $event) use ($logger) { - $appActions = new AppManagement($logger); - $appActions->enableApp($event->getAppID()); - }); - $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, function (ManagerEvent $event) use ($logger) { - $appActions = new AppManagement($logger); - $appActions->enableAppForGroups($event->getAppID(), $event->getGroups()); - }); - $eventDispatcher->addListener(ManagerEvent::EVENT_APP_DISABLE, function (ManagerEvent $event) use ($logger) { - $appActions = new AppManagement($logger); - $appActions->disableApp($event->getAppID()); - }); - } - - private function consoleHooks(IAuditLogger $logger, - IEventDispatcher $eventDispatcher): void { - $eventDispatcher->addListener(ConsoleEvent::class, function (ConsoleEvent $event) use ($logger) { - $appActions = new Console($logger); - $appActions->runCommand($event->getArguments()); - }); - } private function tagHooks(IAuditLogger $logger, IEventDispatcher $eventDispatcher): void { $eventDispatcher->addListener(\OCP\SystemTag\ManagerEvent::EVENT_CREATE, function (\OCP\SystemTag\ManagerEvent $event) use ($logger) { @@ -179,15 +163,8 @@ private function tagHooks(IAuditLogger $logger, }); } - private function fileHooks(IAuditLogger $logger, - IEventDispatcher $eventDispatcher): void { + private function fileHooks(IAuditLogger $logger, IEventDispatcher $eventDispatcher): void { $fileActions = new Files($logger); - $eventDispatcher->addListener( - BeforePreviewFetchedEvent::class, - function (BeforePreviewFetchedEvent $event) use ($fileActions) { - $fileActions->preview($event); - } - ); $eventDispatcher->addListener( BeforeNodeRenamedEvent::class, @@ -257,16 +234,4 @@ private function trashbinHooks(IAuditLogger $logger): void { Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete'); Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore'); } - - private function securityHooks(IAuditLogger $logger, - IEventDispatcher $eventDispatcher): void { - $eventDispatcher->addListener(TwoFactorProviderChallengePassed::class, function (TwoFactorProviderChallengePassed $event) use ($logger) { - $security = new Security($logger); - $security->twofactorSuccess($event->getUser(), $event->getProvider()); - }); - $eventDispatcher->addListener(TwoFactorProviderChallengeFailed::class, function (TwoFactorProviderChallengeFailed $event) use ($logger) { - $security = new Security($logger); - $security->twofactorFailed($event->getUser(), $event->getProvider()); - }); - } } diff --git a/apps/admin_audit/lib/AuditLogger.php b/apps/admin_audit/lib/AuditLogger.php index a08e79072ee11..a622794dc0835 100644 --- a/apps/admin_audit/lib/AuditLogger.php +++ b/apps/admin_audit/lib/AuditLogger.php @@ -1,9 +1,12 @@ + * + * @author Thomas Citharel + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\AdminAudit\Listener; + +use OCA\AdminAudit\Actions\Action; +use OCP\App\Events\AppDisableEvent; +use OCP\App\Events\AppEnableEvent; +use OCP\App\Events\AppUpdateEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; + +/** + * @template-implements IEventListener + */ +class AppManagementEventListener extends Action implements IEventListener { + public function handle(Event $event): void { + if ($event instanceof AppEnableEvent) { + $this->appEnable($event); + } elseif ($event instanceof AppDisableEvent) { + $this->appDisable($event); + } elseif ($event instanceof AppUpdateEvent) { + $this->appUpdate($event); + } + } + + private function appEnable(AppEnableEvent $event): void { + if (empty($event->getGroupIds())) { + $this->log('App "%s" enabled', + ['app' => $event->getAppId()], + ['app'] + ); + } else { + $this->log('App "%1$s" enabled for groups: %2$s', + ['app' => $event->getAppId(), 'groups' => implode(', ', $event->getGroupIds())], + ['app', 'groups'] + ); + } + } + + private function appDisable(AppDisableEvent $event): void { + $this->log('App "%s" disabled', + ['app' => $event->getAppId()], + ['app'] + ); + } + + private function appUpdate(AppUpdateEvent $event): void { + $this->log('App "%s" updated', + ['app' => $event->getAppId()], + ['app'] + ); + } +} diff --git a/apps/admin_audit/lib/Listener/AuthEventListener.php b/apps/admin_audit/lib/Listener/AuthEventListener.php new file mode 100644 index 0000000000000..355ec27c8cf66 --- /dev/null +++ b/apps/admin_audit/lib/Listener/AuthEventListener.php @@ -0,0 +1,83 @@ + + * + * @author Thomas Citharel + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\AdminAudit\Listener; + +use OCA\AdminAudit\Actions\Action; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\User\Events\BeforeUserLoggedInEvent; +use OCP\User\Events\BeforeUserLoggedOutEvent; +use OCP\User\Events\UserLoggedInEvent; +use OCP\User\Events\UserLoggedInWithCookieEvent; + +/** + * @template-implements IEventListener + */ +class AuthEventListener extends Action implements IEventListener { + public function handle(Event $event): void { + if ($event instanceof BeforeUserLoggedInEvent) { + $this->beforeUserLoggedIn($event); + } elseif ($event instanceof UserLoggedInWithCookieEvent || $event instanceof UserLoggedInEvent) { + $this->userLoggedIn($event); + } elseif ($event instanceof BeforeUserLoggedOutEvent) { + $this->beforeUserLogout($event); + } + } + + private function beforeUserLoggedIn(BeforeUserLoggedInEvent $event): void { + $this->log( + 'Login attempt: "%s"', + [ + 'uid' => $event->getUsername() + ], + [ + 'uid', + ], + true + ); + } + + private function userLoggedIn(UserLoggedInWithCookieEvent|UserLoggedInEvent $event): void { + $this->log( + 'Login successful: "%s"', + [ + 'uid' => $event->getUser()->getUID() + ], + [ + 'uid', + ], + true + ); + } + + private function beforeUserLogout(BeforeUserLoggedOutEvent $event): void { + $this->log( + 'Logout occurred', + [], + [] + ); + } +} diff --git a/apps/admin_audit/lib/Listener/ConsoleEventListener.php b/apps/admin_audit/lib/Listener/ConsoleEventListener.php new file mode 100644 index 0000000000000..aa6029f2016cb --- /dev/null +++ b/apps/admin_audit/lib/Listener/ConsoleEventListener.php @@ -0,0 +1,42 @@ + + */ +class ConsoleEventListener extends Action implements IEventListener { + public function handle(Event $event): void { + if ($event instanceof ConsoleEvent) { + $this->runCommand($event); + } + } + + private function runCommand(ConsoleEvent $event): void { + $arguments = $event->getArguments(); + if (!isset($arguments[1]) || $arguments[1] === '_completion') { + // Don't log autocompletion + return; + } + + // Remove `./occ` + array_shift($arguments); + + $this->log('Console command executed: %s', + ['arguments' => implode(' ', $arguments)], + ['arguments'] + ); + } +} diff --git a/apps/admin_audit/lib/Listener/FileEventListener.php b/apps/admin_audit/lib/Listener/FileEventListener.php new file mode 100644 index 0000000000000..6e646f68ec851 --- /dev/null +++ b/apps/admin_audit/lib/Listener/FileEventListener.php @@ -0,0 +1,64 @@ + + * + * @author Thomas Citharel + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\AdminAudit\Listener; + +use OCA\AdminAudit\Actions\Action; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Preview\BeforePreviewFetchedEvent; + +/** + * @template-implements IEventListener + */ +class FileEventListener extends Action implements IEventListener { + public function handle(Event $event): void { + if ($event instanceof BeforePreviewFetchedEvent) { + $this->beforePreviewFetched($event); + } + } + + private function beforePreviewFetched(BeforePreviewFetchedEvent $event): void { + $file = $event->getNode(); + + $this->log( + 'Preview accessed: "%s" (width: "%s", height: "%s" crop: "%s", mode: "%s")', + [ + 'path' => mb_substr($file->getInternalPath(), 5), + 'width' => $event->getWidth(), + 'height' => $event->getHeight(), + 'crop' => $event->isCrop(), + 'mode' => $event->getMode(), + ], + [ + 'path', + 'width', + 'height', + 'crop', + 'mode' + ] + ); + } +} diff --git a/apps/admin_audit/lib/Listener/GroupManagementEventListener.php b/apps/admin_audit/lib/Listener/GroupManagementEventListener.php new file mode 100644 index 0000000000000..6e9a639b70224 --- /dev/null +++ b/apps/admin_audit/lib/Listener/GroupManagementEventListener.php @@ -0,0 +1,97 @@ + + * + * @author Thomas Citharel + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\AdminAudit\Listener; + +use OCA\AdminAudit\Actions\Action; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Group\Events\GroupCreatedEvent; +use OCP\Group\Events\GroupDeletedEvent; +use OCP\Group\Events\UserAddedEvent; +use OCP\Group\Events\UserRemovedEvent; + +/** + * @template-implements IEventListener + */ +class GroupManagementEventListener extends Action implements IEventListener { + public function handle(Event $event): void { + if ($event instanceof UserAddedEvent) { + $this->userAdded($event); + } elseif ($event instanceof UserRemovedEvent) { + $this->userRemoved($event); + } elseif ($event instanceof GroupCreatedEvent) { + $this->groupCreated($event); + } elseif ($event instanceof GroupDeletedEvent) { + $this->groupDeleted($event); + } + } + + private function userAdded(UserAddedEvent $event): void { + $this->log('User "%s" added to group "%s"', + [ + 'group' => $event->getGroup()->getGID(), + 'user' => $event->getUser()->getUID() + ], + [ + 'user', 'group' + ] + ); + } + + private function userRemoved(UserRemovedEvent $event): void { + $this->log('User "%s" removed from group "%s"', + [ + 'group' => $event->getGroup()->getGID(), + 'user' => $event->getUser()->getUID() + ], + [ + 'user', 'group' + ] + ); + } + + private function groupCreated(GroupCreatedEvent $event): void { + $this->log('Group created: "%s"', + [ + 'group' => $event->getGroup()->getGID() + ], + [ + 'group' + ] + ); + } + + private function groupDeleted(GroupDeletedEvent $event): void { + $this->log('Group deleted: "%s"', + [ + 'group' => $event->getGroup()->getGID() + ], + [ + 'group' + ] + ); + } +} diff --git a/apps/admin_audit/lib/Listener/SecurityEventListener.php b/apps/admin_audit/lib/Listener/SecurityEventListener.php new file mode 100644 index 0000000000000..394830a98bf4f --- /dev/null +++ b/apps/admin_audit/lib/Listener/SecurityEventListener.php @@ -0,0 +1,77 @@ + + * + * @author Thomas Citharel + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\AdminAudit\Listener; + +use OCA\AdminAudit\Actions\Action; +use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengeFailed; +use OCP\Authentication\TwoFactorAuth\TwoFactorProviderChallengePassed; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; + +/** + * @template-implements IEventListener + */ +class SecurityEventListener extends Action implements IEventListener { + public function handle(Event $event): void { + if ($event instanceof TwoFactorProviderChallengePassed) { + $this->twoFactorProviderChallengePassed($event); + } elseif ($event instanceof TwoFactorProviderChallengeFailed) { + $this->twoFactorProviderChallengeFailed($event); + } + } + + private function twoFactorProviderChallengePassed(TwoFactorProviderChallengePassed $event): void { + $this->log( + 'Successful two factor attempt by user %s (%s) with provider %s', + [ + 'uid' => $event->getUser()->getUID(), + 'displayName' => $event->getUser()->getDisplayName(), + 'provider' => $event->getProvider()->getDisplayName() + ], + [ + 'displayName', + 'uid', + 'provider', + ] + ); + } + + private function twoFactorProviderChallengeFailed(TwoFactorProviderChallengeFailed $event): void { + $this->log( + 'Failed two factor attempt by user %s (%s) with provider %s', + [ + 'uid' => $event->getUser()->getUID(), + 'displayName' => $event->getUser()->getDisplayName(), + 'provider' => $event->getProvider()->getDisplayName() + ], + [ + 'displayName', + 'uid', + 'provider', + ] + ); + } +} diff --git a/apps/admin_audit/lib/Listener/SharingEventListener.php b/apps/admin_audit/lib/Listener/SharingEventListener.php new file mode 100644 index 0000000000000..b960e89d25ce3 --- /dev/null +++ b/apps/admin_audit/lib/Listener/SharingEventListener.php @@ -0,0 +1,307 @@ + + * + * @author Thomas Citharel + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\AdminAudit\Listener; + +use OCA\AdminAudit\Actions\Action; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Share\Events\ShareCreatedEvent; +use OCP\Share\Events\ShareDeletedEvent; +use OCP\Share\IShare; + +/** + * @template-implements IEventListener + */ +class SharingEventListener extends Action implements IEventListener { + public function handle(Event $event): void { + if ($event instanceof ShareCreatedEvent) { + $this->shareCreated($event); + } elseif ($event instanceof ShareDeletedEvent) { + $this->shareDeleted($event); + } + } + + private function shareCreated(ShareCreatedEvent $event): void { + $share = $event->getShare(); + + $params = [ + 'itemType' => $share->getNodeType(), + 'path' => $share->getNode()->getPath(), + 'itemSource' => $share->getNodeId(), + 'shareWith' => $share->getSharedWith(), + 'permissions' => $share->getPermissions(), + 'id' => $share->getId() + ]; + + match ($share->getShareType()) { + IShare::TYPE_LINK => $this->log( + 'The %s "%s" with ID "%s" has been shared via link with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'permissions', + 'id', + ] + ), + IShare::TYPE_USER => $this->log( + 'The %s "%s" with ID "%s" has been shared to the user "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + IShare::TYPE_GROUP => $this->log( + 'The %s "%s" with ID "%s" has been shared to the group "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + IShare::TYPE_ROOM => $this->log( + 'The %s "%s" with ID "%s" has been shared to the room "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + IShare::TYPE_EMAIL => $this->log( + 'The %s "%s" with ID "%s" has been shared to the email recipient "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + IShare::TYPE_CIRCLE => $this->log( + 'The %s "%s" with ID "%s" has been shared to the circle "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + IShare::TYPE_REMOTE => $this->log( + 'The %s "%s" with ID "%s" has been shared to the remote user "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + IShare::TYPE_REMOTE_GROUP => $this->log( + 'The %s "%s" with ID "%s" has been shared to the remote group "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + IShare::TYPE_DECK => $this->log( + 'The %s "%s" with ID "%s" has been shared to the deck card "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + IShare::TYPE_SCIENCEMESH => $this->log( + 'The %s "%s" with ID "%s" has been shared to the sciencemesh user "%s" with permissions "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'path', + 'itemSource', + 'shareWith', + 'permissions', + 'id', + ] + ), + default => null + }; + } + + private function shareDeleted(ShareDeletedEvent $event): void { + $share = $event->getShare(); + + $params = [ + 'itemType' => $share->getNodeType(), + 'fileTarget' => $share->getTarget(), + 'itemSource' => $share->getNodeId(), + 'shareWith' => $share->getSharedWith(), + 'id' => $share->getId() + ]; + + match ($share->getShareType()) { + IShare::TYPE_LINK => $this->log( + 'The %s "%s" with ID "%s" has been unshared (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'id', + ] + ), + IShare::TYPE_USER => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the user "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + IShare::TYPE_GROUP => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the group "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + IShare::TYPE_ROOM => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the room "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + IShare::TYPE_EMAIL => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the email recipient "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + IShare::TYPE_CIRCLE => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the circle "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + IShare::TYPE_REMOTE => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the remote user "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + IShare::TYPE_REMOTE_GROUP => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the remote group "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + IShare::TYPE_DECK => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the deck card "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + IShare::TYPE_SCIENCEMESH => $this->log( + 'The %s "%s" with ID "%s" has been unshared from the sciencemesh user "%s" (Share ID: %s)', + $params, + [ + 'itemType', + 'fileTarget', + 'itemSource', + 'shareWith', + 'id', + ] + ), + default => null + }; + } +} diff --git a/apps/admin_audit/lib/Listener/UserManagementEventListener.php b/apps/admin_audit/lib/Listener/UserManagementEventListener.php new file mode 100644 index 0000000000000..ee1def07f63ce --- /dev/null +++ b/apps/admin_audit/lib/Listener/UserManagementEventListener.php @@ -0,0 +1,142 @@ + + * + * @author Thomas Citharel + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\AdminAudit\Listener; + +use OCA\AdminAudit\Actions\Action; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\User\Events\PasswordUpdatedEvent; +use OCP\User\Events\UserChangedEvent; +use OCP\User\Events\UserCreatedEvent; +use OCP\User\Events\UserDeletedEvent; +use OCP\User\Events\UserIdAssignedEvent; +use OCP\User\Events\UserIdUnassignedEvent; + +/** + * @template-implements IEventListener + */ +class UserManagementEventListener extends Action implements IEventListener { + public function handle(Event $event): void { + if ($event instanceof UserCreatedEvent) { + $this->userCreated($event); + } elseif ($event instanceof UserDeletedEvent) { + $this->userDeleted($event); + } elseif ($event instanceof UserChangedEvent) { + $this->userChanged($event); + } elseif ($event instanceof PasswordUpdatedEvent) { + $this->passwordUpdated($event); + } elseif ($event instanceof UserIdAssignedEvent) { + $this->userIdAssigned($event); + } elseif ($event instanceof UserIdUnassignedEvent) { + $this->userIdUnassigned($event); + } + } + + private function userCreated(UserCreatedEvent $event): void { + $this->log( + 'User created: "%s"', + [ + 'uid' => $event->getUid() + ], + [ + 'uid', + ] + ); + } + + private function userDeleted(UserDeletedEvent $event): void { + $this->log( + 'User deleted: "%s"', + [ + 'uid' => $event->getUser()->getUID() + ], + [ + 'uid', + ] + ); + } + + private function userChanged(UserChangedEvent $event): void { + switch ($event->getFeature()) { + case 'enabled': + $this->log( + $event->getValue() === true + ? 'User enabled: "%s"' + : 'User disabled: "%s"', + ['user' => $event->getUser()->getUID()], + [ + 'user', + ] + ); + break; + case 'eMailAddress': + $this->log( + 'Email address changed for user %s', + ['user' => $event->getUser()->getUID()], + [ + 'user', + ] + ); + break; + } + } + + private function passwordUpdated(PasswordUpdatedEvent $event): void { + if ($event->getUser()->getBackendClassName() === 'Database') { + $this->log( + 'Password of user "%s" has been changed', + [ + 'user' => $event->getUser()->getUID(), + ], + [ + 'user', + ] + ); + } + } + + /** + * Log assignments of users (typically user backends) + */ + private function userIdAssigned(UserIdAssignedEvent $event): void { + $this->log( + 'UserID assigned: "%s"', + [ 'uid' => $event->getUserId() ], + [ 'uid' ] + ); + } + + /** + * Log unassignments of users (typically user backends, no data removed) + */ + private function userIdUnassigned(UserIdUnassignedEvent $event): void { + $this->log( + 'UserID unassigned: "%s"', + [ 'uid' => $event->getUserId() ], + [ 'uid' ] + ); + } +} diff --git a/apps/admin_audit/tests/Actions/SecurityTest.php b/apps/admin_audit/tests/Listener/SecurityEventListenerTest.php similarity index 56% rename from apps/admin_audit/tests/Actions/SecurityTest.php rename to apps/admin_audit/tests/Listener/SecurityEventListenerTest.php index d06095b12e1eb..482301085308d 100644 --- a/apps/admin_audit/tests/Actions/SecurityTest.php +++ b/apps/admin_audit/tests/Listener/SecurityEventListenerTest.php @@ -1,38 +1,47 @@ logger = $this->createMock(AuditLogger::class); - $this->security = new Security($this->logger); + $this->security = new SecurityEventListener($this->logger); $this->user = $this->createMock(IUser::class); $this->user->method('getUID')->willReturn('myuid'); $this->user->method('getDisplayName')->willReturn('mydisplayname'); + $this->provider = $this->createMock(IProvider::class); + $this->provider->method('getDisplayName')->willReturn('myprovider'); } - public function testTwofactorFailed() { + public function testTwofactorFailed(): void { $this->logger->expects($this->once()) ->method('info') ->with( @@ -40,14 +49,10 @@ public function testTwofactorFailed() { ['app' => 'admin_audit'] ); - $provider = $this->createMock(IProvider::class); - $provider->method('getDisplayName') - ->willReturn('myprovider'); - - $this->security->twofactorFailed($this->user, $provider); + $this->security->handle(new twoFactorProviderChallengeFailed($this->user, $this->provider)); } - public function testTwofactorSuccess() { + public function testTwofactorSuccess(): void { $this->logger->expects($this->once()) ->method('info') ->with( @@ -55,10 +60,6 @@ public function testTwofactorSuccess() { ['app' => 'admin_audit'] ); - $provider = $this->createMock(IProvider::class); - $provider->method('getDisplayName') - ->willReturn('myprovider'); - - $this->security->twofactorSuccess($this->user, $provider); + $this->security->handle(new TwoFactorProviderChallengePassed($this->user, $this->provider)); } } From ec37338d733916977c595a00fba62fcf1892ddd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 10 Sep 2024 12:25:44 +0200 Subject: [PATCH 5/8] chore(admin_audit): Fix License headers on new files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- .../Listener/AppManagementEventListener.php | 22 +++---------------- .../lib/Listener/AuthEventListener.php | 22 +++---------------- .../CriticalActionPerformedEventListener.php | 2 ++ .../lib/Listener/FileEventListener.php | 22 +++---------------- .../Listener/GroupManagementEventListener.php | 22 +++---------------- .../lib/Listener/SecurityEventListener.php | 22 +++---------------- .../lib/Listener/SharingEventListener.php | 22 +++---------------- .../Listener/UserManagementEventListener.php | 22 +++---------------- 8 files changed, 23 insertions(+), 133 deletions(-) diff --git a/apps/admin_audit/lib/Listener/AppManagementEventListener.php b/apps/admin_audit/lib/Listener/AppManagementEventListener.php index 512461034cc6c..c20bdd481d6e4 100644 --- a/apps/admin_audit/lib/Listener/AppManagementEventListener.php +++ b/apps/admin_audit/lib/Listener/AppManagementEventListener.php @@ -3,26 +3,10 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2023 Thomas Citharel - * - * @author Thomas Citharel - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\AdminAudit\Listener; use OCA\AdminAudit\Actions\Action; diff --git a/apps/admin_audit/lib/Listener/AuthEventListener.php b/apps/admin_audit/lib/Listener/AuthEventListener.php index 355ec27c8cf66..2b31a271d23aa 100644 --- a/apps/admin_audit/lib/Listener/AuthEventListener.php +++ b/apps/admin_audit/lib/Listener/AuthEventListener.php @@ -3,26 +3,10 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2023 Thomas Citharel - * - * @author Thomas Citharel - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\AdminAudit\Listener; use OCA\AdminAudit\Actions\Action; diff --git a/apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php b/apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php index 0c4d0401b8027..bc3652a08bcc0 100644 --- a/apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php +++ b/apps/admin_audit/lib/Listener/CriticalActionPerformedEventListener.php @@ -1,10 +1,12 @@ - * - * @author Thomas Citharel - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\AdminAudit\Listener; use OCA\AdminAudit\Actions\Action; diff --git a/apps/admin_audit/lib/Listener/GroupManagementEventListener.php b/apps/admin_audit/lib/Listener/GroupManagementEventListener.php index 6e9a639b70224..df937447e7009 100644 --- a/apps/admin_audit/lib/Listener/GroupManagementEventListener.php +++ b/apps/admin_audit/lib/Listener/GroupManagementEventListener.php @@ -3,26 +3,10 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2023 Thomas Citharel - * - * @author Thomas Citharel - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\AdminAudit\Listener; use OCA\AdminAudit\Actions\Action; diff --git a/apps/admin_audit/lib/Listener/SecurityEventListener.php b/apps/admin_audit/lib/Listener/SecurityEventListener.php index 394830a98bf4f..17253aa384c9f 100644 --- a/apps/admin_audit/lib/Listener/SecurityEventListener.php +++ b/apps/admin_audit/lib/Listener/SecurityEventListener.php @@ -3,26 +3,10 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2023 Thomas Citharel - * - * @author Thomas Citharel - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\AdminAudit\Listener; use OCA\AdminAudit\Actions\Action; diff --git a/apps/admin_audit/lib/Listener/SharingEventListener.php b/apps/admin_audit/lib/Listener/SharingEventListener.php index b960e89d25ce3..1ba3c6f49d33a 100644 --- a/apps/admin_audit/lib/Listener/SharingEventListener.php +++ b/apps/admin_audit/lib/Listener/SharingEventListener.php @@ -3,26 +3,10 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2023 Thomas Citharel - * - * @author Thomas Citharel - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\AdminAudit\Listener; use OCA\AdminAudit\Actions\Action; diff --git a/apps/admin_audit/lib/Listener/UserManagementEventListener.php b/apps/admin_audit/lib/Listener/UserManagementEventListener.php index ee1def07f63ce..c22d04dce9a7c 100644 --- a/apps/admin_audit/lib/Listener/UserManagementEventListener.php +++ b/apps/admin_audit/lib/Listener/UserManagementEventListener.php @@ -3,26 +3,10 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2023 Thomas Citharel - * - * @author Thomas Citharel - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * + * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\AdminAudit\Listener; use OCA\AdminAudit\Actions\Action; From 957ac81a56579757826a90f6ca3c30cfd427dabb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 10 Sep 2024 14:24:55 +0200 Subject: [PATCH 6/8] fix(admin_audit): Remove now unused methods and classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- .../composer/composer/autoload_classmap.php | 1 - .../composer/composer/autoload_static.php | 1 - apps/admin_audit/lib/Actions/Files.php | 30 -- apps/admin_audit/lib/Actions/Sharing.php | 267 ------------------ .../lib/Actions/UserManagement.php | 42 --- .../lib/Listener/FileEventListener.php | 38 ++- 6 files changed, 23 insertions(+), 356 deletions(-) delete mode 100644 apps/admin_audit/lib/Actions/UserManagement.php diff --git a/apps/admin_audit/composer/composer/autoload_classmap.php b/apps/admin_audit/composer/composer/autoload_classmap.php index b73c4b9b3a541..b67d90e768921 100644 --- a/apps/admin_audit/composer/composer/autoload_classmap.php +++ b/apps/admin_audit/composer/composer/autoload_classmap.php @@ -12,7 +12,6 @@ 'OCA\\AdminAudit\\Actions\\Sharing' => $baseDir . '/../lib/Actions/Sharing.php', 'OCA\\AdminAudit\\Actions\\TagManagement' => $baseDir . '/../lib/Actions/TagManagement.php', 'OCA\\AdminAudit\\Actions\\Trashbin' => $baseDir . '/../lib/Actions/Trashbin.php', - 'OCA\\AdminAudit\\Actions\\UserManagement' => $baseDir . '/../lib/Actions/UserManagement.php', 'OCA\\AdminAudit\\Actions\\Versions' => $baseDir . '/../lib/Actions/Versions.php', 'OCA\\AdminAudit\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php', 'OCA\\AdminAudit\\AuditLogger' => $baseDir . '/../lib/AuditLogger.php', diff --git a/apps/admin_audit/composer/composer/autoload_static.php b/apps/admin_audit/composer/composer/autoload_static.php index ec5d6b67011d8..f8fd457edd8d5 100644 --- a/apps/admin_audit/composer/composer/autoload_static.php +++ b/apps/admin_audit/composer/composer/autoload_static.php @@ -27,7 +27,6 @@ class ComposerStaticInitAdminAudit 'OCA\\AdminAudit\\Actions\\Sharing' => __DIR__ . '/..' . '/../lib/Actions/Sharing.php', 'OCA\\AdminAudit\\Actions\\TagManagement' => __DIR__ . '/..' . '/../lib/Actions/TagManagement.php', 'OCA\\AdminAudit\\Actions\\Trashbin' => __DIR__ . '/..' . '/../lib/Actions/Trashbin.php', - 'OCA\\AdminAudit\\Actions\\UserManagement' => __DIR__ . '/..' . '/../lib/Actions/UserManagement.php', 'OCA\\AdminAudit\\Actions\\Versions' => __DIR__ . '/..' . '/../lib/Actions/Versions.php', 'OCA\\AdminAudit\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php', 'OCA\\AdminAudit\\AuditLogger' => __DIR__ . '/..' . '/../lib/AuditLogger.php', diff --git a/apps/admin_audit/lib/Actions/Files.php b/apps/admin_audit/lib/Actions/Files.php index 50448e88f7070..5c08640d2d2af 100644 --- a/apps/admin_audit/lib/Actions/Files.php +++ b/apps/admin_audit/lib/Actions/Files.php @@ -18,7 +18,6 @@ use OCP\Files\Events\Node\NodeWrittenEvent; use OCP\Files\InvalidPathException; use OCP\Files\NotFoundException; -use OCP\Preview\BeforePreviewFetchedEvent; use Psr\Log\LoggerInterface; /** @@ -229,33 +228,4 @@ public function delete(NodeDeletedEvent $event): void { array_keys($params) ); } - - /** - * Logs preview access to a file - * - * @param BeforePreviewFetchedEvent $event - */ - public function preview(BeforePreviewFetchedEvent $event): void { - try { - $file = $event->getNode(); - $params = [ - 'id' => $file->getId(), - 'width' => $event->getWidth(), - 'height' => $event->getHeight(), - 'crop' => $event->isCrop(), - 'mode' => $event->getMode(), - 'path' => mb_substr($file->getInternalPath(), 5) - ]; - } catch (InvalidPathException|NotFoundException $e) { - \OCP\Server::get(LoggerInterface::class)->error( - 'Exception thrown in file preview: '.$e->getMessage(), ['app' => 'admin_audit', 'exception' => $e] - ); - return; - } - $this->log( - 'Preview accessed: (id: "%s", width: "%s", height: "%s" crop: "%s", mode: "%s", path: "%s")', - $params, - array_keys($params) - ); - } } diff --git a/apps/admin_audit/lib/Actions/Sharing.php b/apps/admin_audit/lib/Actions/Sharing.php index bca2b6eecacdb..8f021d5f210fc 100644 --- a/apps/admin_audit/lib/Actions/Sharing.php +++ b/apps/admin_audit/lib/Actions/Sharing.php @@ -7,279 +7,12 @@ */ namespace OCA\AdminAudit\Actions; -use OCP\Share\IShare; - /** * Class Sharing logs the sharing actions * * @package OCA\AdminAudit\Actions */ class Sharing extends Action { - /** - * Logs sharing of data - * - * @param array $params - */ - public function shared(array $params): void { - if ($params['shareType'] === IShare::TYPE_LINK) { - $this->log( - 'The %s "%s" with ID "%s" has been shared via link with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_USER) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the user "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_GROUP) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the group "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_ROOM) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the room "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_EMAIL) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the email recipient "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_CIRCLE) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the circle "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_REMOTE) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the remote user "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_REMOTE_GROUP) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the remote group "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_DECK) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the deck card "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_SCIENCEMESH) { - $this->log( - 'The %s "%s" with ID "%s" has been shared to the ScienceMesh user "%s" with permissions "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'path', - 'itemSource', - 'shareWith', - 'permissions', - 'id', - ] - ); - } - } - - /** - * Logs unsharing of data - * - * @param array $params - */ - public function unshare(array $params): void { - if ($params['shareType'] === IShare::TYPE_LINK) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_USER) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the user "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_GROUP) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the group "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_ROOM) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the room "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_EMAIL) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the email recipient "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_CIRCLE) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the circle "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_REMOTE) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the remote user "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_REMOTE_GROUP) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the remote group "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_DECK) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the deck card "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } elseif ($params['shareType'] === IShare::TYPE_SCIENCEMESH) { - $this->log( - 'The %s "%s" with ID "%s" has been unshared from the ScienceMesh user "%s" (Share ID: %s)', - $params, - [ - 'itemType', - 'fileTarget', - 'itemSource', - 'shareWith', - 'id', - ] - ); - } - } /** * Logs the updating of permission changes for shares diff --git a/apps/admin_audit/lib/Actions/UserManagement.php b/apps/admin_audit/lib/Actions/UserManagement.php deleted file mode 100644 index 5b8b11f196b50..0000000000000 --- a/apps/admin_audit/lib/Actions/UserManagement.php +++ /dev/null @@ -1,42 +0,0 @@ -log( - 'UserID assigned: "%s"', - [ 'uid' => $uid ], - [ 'uid' ] - ); - } - - /** - * Log unassignments of users (typically user backends, no data removed) - * - * @param string $uid - */ - public function unassign(string $uid): void { - $this->log( - 'UserID unassigned: "%s"', - [ 'uid' => $uid ], - [ 'uid' ] - ); - } -} diff --git a/apps/admin_audit/lib/Listener/FileEventListener.php b/apps/admin_audit/lib/Listener/FileEventListener.php index a931ef1824149..74bb2ac836c52 100644 --- a/apps/admin_audit/lib/Listener/FileEventListener.php +++ b/apps/admin_audit/lib/Listener/FileEventListener.php @@ -12,7 +12,10 @@ use OCA\AdminAudit\Actions\Action; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +use OCP\Files\InvalidPathException; +use OCP\Files\NotFoundException; use OCP\Preview\BeforePreviewFetchedEvent; +use Psr\Log\LoggerInterface; /** * @template-implements IEventListener @@ -24,25 +27,30 @@ public function handle(Event $event): void { } } + /** + * Logs preview access to a file + */ private function beforePreviewFetched(BeforePreviewFetchedEvent $event): void { - $file = $event->getNode(); - - $this->log( - 'Preview accessed: "%s" (width: "%s", height: "%s" crop: "%s", mode: "%s")', - [ - 'path' => mb_substr($file->getInternalPath(), 5), + try { + $file = $event->getNode(); + $params = [ + 'id' => $file->getId(), 'width' => $event->getWidth(), 'height' => $event->getHeight(), 'crop' => $event->isCrop(), 'mode' => $event->getMode(), - ], - [ - 'path', - 'width', - 'height', - 'crop', - 'mode' - ] - ); + 'path' => mb_substr($file->getInternalPath(), 5) + ]; + $this->log( + 'Preview accessed: (id: "%s", width: "%s", height: "%s" crop: "%s", mode: "%s", path: "%s")', + $params, + array_keys($params) + ); + } catch (InvalidPathException|NotFoundException $e) { + \OCP\Server::get(LoggerInterface::class)->error( + 'Exception thrown in file preview: '.$e->getMessage(), ['app' => 'admin_audit', 'exception' => $e] + ); + return; + } } } From 7d881b1bc35e24cba29184f11d4b28188fe487ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 10 Sep 2024 16:20:30 +0200 Subject: [PATCH 7/8] chore: Add descriptions for new events and fix copyright year MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/public/User/Events/BeforeUserIdUnassignedEvent.php | 5 +++-- lib/public/User/Events/UserIdAssignedEvent.php | 5 +++-- lib/public/User/Events/UserIdUnassignedEvent.php | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/public/User/Events/BeforeUserIdUnassignedEvent.php b/lib/public/User/Events/BeforeUserIdUnassignedEvent.php index 744ecd8909fd6..2dee62521aa49 100644 --- a/lib/public/User/Events/BeforeUserIdUnassignedEvent.php +++ b/lib/public/User/Events/BeforeUserIdUnassignedEvent.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -12,6 +12,7 @@ use OCP\EventDispatcher\Event; /** + * Emitted before removing the mapping between an external user and an internal userid * @since 31.0.0 */ class BeforeUserIdUnassignedEvent extends Event { @@ -19,7 +20,7 @@ class BeforeUserIdUnassignedEvent extends Event { * @since 31.0.0 */ public function __construct( - private string $userId, + private readonly string $userId, ) { parent::__construct(); } diff --git a/lib/public/User/Events/UserIdAssignedEvent.php b/lib/public/User/Events/UserIdAssignedEvent.php index 63daca098203c..829bd50c0d04c 100644 --- a/lib/public/User/Events/UserIdAssignedEvent.php +++ b/lib/public/User/Events/UserIdAssignedEvent.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -12,6 +12,7 @@ use OCP\EventDispatcher\Event; /** + * Emitted by backends (like user_ldap) when a user created externally is mapped for the first time and assigned a userid * @since 31.0.0 */ class UserIdAssignedEvent extends Event { @@ -19,7 +20,7 @@ class UserIdAssignedEvent extends Event { * @since 31.0.0 */ public function __construct( - private string $userId, + private readonly string $userId, ) { parent::__construct(); } diff --git a/lib/public/User/Events/UserIdUnassignedEvent.php b/lib/public/User/Events/UserIdUnassignedEvent.php index db8861b98a4d9..128648a075344 100644 --- a/lib/public/User/Events/UserIdUnassignedEvent.php +++ b/lib/public/User/Events/UserIdUnassignedEvent.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -12,6 +12,7 @@ use OCP\EventDispatcher\Event; /** + * Emitted after removing the mapping between an external user and an internal userid * @since 31.0.0 */ class UserIdUnassignedEvent extends Event { @@ -19,7 +20,7 @@ class UserIdUnassignedEvent extends Event { * @since 31.0.0 */ public function __construct( - private string $userId, + private readonly string $userId, ) { parent::__construct(); } From d76745553c29897d9d7adb28b8d92a098783ca49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= <91878298+come-nc@users.noreply.github.com> Date: Fri, 13 Sep 2024 16:01:55 +0200 Subject: [PATCH 8/8] fix: Fix phpdoc wording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Anna Signed-off-by: Côme Chilliet <91878298+come-nc@users.noreply.github.com> --- lib/public/Preview/BeforePreviewFetchedEvent.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/public/Preview/BeforePreviewFetchedEvent.php b/lib/public/Preview/BeforePreviewFetchedEvent.php index 6aed6bcc7044e..8ab875070d99c 100644 --- a/lib/public/Preview/BeforePreviewFetchedEvent.php +++ b/lib/public/Preview/BeforePreviewFetchedEvent.php @@ -27,11 +27,11 @@ public function __construct( private Node $node, /** @deprecated 28.0.0 passing null is deprecated **/ private ?int $width = null, - /** @deprecated 28.0.0 passing null is null deprecated **/ + /** @deprecated 28.0.0 passing null is deprecated **/ private ?int $height = null, - /** @deprecated 28.0.0 passing null is null deprecated **/ + /** @deprecated 28.0.0 passing null is deprecated **/ private ?bool $crop = null, - /** @deprecated 28.0.0 passing null is null deprecated **/ + /** @deprecated 28.0.0 passing null is deprecated **/ private ?string $mode = null, private ?string $mimeType = null, ) {