From 6a7a114f035297e7cd8d50c18e6b98d38886f318 Mon Sep 17 00:00:00 2001 From: Alexander Kellner Date: Wed, 28 Feb 2024 14:16:06 +0100 Subject: [PATCH] [FEATURE] Respect authorization in activity protocol, conversion funnel and fingerprint profiles --- Classes/Controller/FrontendController.php | 16 +++---- Classes/Domain/Factory/VisitorFactory.php | 28 +++++++----- Classes/Domain/Model/Fingerprint.php | 28 ++++++++++++ Classes/Domain/Model/Log.php | 16 +++++++ Classes/Domain/Model/Pagevisit.php | 15 +++++++ Classes/Domain/Model/Visitor.php | 45 ++++++++++++++++--- .../TCA/tx_lux_domain_model_fingerprint.php | 10 ++++- .../Private/Language/de.locallang_db.xlf | 4 ++ Resources/Private/Language/locallang_db.xlf | 3 ++ ext_tables.sql | 2 + 10 files changed, 138 insertions(+), 29 deletions(-) diff --git a/Classes/Controller/FrontendController.php b/Classes/Controller/FrontendController.php index 2f3d47de..999d7358 100644 --- a/Classes/Controller/FrontendController.php +++ b/Classes/Controller/FrontendController.php @@ -3,6 +3,7 @@ declare(strict_types=1); namespace In2code\Lux\Controller; +use Doctrine\DBAL\Driver\Exception; use Doctrine\DBAL\Exception as ExceptionDbal; use In2code\Lux\Domain\Factory\VisitorFactory; use In2code\Lux\Domain\Model\Visitor; @@ -23,7 +24,6 @@ use In2code\Lux\Exception\ConfigurationException; use In2code\Lux\Exception\EmailValidationException; use In2code\Lux\Exception\FakeException; -use In2code\Lux\Exception\FileNotFoundException; use In2code\Lux\Utility\BackendUtility; use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Http\Message\ResponseInterface; @@ -79,6 +79,7 @@ public function initializeDispatchRequestAction(): void * @param array $arguments * @return ResponseInterface * @noinspection PhpUnused + * @throws InvalidConfigurationTypeException */ public function dispatchRequestAction( string $dispatchAction, @@ -378,10 +379,6 @@ protected function callAdditionalTrackers(Visitor $visitor, array $arguments): v $luxletterTracker->trackFromLuxletterLink(); } - /** - * @param Visitor $visitor - * @return array - */ protected function afterAction(Visitor $visitor): array { /** @var AfterTrackingEvent $event */ @@ -391,10 +388,6 @@ protected function afterAction(Visitor $visitor): array return $event->getResults(); } - /** - * @param Throwable $exception - * @return array - */ protected function getError(Throwable $exception): array { $this->eventDispatcher->dispatch( @@ -422,12 +415,13 @@ protected function getError(Throwable $exception): array * @param bool $tempVisitor * @return Visitor * @throws ConfigurationException + * @throws ExceptionDbal * @throws ExtensionConfigurationExtensionNotConfiguredException * @throws ExtensionConfigurationPathDoesNotExistException * @throws IllegalObjectTypeException - * @throws UnknownObjectException - * @throws FileNotFoundException * @throws InvalidConfigurationTypeException + * @throws UnknownObjectException + * @throws Exception */ protected function getVisitor(string $identificator, bool $tempVisitor = false): Visitor { diff --git a/Classes/Domain/Factory/VisitorFactory.php b/Classes/Domain/Factory/VisitorFactory.php index c8b212db..7c0fced4 100644 --- a/Classes/Domain/Factory/VisitorFactory.php +++ b/Classes/Domain/Factory/VisitorFactory.php @@ -3,22 +3,24 @@ declare(strict_types=1); namespace In2code\Lux\Domain\Factory; -use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Driver\Exception as ExceptionDbalDriver; +use Doctrine\DBAL\Exception as ExceptionDbal; use In2code\Lux\Domain\Factory\Ipinformation\Handler; use In2code\Lux\Domain\Model\Fingerprint; use In2code\Lux\Domain\Model\Visitor; use In2code\Lux\Domain\Repository\VisitorRepository; +use In2code\Lux\Domain\Service\SiteService; use In2code\Lux\Domain\Service\VisitorMergeService; use In2code\Lux\Events\Log\LogVisitorEvent; use In2code\Lux\Events\StopAnyProcessBeforePersistenceEvent; use In2code\Lux\Events\VisitorFactoryAfterCreateNewEvent; use In2code\Lux\Events\VisitorFactoryBeforeCreateNewEvent; use In2code\Lux\Exception\ConfigurationException; -use In2code\Lux\Exception\FileNotFoundException; use In2code\Lux\Exception\FingerprintMustNotBeEmptyException; use In2code\Lux\Exception\Validation\IdentificatorFormatException; use In2code\Lux\Utility\ConfigurationUtility; use In2code\Lux\Utility\CookieUtility; +use In2code\Lux\Utility\FrontendUtility; use In2code\Lux\Utility\IpUtility; use In2code\Lux\Utility\StringUtility; use Psr\EventDispatcher\EventDispatcherInterface; @@ -42,6 +44,7 @@ class VisitorFactory * @param string $identificator * @param bool $tempVisitor If there is no fingerprint (doNotTrack) but we even want to generate a visitor object * @throws FingerprintMustNotBeEmptyException + * @throws IdentificatorFormatException */ public function __construct(string $identificator, bool $tempVisitor = false) { @@ -49,7 +52,10 @@ public function __construct(string $identificator, bool $tempVisitor = false) if ($identificator === '' && $tempVisitor === true) { $identificator = StringUtility::getRandomString(32, false); } - $this->fingerprint = GeneralUtility::makeInstance(Fingerprint::class)->setValue($identificator); + $this->fingerprint = GeneralUtility::makeInstance(Fingerprint::class) + ->setValue($identificator) + ->setSite(GeneralUtility::makeInstance(SiteService::class) + ->getSiteIdentifierFromPageIdentifier(FrontendUtility::getCurrentPageIdentifier())); $this->visitorRepository = GeneralUtility::makeInstance(VisitorRepository::class); $this->eventDispatcher = GeneralUtility::makeInstance(EventDispatcherInterface::class); $this->eventDispatcher->dispatch( @@ -60,13 +66,13 @@ public function __construct(string $identificator, bool $tempVisitor = false) /** * @return Visitor * @throws ConfigurationException - * @throws DBALException + * @throws ExceptionDbal * @throws ExtensionConfigurationExtensionNotConfiguredException * @throws ExtensionConfigurationPathDoesNotExistException - * @throws FileNotFoundException * @throws IllegalObjectTypeException * @throws InvalidConfigurationTypeException * @throws UnknownObjectException + * @throws ExceptionDbalDriver */ public function getVisitor(): Visitor { @@ -90,9 +96,11 @@ public function getVisitor(): Visitor * respected, to not lose visitors when changing lux from 6.x to 7.x * * @return Visitor|null + * @throws ConfigurationException * @throws IllegalObjectTypeException * @throws UnknownObjectException - * @throws DBALException + * @throws ExceptionDbalDriver + * @throws ExceptionDbal */ protected function getVisitorFromDatabaseByFingerprint(): ?Visitor { @@ -133,13 +141,12 @@ protected function getVisitorFromDatabaseByLegacyCookie(): ?Visitor * @throws ExtensionConfigurationExtensionNotConfiguredException * @throws ExtensionConfigurationPathDoesNotExistException * @throws IllegalObjectTypeException - * @throws FileNotFoundException * @throws InvalidConfigurationTypeException */ protected function createNewVisitor(): Visitor { - $visitor = GeneralUtility::makeInstance(Visitor::class); - $visitor->addFingerprint($this->fingerprint); + $visitor = GeneralUtility::makeInstance(Visitor::class) + ->addFingerprint($this->fingerprint); $this->enrichNewVisitorWithIpInformation($visitor); $visitor->resetCompanyAutomatic(); // must be after enrichNewVisitorWithIpInformation() /** @var LogVisitorEvent $event */ @@ -150,10 +157,11 @@ protected function createNewVisitor(): Visitor /** * @param Visitor $visitor * @return void + * @throws ConfigurationException * @throws ExtensionConfigurationExtensionNotConfiguredException * @throws ExtensionConfigurationPathDoesNotExistException * @throws IllegalObjectTypeException - * @throws ConfigurationException + * @throws InvalidConfigurationTypeException */ protected function enrichNewVisitorWithIpInformation(Visitor $visitor) { diff --git a/Classes/Domain/Model/Fingerprint.php b/Classes/Domain/Model/Fingerprint.php index 85bad410..cdc5740f 100644 --- a/Classes/Domain/Model/Fingerprint.php +++ b/Classes/Domain/Model/Fingerprint.php @@ -3,7 +3,9 @@ declare(strict_types=1); namespace In2code\Lux\Domain\Model; +use In2code\Lux\Domain\Service\SiteService; use In2code\Lux\Exception\FingerprintMustNotBeEmptyException; +use In2code\Lux\Utility\BackendUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use WhichBrowser\Parser; @@ -17,6 +19,7 @@ class Fingerprint extends AbstractModel protected string $value = ''; protected string $domain = ''; protected string $userAgent = ''; + protected string $site = ''; protected int $type = 0; public function __construct(string $domain = '', string $userAgent = '') @@ -122,6 +125,17 @@ public function setUserAgent(string $userAgent): self return $this; } + public function getSite(): string + { + return $this->site; + } + + public function setSite(string $site): self + { + $this->site = $site; + return $this; + } + public function getType(): int { return $this->type; @@ -146,4 +160,18 @@ public function getTypeString(): string } return 'Unknown'; } + + /** + * Check if this record can be viewed by current editor + * + * @return bool + */ + public function canBeRead(): bool + { + if (BackendUtility::isAdministrator() || $this->site === '') { + return true; + } + $sites = GeneralUtility::makeInstance(SiteService::class)->getAllowedSites(); + return array_key_exists($this->getSite(), $sites); + } } diff --git a/Classes/Domain/Model/Log.php b/Classes/Domain/Model/Log.php index cc786442..c6091fdc 100644 --- a/Classes/Domain/Model/Log.php +++ b/Classes/Domain/Model/Log.php @@ -7,6 +7,8 @@ use In2code\Lux\Domain\Repository\LinklistenerRepository; use In2code\Lux\Domain\Repository\SearchRepository; use In2code\Lux\Domain\Repository\UtmRepository; +use In2code\Lux\Domain\Service\SiteService; +use In2code\Lux\Utility\BackendUtility; use In2code\Luxenterprise\Domain\Model\AbTestingPage; use In2code\Luxenterprise\Domain\Repository\AbTestingPageRepository; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -201,4 +203,18 @@ public static function getIdentifiedStatus(): array Log::STATUS_IDENTIFIED_EMAIL4LINK, ]; } + + /** + * Check if this record can be viewed by current editor + * + * @return bool + */ + public function canBeRead(): bool + { + if (BackendUtility::isAdministrator() || $this->site === '') { + return true; + } + $sites = GeneralUtility::makeInstance(SiteService::class)->getAllowedSites(); + return array_key_exists($this->getSite(), $sites); + } } diff --git a/Classes/Domain/Model/Pagevisit.php b/Classes/Domain/Model/Pagevisit.php index d9385572..2e84cbff 100644 --- a/Classes/Domain/Model/Pagevisit.php +++ b/Classes/Domain/Model/Pagevisit.php @@ -7,6 +7,7 @@ use In2code\Lux\Domain\Repository\NewsvisitRepository; use In2code\Lux\Domain\Service\Referrer\Readable; use In2code\Lux\Domain\Service\SiteService; +use In2code\Lux\Utility\BackendUtility; use In2code\Lux\Utility\FrontendUtility; use TYPO3\CMS\Core\Exception\SiteNotFoundException; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; @@ -194,4 +195,18 @@ public function getNewsvisit(): ?Newsvisit $newsvisitRepository = GeneralUtility::makeInstance(NewsvisitRepository::class); return $newsvisitRepository->findByPagevisit($this); } + + /** + * Check if this record can be viewed by current editor + * + * @return bool + */ + public function canBeRead(): bool + { + if (BackendUtility::isAdministrator() || $this->site === '') { + return true; + } + $sites = GeneralUtility::makeInstance(SiteService::class)->getAllowedSites(); + return array_key_exists($this->getSite(), $sites); + } } diff --git a/Classes/Domain/Model/Visitor.php b/Classes/Domain/Model/Visitor.php index fabb2ade..281e386e 100644 --- a/Classes/Domain/Model/Visitor.php +++ b/Classes/Domain/Model/Visitor.php @@ -243,11 +243,18 @@ public function increaseCategoryscoringByCategory(int $value, Category $category $this->setCategoryscoringByCategory($newScoring, $category); } - public function getFingerprints(): ?ObjectStorage + public function getFingerprints(): array { - return $this->fingerprints instanceof LazyLoadingProxy + $fingerprints = $this->fingerprints instanceof LazyLoadingProxy ? $this->fingerprints->_loadRealInstance() : $this->fingerprints; + $fpArray = $fingerprints->toArray(); + foreach ($fpArray as $key => $fingerprint) { + if ($fingerprint->canBeRead() === false) { + unset($fpArray[$key]); + } + } + return $fpArray; } /** @@ -257,7 +264,7 @@ public function getFingerprints(): ?ObjectStorage */ public function getFingerprintsSorted(): array { - $fingerprints = $this->getFingerprints()->toArray(); + $fingerprints = $this->getFingerprints(); return array_reverse($fingerprints); } @@ -432,6 +439,18 @@ public function setVisits(int $visits): self return $this; } + public function getPagevisitsAuthorized(): array + { + $pagevisits = $this->pagevisits->toArray(); + foreach ($pagevisits as $key => $pagevisit) { + /** @var Pagevisit $pagevisits */ + if ($pagevisit->canBeRead() === false) { + unset($pagevisits[$key]); + } + } + return $pagevisits; + } + /** * Get pagevisits of a visitor and sort it descending (last visit at first) * @@ -440,7 +459,7 @@ public function setVisits(int $visits): self */ public function getPagevisits(): array { - $pagevisits = $this->pagevisits; + $pagevisits = $this->getPagevisitsAuthorized(); $pagevisitsArray = []; /** @var Pagevisit $pagevisit */ foreach ($pagevisits as $pagevisit) { @@ -452,7 +471,7 @@ public function getPagevisits(): array public function getPagevisitsOfGivenPageIdentifier(int $pageIdentifier): array { - $pagevisits = $this->pagevisits; + $pagevisits = $this->getPagevisitsAuthorized(); $pagevisitsArray = []; /** @var Pagevisit $pagevisit */ foreach ($pagevisits as $pagevisit) { @@ -538,7 +557,7 @@ public function getLastPagevisit(): ?Pagevisit */ public function getNumberOfUniquePagevisits(): int { - $pagevisits = $this->pagevisits; + $pagevisits = $this->getPagevisitsAuthorized(); $number = 1; if (count($pagevisits) > 1) { /** @var DateTime $lastVisit **/ @@ -577,7 +596,7 @@ public function addNewsvisit(Newsvisit $newsvisits): self public function removeNewsvisit(Newsvisit $newsvisits): self { - $this->pagevisits->detach($newsvisits); + $this->newsvisits->detach($newsvisits); return $this; } @@ -762,10 +781,22 @@ public function getLastDownload(): ?Download public function getLogs(): array { $logs = $this->logs->toArray(); + $logs = $this->filterLogsByAuthentication($logs); krsort($logs); return $logs; } + protected function filterLogsByAuthentication(array $logs): array + { + foreach ($logs as $key => $log) { + /** @var Log $log */ + if ($log->canBeRead() === false) { + unset($logs[$key]); + } + } + return $logs; + } + public function getLatestLog(): ?Log { $logs = $this->getLogs(); diff --git a/Configuration/TCA/tx_lux_domain_model_fingerprint.php b/Configuration/TCA/tx_lux_domain_model_fingerprint.php index f3bf429b..02b5745d 100644 --- a/Configuration/TCA/tx_lux_domain_model_fingerprint.php +++ b/Configuration/TCA/tx_lux_domain_model_fingerprint.php @@ -24,7 +24,7 @@ 'hideTable' => true, ], 'types' => [ - '1' => ['showitem' => 'value,domain,user_agent,type'], + '1' => ['showitem' => 'value,domain,site,user_agent,type'], ], 'columns' => [ 'value' => [ @@ -43,6 +43,14 @@ 'readOnly' => true, ], ], + 'site' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:lux/Resources/Private/Language/locallang_db.xlf:' . Fingerprint::TABLE_NAME . '.site', + 'config' => [ + 'type' => 'input', + 'readOnly' => true, + ], + ], 'user_agent' => [ 'exclude' => true, 'label' => diff --git a/Resources/Private/Language/de.locallang_db.xlf b/Resources/Private/Language/de.locallang_db.xlf index a8a97f63..dd14f798 100644 --- a/Resources/Private/Language/de.locallang_db.xlf +++ b/Resources/Private/Language/de.locallang_db.xlf @@ -140,6 +140,10 @@ Domain Domain + + Site + Site + User agent User agent diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf index 32011ee9..14540333 100644 --- a/Resources/Private/Language/locallang_db.xlf +++ b/Resources/Private/Language/locallang_db.xlf @@ -106,6 +106,9 @@ Domain + + Site + User agent diff --git a/ext_tables.sql b/ext_tables.sql index fc7a82c2..b62cc893 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -65,6 +65,7 @@ CREATE TABLE tx_lux_domain_model_fingerprint ( domain varchar(255) DEFAULT '' NOT NULL, user_agent varchar(512) DEFAULT '' NOT NULL, type int(11) unsigned DEFAULT '0' NOT NULL, + site varchar(255) DEFAULT '' NOT NULL, tstamp int(11) unsigned DEFAULT '0' NOT NULL, crdate int(11) unsigned DEFAULT '0' NOT NULL, @@ -85,6 +86,7 @@ CREATE TABLE tx_lux_domain_model_fingerprint ( KEY domain (domain(50)), KEY user_agent (user_agent(50)), KEY type (type), + KEY site (site(50)), KEY crdate (crdate), KEY language (l10n_parent,sys_language_uid) );