diff --git a/.project/tests/phpstan-baseline.neon b/.project/tests/phpstan-baseline.neon index dce5a0fef..32511658e 100644 --- a/.project/tests/phpstan-baseline.neon +++ b/.project/tests/phpstan-baseline.neon @@ -6,6 +6,12 @@ parameters: count: 1 path: ../../Classes/Command/AbstractCleanupCommand.php + - + message: '#^Call to an undefined method object\:\:getValue\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../../Classes/Command/CleanupUnusedUploadsCommand.php + - message: '#^Method In2code\\Powermail\\Command\\CleanupUnusedUploadsCommand\:\:getUsedUploads\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -295,13 +301,13 @@ parameters: path: ../../Classes/Domain/Factory/FileFactory.php - - message: '#^Cannot call method getUid\(\) on In2code\\Powermail\\Domain\\Model\\Form\|TYPO3\\CMS\\Extbase\\Persistence\\Generic\\LazyLoadingProxy\|null\.$#' - identifier: method.nonObject + message: '#^Call to an undefined method object\:\:setPid\(\)\.$#' + identifier: method.notFound count: 1 path: ../../Classes/Domain/Factory/MailFactory.php - - message: '#^Cannot call method setPid\(\) on object\|null\.$#' + message: '#^Cannot call method getUid\(\) on In2code\\Powermail\\Domain\\Model\\Form\|TYPO3\\CMS\\Extbase\\Persistence\\Generic\\LazyLoadingProxy\|null\.$#' identifier: method.nonObject count: 1 path: ../../Classes/Domain/Factory/MailFactory.php @@ -936,6 +942,12 @@ parameters: count: 1 path: ../../Classes/Domain/Repository/MailRepository.php + - + message: '#^Call to an undefined method object\:\:getField\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../../Classes/Domain/Repository/MailRepository.php + - message: '#^Call to an undefined method object\:\:getForm\(\)\.$#' identifier: method.notFound @@ -955,33 +967,27 @@ parameters: path: ../../Classes/Domain/Repository/MailRepository.php - - message: '#^Call to an undefined method object\:\:getValue\(\)\.$#' + message: '#^Call to an undefined method object\:\:getUid\(\)\.$#' identifier: method.notFound - count: 1 - path: ../../Classes/Domain/Repository/MailRepository.php - - - - message: '#^Cannot call method getField\(\) on object\|null\.$#' - identifier: method.nonObject count: 2 path: ../../Classes/Domain/Repository/MailRepository.php - - message: '#^Cannot call method getMarker\(\) on class\-string\|object\.$#' - identifier: method.nonObject + message: '#^Call to an undefined method object\:\:getValue\(\)\.$#' + identifier: method.notFound count: 3 path: ../../Classes/Domain/Repository/MailRepository.php - - message: '#^Cannot call method getTitle\(\) on class\-string\|object\.$#' + message: '#^Cannot call method getMarker\(\) on class\-string\|object\.$#' identifier: method.nonObject count: 1 path: ../../Classes/Domain/Repository/MailRepository.php - - message: '#^Cannot call method getValue\(\) on object\|null\.$#' + message: '#^Cannot call method getTitle\(\) on class\-string\|object\.$#' identifier: method.nonObject - count: 2 + count: 1 path: ../../Classes/Domain/Repository/MailRepository.php - @@ -1152,12 +1158,6 @@ parameters: count: 1 path: ../../Classes/Domain/Repository/MailRepository.php - - - message: '#^Parameter \#1 \$object_or_class of function method_exists expects object\|string, object\|null given\.$#' - identifier: argument.type - count: 2 - path: ../../Classes/Domain/Repository/MailRepository.php - - message: '#^Parameter \#2 \$formUid of method In2code\\Powermail\\Domain\\Repository\\FieldRepository\:\:findByMarkerAndForm\(\) expects int, int\<1, max\>\|null given\.$#' identifier: argument.type @@ -2323,8 +2323,8 @@ parameters: path: ../../Classes/Domain/Validator/SpamShield/Breaker/IpBreaker.php - - message: '#^Cannot call method getValue\(\) on object\|null\.$#' - identifier: method.nonObject + message: '#^Call to an undefined method object\:\:getValue\(\)\.$#' + identifier: method.notFound count: 1 path: ../../Classes/Domain/Validator/SpamShield/Breaker/ValueBreaker.php @@ -2347,8 +2347,8 @@ parameters: path: ../../Classes/Domain/Validator/SpamShield/IpBlacklistMethod.php - - message: '#^Cannot call method getValue\(\) on object\|null\.$#' - identifier: method.nonObject + message: '#^Call to an undefined method object\:\:getValue\(\)\.$#' + identifier: method.notFound count: 2 path: ../../Classes/Domain/Validator/SpamShield/LinkMethod.php @@ -2371,14 +2371,14 @@ parameters: path: ../../Classes/Domain/Validator/SpamShield/MethodInterface.php - - message: '#^Cannot call method getField\(\) on object\|null\.$#' - identifier: method.nonObject + message: '#^Call to an undefined method object\:\:getField\(\)\.$#' + identifier: method.notFound count: 2 path: ../../Classes/Domain/Validator/SpamShield/NameMethod.php - - message: '#^Cannot call method getValue\(\) on object\|null\.$#' - identifier: method.nonObject + message: '#^Call to an undefined method object\:\:getValue\(\)\.$#' + identifier: method.notFound count: 3 path: ../../Classes/Domain/Validator/SpamShield/NameMethod.php @@ -2401,8 +2401,8 @@ parameters: path: ../../Classes/Domain/Validator/SpamShield/SessionMethod.php - - message: '#^Cannot call method getValue\(\) on object\|null\.$#' - identifier: method.nonObject + message: '#^Call to an undefined method object\:\:getValue\(\)\.$#' + identifier: method.notFound count: 3 path: ../../Classes/Domain/Validator/SpamShield/UniqueMethod.php @@ -2478,6 +2478,24 @@ parameters: count: 1 path: ../../Classes/Domain/Validator/SpamShieldValidator.php + - + message: '#^Result of && is always true\.$#' + identifier: booleanAnd.alwaysTrue + count: 1 + path: ../../Classes/Domain/Validator/StringValidator.php + + - + message: '#^Strict comparison using \!\=\= between non\-falsy\-string and '''' will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../Classes/Domain/Validator/StringValidator.php + + - + message: '#^Strict comparison using \!\=\= between non\-falsy\-string and ''0'' will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../Classes/Domain/Validator/StringValidator.php + - message: '#^Cannot call method getMarker\(\) on In2code\\Powermail\\Domain\\Model\\Field\|null\.$#' identifier: method.nonObject @@ -3819,13 +3837,7 @@ parameters: - message: '#^Method In2code\\Powermail\\Utility\\ReportingUtility\:\:getGroupedAnswersFromMails\(\) has parameter \$mails with no value type specified in iterable type iterable\<\(int\|string\), mixed\>\.$#' identifier: missingType.iterableValue - count: 1 - path: ../../Classes/Utility/ReportingUtility.php - - - - message: '#^Method In2code\\Powermail\\Utility\\ReportingUtility\:\:getGroupedAnswersFromMails\(\) has parameter \$mails with no value type specified in iterable type iterable\<\(int\|string\), mixed\>\|TYPO3\\CMS\\Extbase\\Persistence\\QueryResultInterface\.$#' - identifier: missingType.iterableValue - count: 1 + count: 2 path: ../../Classes/Utility/ReportingUtility.php - @@ -3843,13 +3855,7 @@ parameters: - message: '#^Method In2code\\Powermail\\Utility\\ReportingUtility\:\:getGroupedMarketingPropertiesFromMails\(\) has parameter \$mails with no value type specified in iterable type iterable\<\(int\|string\), mixed\>\.$#' identifier: missingType.iterableValue - count: 1 - path: ../../Classes/Utility/ReportingUtility.php - - - - message: '#^Method In2code\\Powermail\\Utility\\ReportingUtility\:\:getGroupedMarketingPropertiesFromMails\(\) has parameter \$mails with no value type specified in iterable type iterable\<\(int\|string\), mixed\>\|TYPO3\\CMS\\Extbase\\Persistence\\QueryResultInterface\.$#' - identifier: missingType.iterableValue - count: 1 + count: 2 path: ../../Classes/Utility/ReportingUtility.php - @@ -3966,6 +3972,12 @@ parameters: count: 1 path: ../../Classes/Utility/StringUtility.php + - + message: '#^Offset 1 might not exist on array\{\}\|array\{non\-falsy\-string, string\}\.$#' + identifier: offsetAccess.notFound + count: 1 + path: ../../Classes/Utility/StringUtility.php + - message: '#^Method In2code\\Powermail\\Utility\\TemplateUtility\:\:fluidParseString\(\) has parameter \$variables with no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -4098,6 +4110,18 @@ parameters: count: 1 path: ../../Classes/ViewHelpers/Condition/IsThereAMailWithStartingLetterViewHelper.php + - + message: '#^Result of && is always false\.$#' + identifier: booleanAnd.alwaysFalse + count: 1 + path: ../../Classes/ViewHelpers/Condition/OrViewHelper.php + + - + message: '#^Strict comparison using \=\=\= between 0\|0\.0\|''''\|''0''\|array\{\}\|false\|null and mixed will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: ../../Classes/ViewHelpers/Condition/OrViewHelper.php + - message: '#^Cannot cast object to string\.$#' identifier: cast.string @@ -4495,14 +4519,20 @@ parameters: path: ../../Classes/ViewHelpers/Misc/PrefillFieldViewHelper.php - - message: '#^Cannot call method getField\(\) on object\|null\.$#' - identifier: method.nonObject + message: '#^Strict comparison using \!\=\= between object and null will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../Classes/ViewHelpers/Misc/PrefillFieldViewHelper.php + + - + message: '#^Call to an undefined method object\:\:getField\(\)\.$#' + identifier: method.notFound count: 1 path: ../../Classes/ViewHelpers/Misc/PrefillMultiFieldViewHelper.php - - message: '#^Cannot call method getValue\(\) on object\|null\.$#' - identifier: method.nonObject + message: '#^Call to an undefined method object\:\:getValue\(\)\.$#' + identifier: method.notFound count: 1 path: ../../Classes/ViewHelpers/Misc/PrefillMultiFieldViewHelper.php diff --git a/Classes/Controller/FormController.php b/Classes/Controller/FormController.php index 3be0c7ec3..590f76ae9 100644 --- a/Classes/Controller/FormController.php +++ b/Classes/Controller/FormController.php @@ -30,6 +30,7 @@ use In2code\Powermail\Events\FormControllerOptinConfirmActionAfterPersistEvent; use In2code\Powermail\Events\FormControllerOptinConfirmActionBeforeRenderViewEvent; use In2code\Powermail\Exception\DeprecatedException; +use In2code\Powermail\Exception\SpamDetectedException; use In2code\Powermail\Finisher\FinisherRunner; use In2code\Powermail\Utility\ConfigurationUtility; use In2code\Powermail\Utility\DatabaseUtility; @@ -611,16 +612,20 @@ public function processRequest(RequestInterface $request): ResponseInterface } catch (PropagateResponseException $e) { return $e->getResponse(); } catch (BadRequestException $e) { + $logger = ObjectUtility::getLogger(__CLASS__); if (in_array($e->getCode(), [1581862822, 1699604555, 1691267306])) { // If the trustedProperties HMAC can not be validated, we redirect to an empty form because the // request cannot be salvaged and would lead to an infinite loop. - $logger = ObjectUtility::getLogger(__CLASS__); $logger->warning('Redirecting to empty form because HMAC validation failed.', [$e->getMessage()]); return $this->redirect('form'); } - $logger = ObjectUtility::getLogger(__CLASS__); $logger->critical('An error occurred: ', [$e->getMessage()]); return (new ForwardResponse('form'))->withoutArguments(); + } catch (SpamDetectedException $e) { + // Catch "Could not ultimately dispatch the request after 101 iterations" within spamshield + $logger = ObjectUtility::getLogger(__CLASS__); + $logger->critical('SPAM detected: ', [$e->getMessage()]); + return $this->redirect('form'); } catch (\Exception $e) { $logger = ObjectUtility::getLogger(__CLASS__); $logger->critical('An error occurred: ', [$e->getMessage()]); diff --git a/Classes/Domain/Validator/SpamShieldValidator.php b/Classes/Domain/Validator/SpamShieldValidator.php index 5026e2ade..1d392fa55 100644 --- a/Classes/Domain/Validator/SpamShieldValidator.php +++ b/Classes/Domain/Validator/SpamShieldValidator.php @@ -10,6 +10,7 @@ use In2code\Powermail\Domain\Validator\SpamShield\MethodInterface; use In2code\Powermail\Exception\ClassDoesNotExistException; use In2code\Powermail\Exception\InterfaceNotImplementedException; +use In2code\Powermail\Exception\SpamDetectedException; use In2code\Powermail\Utility\BasicFileUtility; use In2code\Powermail\Utility\ConfigurationUtility; use In2code\Powermail\Utility\FrontendUtility; @@ -77,6 +78,13 @@ protected function isValid($mail): void $this->setValidState(false); $this->sendSpamNotificationMail($mail); $this->logSpamNotification($mail); + throw new SpamDetectedException( + 'Powermail: Spam tolerance limit reached;' + . '; value: ' . $this->getCalculatedSpamFactor(true) + . '; form: ' . $mail->getForm()->getUid() + . ' on page: ' . $mail->getForm()->getPid(), + 1784729722 + ); } } diff --git a/Classes/Exception/SpamDetectedException.php b/Classes/Exception/SpamDetectedException.php new file mode 100644 index 000000000..41c4158a2 --- /dev/null +++ b/Classes/Exception/SpamDetectedException.php @@ -0,0 +1,26 @@ + HTTP Status Header lines + */ + protected $statusHeaders = [HttpUtility::HTTP_STATUS_406]; + + protected $title = 'Spam Detected'; + + protected $message = 'The request cannot be fulfilled due to detected spam.'; + + public function __construct($message = null, $code = 0) + { + if (!empty($message)) { + $this->message = $message; + } + parent::__construct($this->statusHeaders, $this->message, $this->title, $code); + } +} diff --git a/Classes/Update/PowermailTextNullUpdateWizard.php b/Classes/Update/PowermailTextNullUpdateWizard.php index 15a6187a7..47fd0e219 100644 --- a/Classes/Update/PowermailTextNullUpdateWizard.php +++ b/Classes/Update/PowermailTextNullUpdateWizard.php @@ -9,6 +9,7 @@ use TYPO3\CMS\Install\Attribute\UpgradeWizard; use TYPO3\CMS\Install\Updates\DatabaseUpdatedPrerequisite; use TYPO3\CMS\Install\Updates\UpgradeWizardInterface; + /** * If there are any TEXT legacy fields in the database, that have a NULL value * update them with an empty string.