From d17fc67adb1b4584d56b3a8ae325068ab62d9717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Ku=C3=9Fmann?= Date: Fri, 11 Oct 2024 14:05:52 +0200 Subject: [PATCH] fix: fix deprecations --- Classes/Domain/Repository/Entry.php | 111 ------------------ Classes/Domain/Repository/EntryRepository.php | 95 +++++++++++++-- Classes/Domain/Service/RestrictionService.php | 19 +-- .../RestrictionServiceClientIpAbstract.php | 16 +-- ...RestrictionServiceFrontendNameAbstract.php | 16 +-- code-quality/phpstan-baseline.neon | 31 ----- 6 files changed, 106 insertions(+), 182 deletions(-) delete mode 100755 Classes/Domain/Repository/Entry.php diff --git a/Classes/Domain/Repository/Entry.php b/Classes/Domain/Repository/Entry.php deleted file mode 100755 index 4fa1a27..0000000 --- a/Classes/Domain/Repository/Entry.php +++ /dev/null @@ -1,111 +0,0 @@ - - * - * All rights reserved - * - * This script is part of the TYPO3 project. The TYPO3 project is - * free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * The GNU General Public License can be found at - * http://www.gnu.org/copyleft/gpl.html. - * - * This script 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 General Public License for more details. - * - * This copyright notice MUST APPEAR in all copies of the script! - ***************************************************************/ - -use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; -use TYPO3\CMS\Extbase\Persistence\Repository; - -/** - * @subpackage Domain_Repository - */ -class Entry extends Repository -{ - public function initializeObject(): void - { - /** @var Typo3QuerySettings $defaultQuerySettings */ - $defaultQuerySettings = GeneralUtility::makeInstance(Typo3QuerySettings::class); - // don't add the pid constraint - $defaultQuerySettings->setRespectStoragePage(false); - // don't add fields from enable columns constraint - $defaultQuerySettings->setIgnoreEnableFields(true) - ->setIncludeDeleted(true); - // don't add sys_language_uid constraint - $defaultQuerySettings->setRespectSysLanguage(false); - $this->setDefaultQuerySettings($defaultQuerySettings); - } - - /** - * @param int $uid - * - * @return object|null - */ - public function findByUid($uid) - { - $query = $this->createQuery(); - $query->getQuerySettings() - ->setRespectSysLanguage(false); - $query->getQuerySettings() - ->setRespectStoragePage(false); - $query->getQuerySettings() - ->setIgnoreEnableFields(true) - ->setIncludeDeleted(true); - $query->matching($query->equals('uid', $uid)); - - return $query->execute() - ->getFirst(); - } - - public function cleanUp($secondsTillReset, $maxFailures, $restrictionTime, $identifier = null): void - { - $time = time(); - $age = (int) $time - $secondsTillReset; - $restrictionTime = (int) $time - $restrictionTime; - $query = $this->createQuery(); - $query->getQuerySettings() - ->setRespectSysLanguage(false); - $query->getQuerySettings() - ->setRespectStoragePage(false); - $query->getQuerySettings() - ->setIgnoreEnableFields(true) - ->setIncludeDeleted(true); - $constraintsRestrictedEntries = [ - $query->lessThan('tstamp', $restrictionTime), - $query->greaterThanOrEqual('failures', $maxFailures), - ]; - $constraintsResettableEntries = [ - $query->lessThan('crdate', $age), - $query->lessThan('failures', $maxFailures), - ]; - - if ($identifier !== null) { - $constraintsRestrictedEntries[] = $query->equals('identifier', $identifier); - $constraintsResettableEntries[] = $query->equals('identifier', $identifier); - } - - $query->matching( - $query->logicalOr( - $query->logicalAnd($constraintsRestrictedEntries), - $query->logicalAnd($constraintsResettableEntries) - ) - ); - foreach ($query->execute() as $object) { - $this->remove($object); - $this->add($object); - } - } -} diff --git a/Classes/Domain/Repository/EntryRepository.php b/Classes/Domain/Repository/EntryRepository.php index ff3b1ec..0cf8198 100755 --- a/Classes/Domain/Repository/EntryRepository.php +++ b/Classes/Domain/Repository/EntryRepository.php @@ -26,24 +26,97 @@ * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +use Aoe\FeloginBruteforceProtection\Domain\Model\Entry; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Database\Query\QueryBuilder; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; use TYPO3\CMS\Extbase\Persistence\QueryResultInterface; use TYPO3\CMS\Extbase\Persistence\Repository; class EntryRepository extends Repository { - public function initializeObject(): void + private const ENTRY_DB_TABLE = 'tx_feloginbruteforceprotection_domain_model_entry'; + + /** + * We don't use the extbase-logic to do the DB-query - because we must do the DB-query BEFORE the FE-user is initialised - and + * this would lead to the TYPO3-deprecation 'Using extbase in a context without TypoScript. Will stop working with TYPO3 v13.' + */ + public function findOneEntryByIdentifier(string $identifier): ?Entry + { + /** @var QueryBuilder $queryBuilder */ + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::ENTRY_DB_TABLE); + $records = $queryBuilder->select('*') + ->from(self::ENTRY_DB_TABLE) + ->where( + $queryBuilder->expr() + ->eq('identifier', $queryBuilder->createNamedParameter($identifier, \PDO::PARAM_STR)), + ) + ->executeQuery() + ->fetchAllAssociative(); + + if (count($records) === 1) { + $entry = new Entry(); + $entry->_setProperty('uid', $records[0]['uid']); + $entry->_setProperty('pid', $records[0]['pid']); + $entry->_setProperty('tstamp', $records[0]['tstamp']); + $entry->_setProperty('crdate', $records[0]['crdate']); + $entry->_setProperty('identifier', $records[0]['identifier']); + $entry->_setProperty('failures', $records[0]['failures']); + return $entry; + } + + return null; + } + + /** + * We don't use the extbase-logic to do the DB-query - because we must do the DB-query BEFORE the FE-user is initialised - and + * this would lead to the TYPO3-deprecation 'Using extbase in a context without TypoScript. Will stop working with TYPO3 v13.' + */ + public function createEntry(Entry $entry): void { - /** @var Typo3QuerySettings $defaultQuerySettings */ - $defaultQuerySettings = GeneralUtility::makeInstance(Typo3QuerySettings::class); - // don't add the pid constraint - $defaultQuerySettings->setRespectStoragePage(false); - // don't add fields from enable columns constraint - $defaultQuerySettings->setIgnoreEnableFields(true); - // don't add sys_language_uid constraint - $defaultQuerySettings->setRespectSysLanguage(false); - $this->setDefaultQuerySettings($defaultQuerySettings); + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::ENTRY_DB_TABLE); + $queryBuilder->insert(self::ENTRY_DB_TABLE) + ->values([ + 'pid' => 0, + 'tstamp' => $entry->getTstamp(), + 'crdate' => $entry->getCrdate(), + 'identifier' => $entry->getIdentifier(), + 'failures' => $entry->getFailures(), + ]) + ->executeStatement(); + } + + /** + * We don't use the extbase-logic to do the DB-query - because we must do the DB-query BEFORE the FE-user is initialised - and + * this would lead to the TYPO3-deprecation 'Using extbase in a context without TypoScript. Will stop working with TYPO3 v13.' + */ + public function updateEntry(Entry $entry): void + { + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::ENTRY_DB_TABLE); + $queryBuilder->update(self::ENTRY_DB_TABLE) + ->set('failures', $entry->getFailures()) + ->set('tstamp', $entry->getTstamp()) + ->where( + $queryBuilder->expr() + ->eq('identifier', $queryBuilder->createNamedParameter($entry->getIdentifier(), \PDO::PARAM_STR)), + ) + ->executeStatement(); + } + + /** + * We don't use the extbase-logic to do the DB-query - because we must do the DB-query BEFORE the FE-user is initialised - and + * this would lead to the TYPO3-deprecation 'Using extbase in a context without TypoScript. Will stop working with TYPO3 v13.' + */ + public function removeEntry(Entry $entry): void + { + /** @var QueryBuilder $queryBuilder */ + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::ENTRY_DB_TABLE); + $queryBuilder->delete(self::ENTRY_DB_TABLE) + ->where( + $queryBuilder->expr() + ->eq('identifier', $queryBuilder->createNamedParameter($entry->getIdentifier(), \PDO::PARAM_STR)), + ) + ->executeStatement(); } /** diff --git a/Classes/Domain/Service/RestrictionService.php b/Classes/Domain/Service/RestrictionService.php index 4f0bb01..9180970 100755 --- a/Classes/Domain/Service/RestrictionService.php +++ b/Classes/Domain/Service/RestrictionService.php @@ -33,7 +33,6 @@ use Aoe\FeloginBruteforceProtection\Service\Logger\LoggerInterface; use Aoe\FeloginBruteforceProtection\System\Configuration; use TYPO3\CMS\Core\Utility\GeneralUtility; -use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; class RestrictionService { @@ -47,8 +46,6 @@ class RestrictionService protected EntryRepository $entryRepository; - protected PersistenceManager $persistenceManager; - protected Entry $entry; protected bool $clientRestricted; @@ -62,7 +59,6 @@ public function __construct(RestrictionIdentifierInterface $restrictionIdentifie $this->restrictionIdentifier = $restrictionIdentifier; $this->configuration = GeneralUtility::makeInstance(Configuration::class); - $this->persistenceManager = GeneralUtility::makeInstance(PersistenceManager::class); $this->entryRepository = GeneralUtility::makeInstance(EntryRepository::class); $this->feLoginBruteForceApi = GeneralUtility::makeInstance(FeLoginBruteForceApi::class); } @@ -84,8 +80,7 @@ public function isClientRestricted(): bool public function removeEntry(): void { if ($this->hasEntry()) { - $this->entryRepository->remove($this->entry); - $this->persistenceManager->persistAll(); + $this->entryRepository->removeEntry($this->entry); $this->log('Bruteforce Counter removed', LoggerInterface::SEVERITY_INFO); } @@ -114,7 +109,7 @@ public function checkAndHandleRestriction(): void } $this->entry->increaseFailures(); - $this->saveEntry(); + $this->updateEntry(); $this->restrictionLog(); } @@ -127,7 +122,7 @@ public function hasEntry(): bool public function getEntry(): ?Entry { if (!isset($this->entry)) { - $entry = $this->entryRepository->findOneBy(['identifier' => $this->getClientIdentifier()]); + $entry = $this->entryRepository->findOneEntryByIdentifier($this->getClientIdentifier()); if ($entry instanceof Entry) { $this->entry = $entry; if ($this->isOutdated($entry)) { @@ -198,19 +193,17 @@ private function createEntry(): void $this->entry->setTstamp(time()); $this->entry->setIdentifier($this->getClientIdentifier()); - $this->entryRepository->add($this->entry); - $this->persistenceManager->persistAll(); + $this->entryRepository->createEntry($this->entry); $this->clientRestricted = false; } - private function saveEntry(): void + private function updateEntry(): void { if ($this->entry->getFailures() > 0) { $this->entry->setTstamp(time()); } - $this->entryRepository->add($this->entry); - $this->persistenceManager->persistAll(); + $this->entryRepository->updateEntry($this->entry); if ($this->hasMaximumNumberOfFailuresReached($this->entry)) { $this->clientRestricted = true; } diff --git a/Tests/Functional/Domain/Service/RestrictionServiceClientIpAbstract.php b/Tests/Functional/Domain/Service/RestrictionServiceClientIpAbstract.php index e375259..bfd52e3 100755 --- a/Tests/Functional/Domain/Service/RestrictionServiceClientIpAbstract.php +++ b/Tests/Functional/Domain/Service/RestrictionServiceClientIpAbstract.php @@ -139,12 +139,12 @@ public function testIsNotClientRestrictedWhenMaximumNumbersOfFailureNotReached() $entryRepository = $this->getAccessibleMock( EntryRepository::class, - ['findOneBy', 'remove'], + ['findOneEntryByIdentifier', 'removeEntry'], [], '', false ); - $entryRepository->method('findOneBy') + $entryRepository->method('findOneEntryByIdentifier') ->willReturn($entry); GeneralUtility::setSingletonInstance(EntryRepository::class, $entryRepository); @@ -178,12 +178,12 @@ public function testIsClientRestrictedWithFailures(): void $entryRepository = $this->getAccessibleMock( EntryRepository::class, - ['findOneBy', 'remove'], + ['findOneEntryByIdentifier', 'removeEntry'], [], '', false ); - $entryRepository->method('findOneBy') + $entryRepository->method('findOneEntryByIdentifier') ->willReturn($entry); GeneralUtility::setSingletonInstance(EntryRepository::class, $entryRepository); @@ -216,12 +216,12 @@ public function testIsClientRestrictedWithFailuresAndTimeout(): void $entryRepository = $this->getAccessibleMock( EntryRepository::class, - ['findOneBy', 'remove'], + ['findOneEntryByIdentifier', 'removeEntry'], [], '', false ); - $entryRepository->method('findOneBy') + $entryRepository->method('findOneEntryByIdentifier') ->willReturn($entry); GeneralUtility::setSingletonInstance(EntryRepository::class, $entryRepository); @@ -254,12 +254,12 @@ public function testIsClientRestrictedWithLessFailures(): void $entryRepository = $this->getAccessibleMock( EntryRepository::class, - ['findOneBy', 'remove'], + ['findOneEntryByIdentifier', 'removeEntry'], [], '', false ); - $entryRepository->method('findOneBy') + $entryRepository->method('findOneEntryByIdentifier') ->willReturn($entry); GeneralUtility::setSingletonInstance(EntryRepository::class, $entryRepository); diff --git a/Tests/Functional/Domain/Service/RestrictionServiceFrontendNameAbstract.php b/Tests/Functional/Domain/Service/RestrictionServiceFrontendNameAbstract.php index 8b3785c..337afe6 100755 --- a/Tests/Functional/Domain/Service/RestrictionServiceFrontendNameAbstract.php +++ b/Tests/Functional/Domain/Service/RestrictionServiceFrontendNameAbstract.php @@ -123,7 +123,7 @@ public function testIsClientRestricted(): void $entryRepository = $this->getAccessibleMock( EntryRepository::class, - ['findOneBy', 'remove'], + ['findOneEntryByIdentifier', 'removeEntry'], [], '', false @@ -134,7 +134,7 @@ public function testIsClientRestricted(): void ->willReturn(0); $entry->method('getCrdate') ->willReturn(time() - 400); - $entryRepository->method('findOneBy') + $entryRepository->method('findOneEntryByIdentifier') ->willReturn($entry); GeneralUtility::setSingletonInstance(EntryRepository::class, $entryRepository); @@ -163,12 +163,12 @@ public function testIsClientRestrictedWithFailures(): void ->willReturn(time() - 400); $entryRepository = $this->getAccessibleMock( EntryRepository::class, - ['findOneBy', 'remove'], + ['findOneEntryByIdentifier', 'removeEntry'], [], '', false ); - $entryRepository->method('findOneBy') + $entryRepository->method('findOneEntryByIdentifier') ->willReturn($entry); GeneralUtility::setSingletonInstance(EntryRepository::class, $entryRepository); @@ -197,12 +197,12 @@ public function testIsClientRestrictedWithFailuresAndTimeout(): void ->willReturn(time() - 4000); $entryRepository = $this->getAccessibleMock( EntryRepository::class, - ['findOneBy', 'remove'], + ['findOneEntryByIdentifier', 'removeEntry'], [], '', false ); - $entryRepository->method('findOneBy') + $entryRepository->method('findOneEntryByIdentifier') ->willReturn($entry); GeneralUtility::setSingletonInstance(EntryRepository::class, $entryRepository); @@ -231,12 +231,12 @@ public function testIsClientRestrictedWithLessFailures(): void ->willReturn(time() - 400); $entryRepository = $this->getAccessibleMock( EntryRepository::class, - ['findOneBy', 'remove'], + ['findOneEntryByIdentifier', 'removeEntry'], [], '', false ); - $entryRepository->method('findOneBy') + $entryRepository->method('findOneEntryByIdentifier') ->willReturn($entry); GeneralUtility::setSingletonInstance(EntryRepository::class, $entryRepository); diff --git a/code-quality/phpstan-baseline.neon b/code-quality/phpstan-baseline.neon index 47cbc8a..f7ecb38 100644 --- a/code-quality/phpstan-baseline.neon +++ b/code-quality/phpstan-baseline.neon @@ -1,36 +1,5 @@ parameters: ignoreErrors: - - - - message: "#^Class Aoe\\\\FeloginBruteforceProtection\\\\Domain\\\\Repository\\\\Entry extends generic class TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\Repository but does not specify its types\\: T$#" - count: 1 - path: ../Classes/Domain/Repository/Entry.php - - - - message: "#^Method Aoe\\\\FeloginBruteforceProtection\\\\Domain\\\\Repository\\\\Entry\\:\\:cleanUp\\(\\) has parameter \\$identifier with no type specified\\.$#" - count: 1 - path: ../Classes/Domain/Repository/Entry.php - - - - message: "#^Method Aoe\\\\FeloginBruteforceProtection\\\\Domain\\\\Repository\\\\Entry\\:\\:cleanUp\\(\\) has parameter \\$maxFailures with no type specified\\.$#" - count: 1 - path: ../Classes/Domain/Repository/Entry.php - - - - message: "#^Method Aoe\\\\FeloginBruteforceProtection\\\\Domain\\\\Repository\\\\Entry\\:\\:cleanUp\\(\\) has parameter \\$restrictionTime with no type specified\\.$#" - count: 1 - path: ../Classes/Domain/Repository/Entry.php - - - - message: "#^Method Aoe\\\\FeloginBruteforceProtection\\\\Domain\\\\Repository\\\\Entry\\:\\:cleanUp\\(\\) has parameter \\$secondsTillReset with no type specified\\.$#" - count: 1 - path: ../Classes/Domain/Repository/Entry.php - - - - message: "#^Parameter \\#1 \\.\\.\\.\\$constraints of method TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\QueryInterface\\\\:\\:logicalAnd\\(\\) expects TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\Generic\\\\Qom\\\\ConstraintInterface, array\\ given\\.$#" - count: 2 - path: ../Classes/Domain/Repository/Entry.php - - message: "#^Class Aoe\\\\FeloginBruteforceProtection\\\\Domain\\\\Repository\\\\EntryRepository extends generic class TYPO3\\\\CMS\\\\Extbase\\\\Persistence\\\\Repository but does not specify its types\\: T$#" count: 1