Skip to content

Commit

Permalink
[!!!][TASK] Added TYPO3 13 compatibility
Browse files Browse the repository at this point in the history
This commit contains a breaking change, which must be migrated
manually.

The following TypoScript settings must be migrated to site settings:

* `plugin.tx_fechangepwd.settings.changePasswordPid` => `fe_change_pwd.changePasswordPid`
* `plugin.tx_fechangepwd.settings.redirect.*` => `fe_change_pwd.redirect.*`

Closes #82
Closes #75
  • Loading branch information
derhansen committed Jul 15, 2024
1 parent bea3628 commit e854495
Show file tree
Hide file tree
Showing 28 changed files with 287 additions and 250 deletions.
14 changes: 7 additions & 7 deletions .Build/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
],
"require": {
"derhansen/fe_change_pwd": "@dev",
"typo3/cms-core": "^12.4",
"typo3/cms-core": "^13.2 || dev-main",
"ext-curl": "*",
"ext-pdo": "*",
"php": ">=8.1"
},
"require-dev": {
"typo3/cms-backend": "^12.4",
"typo3/cms-frontend": "^12.4",
"typo3/cms-recordlist": "^12.4",
"typo3/cms-extbase": "^12.4",
"typo3/cms-fluid": "^12.4",
"typo3/cms-backend": "^13.2 || dev-main",
"typo3/cms-frontend": "^13.2 || dev-main",
"typo3/cms-recordlist": "^13.2 || dev-main",
"typo3/cms-extbase": "^13.2 || dev-main",
"typo3/cms-fluid": "^13.2 || dev-main",
"typo3/cms-composer-installers": "^5.0",
"typo3/testing-framework": "^8.0.0 || dev-main",
"typo3/testing-framework": "^8.2.0 || dev-main",
"friendsofphp/php-cs-fixer": "^3.12.0",
"saschaegerer/phpstan-typo3": "^1.1.2",
"phpstan/extension-installer": "^1.1"
Expand Down
34 changes: 21 additions & 13 deletions .Build/php-cs-fixer/.php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,45 @@
->setRiskyAllowed(true)
->setRules([
'@DoctrineAnnotation' => true,
'@PER' => true,
// @todo: Switch to @PER-CS2.0 once php-cs-fixer's todo list is done: https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/7247
'@PER-CS1.0' => true,
'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'blank_line_after_opening_tag' => true,
'braces' => ['allow_single_line_closure' => true],
'cast_spaces' => ['space' => 'none'],
'compact_nullable_typehint' => true,
// @todo: Can be dropped once we enable @PER-CS2.0
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => ['space' => 'none'],
'declare_parentheses' => true,
'dir_constant' => true,
'function_typehint_space' => true,
'lowercase_cast' => true,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
// @todo: Can be dropped once we enable @PER-CS2.0
'function_declaration' => [
'closure_fn_spacing' => 'none',
],
'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']],
'type_declaration_spaces' => true,
'global_namespace_import' => ['import_classes' => false, 'import_constants' => false, 'import_functions' => false],
'list_syntax' => ['syntax' => 'short'],
// @todo: Can be dropped once we enable @PER-CS2.0
'method_argument_space' => true,
'modernize_strpos' => true,
'modernize_types_casting' => true,
'native_function_casing' => true,
'new_with_braces' => true,
'no_alias_functions' => true,
'no_blank_lines_after_phpdoc' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_blank_lines' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_null_property_initialization' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_superfluous_elseif' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_trailing_comma_in_singleline' => true,
'no_unneeded_control_parentheses' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_nullsafe_operator' => true,
'no_whitespace_in_blank_line' => true,
'ordered_imports' => true,
'ordered_imports' => ['imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha'],
'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']],
'php_unit_mock_short_will_return' => true,
'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],
Expand All @@ -59,8 +65,10 @@
'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
'return_type_declaration' => ['space_before' => 'none'],
'single_quote' => true,
'single_space_around_construct' => true,
'single_line_comment_style' => ['comment_types' => ['hash']],
'single_trait_insert_per_statement' => true,
// @todo: Can be dropped once we enable @PER-CS2.0
'single_line_empty_body' => true,
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
'whitespace_after_comma_in_array' => ['ensure_single_space' => true],
'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false],
Expand Down
8 changes: 6 additions & 2 deletions .Build/phpstan/phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@ parameters:
- ../../Classes/
- ../../Configuration/

checkMissingIterableValueType: false
reportUnmatchedIgnoredErrors: true
ignoreErrors:
- identifier: missingType.iterableValue
reportUnmatchedIgnoredErrors: true
typo3:
requestGetAttributeMapping:
frontend.page.information: \TYPO3\CMS\Frontend\Page\PageInformation
5 changes: 3 additions & 2 deletions .github/workflows/CodeQuality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ jobs:
strategy:
matrix:
env:
- { php: 8.1}
- { php: 8.2}
- { php: 8.3}
- { php: 8.4}

env: ${{ matrix.env }}

Expand Down Expand Up @@ -44,4 +45,4 @@ jobs:
- name: Run phpstan checks
run: |
.Build/vendor/bin/phpstan --configuration=.Build/phpstan/phpstan.neon
.Build/vendor/bin/phpstan --configuration=.Build/phpstan/phpstan.neon
6 changes: 3 additions & 3 deletions .github/workflows/Tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
typo3: ['^12.4']
php: ['8.1', '8.2']
typo3: ['^13.2', 'dev-main']
php: ['8.2', '8.3', '8.4']

steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -37,4 +37,4 @@ jobs:
git checkout composer.json
- name: Unit Tests
run: .Build/vendor/bin/phpunit --colors -c .Build/phpunit/UnitTests.xml
run: .Build/vendor/bin/phpunit -c .Build/phpunit/UnitTests.xml
30 changes: 13 additions & 17 deletions Classes/Controller/PasswordController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
use Derhansen\FeChangePwd\Domain\Model\Dto\ChangePassword;
use Derhansen\FeChangePwd\Event\AfterPasswordUpdatedEvent;
use Derhansen\FeChangePwd\Exception\InvalidEmailAddressException;
use Derhansen\FeChangePwd\Exception\MissingFeatureToggleException;
use Derhansen\FeChangePwd\Service\FrontendUserService;
use Derhansen\FeChangePwd\Service\SettingsService;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Configuration\Features;
use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
Expand All @@ -28,29 +28,20 @@ class PasswordController extends ActionController
{
public function __construct(
protected readonly FrontendUserService $frontendUserService,
protected readonly Features $features,
protected readonly SettingsService $settingsService,
) {}

public function initializeAction(): void
{
if (!$this->features->isFeatureEnabled('security.usePasswordPolicyForFrontendUsers')) {
throw new MissingFeatureToggleException(
'Extension fe_change_pwd relies on TYPO3 password policies being enabled. Please activate security.usePasswordPolicyForFrontendUsers feature toggle.',
1683482651
);
}
}

/**
* Edit action
*/
public function editAction(): ResponseInterface
{
$changePassword = new ChangePassword();
$changePassword->setChangeHmac($this->frontendUserService->getChangeHmac());
$changePassword->setChangeHmac($this->frontendUserService->getChangeHmac($this->request));
$this->view->assignMultiple([
'changePasswordReason' => $this->frontendUserService->getMustChangePasswordReason(),
'changePasswordReason' => $this->frontendUserService->getMustChangePasswordReason($this->request),
'changePassword' => $changePassword,
'siteSettings' => $this->settingsService->getSiteSettings($this->request),
]);

return $this->htmlResponse();
Expand All @@ -63,7 +54,7 @@ public function initializeUpdateAction(): void
{
$changePasswordArray = $this->request->getArgument('changePassword');
$changeHmac = $changePasswordArray['changeHmac'] ? (string)$changePasswordArray['changeHmac'] : '';
if (!$this->frontendUserService->validateChangeHmac($changeHmac)) {
if (!$this->frontendUserService->validateChangeHmac($this->request, $changeHmac)) {
throw new InvalidHashException(
'Possible CSRF detected. Ensure a valid "changeHmac" is provided.',
1572672118
Expand All @@ -78,7 +69,7 @@ public function initializeUpdateAction(): void
*/
public function updateAction(ChangePassword $changePassword): ResponseInterface
{
$this->frontendUserService->updatePassword($changePassword->getPassword1(), $this->settings);
$this->frontendUserService->updatePassword($this->request, $changePassword->getPassword1(), $this->settings);

$this->eventDispatcher->dispatch(new AfterPasswordUpdatedEvent($changePassword, $this));

Expand Down Expand Up @@ -123,4 +114,9 @@ protected function getErrorFlashMessage(): bool
{
return false;
}

protected function getFrontendUser(): AbstractUserAuthentication
{
return $this->request->getAttribute('frontend.user');
}
}
4 changes: 1 addition & 3 deletions Classes/Exception/InvalidEmailAddressException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@

namespace Derhansen\FeChangePwd\Exception;

use Exception;

class InvalidEmailAddressException extends Exception {}
class InvalidEmailAddressException extends \Exception {}
4 changes: 1 addition & 3 deletions Classes/Exception/InvalidUserException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@

namespace Derhansen\FeChangePwd\Exception;

use Exception;

class InvalidUserException extends Exception {}
class InvalidUserException extends \Exception {}
4 changes: 1 addition & 3 deletions Classes/Exception/MissingFeatureToggleException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@

namespace Derhansen\FeChangePwd\Exception;

use Exception;

class MissingFeatureToggleException extends Exception {}
class MissingFeatureToggleException extends \Exception {}
4 changes: 1 addition & 3 deletions Classes/Exception/MissingPasswordHashServiceException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@

namespace Derhansen\FeChangePwd\Exception;

use Exception;

class MissingPasswordHashServiceException extends Exception {}
class MissingPasswordHashServiceException extends \Exception {}
4 changes: 1 addition & 3 deletions Classes/Exception/NoChangePasswordPidException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@

namespace Derhansen\FeChangePwd\Exception;

use Exception;

class NoChangePasswordPidException extends Exception {}
class NoChangePasswordPidException extends \Exception {}
48 changes: 24 additions & 24 deletions Classes/Middleware/ForcePasswordChangeRedirect.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use TYPO3\CMS\Core\Http\RedirectResponse;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Core\Site\Entity\Site;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;

/**
* This middleware redirects the current frontend user to a configured page if the user must change the password
Expand All @@ -39,49 +38,50 @@ public function __construct(
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$typoScriptFrontendController = $request->getAttribute('frontend.controller');
$pageInformation = $request->getAttribute('frontend.page.information');
$frontendUser = $request->getAttribute('frontend.user');
$pageUid = $typoScriptFrontendController->id;
$pageUid = $pageInformation->getId();

// Early return, if no frontend user
if (!isset($frontendUser->user['uid'])) {
return $handler->handle($request);
}

$settings = $this->settingsService->getSettings($request);
$siteSettings = $this->settingsService->getSiteSettings($request);

// Early return if page is excluded from redirect or user is not forced to change the password
if (!$this->frontendUserService->mustChangePassword($frontendUser->user) ||
$this->pageAccessService->isExcludePage($pageUid, $settings)
if (!$this->frontendUserService->mustChangePassword($request, $frontendUser->user) ||
$this->pageAccessService->isExcludePage($pageUid, $siteSettings)
) {
return $handler->handle($request);
}

switch ($this->pageAccessService->getRedirectMode($settings)) {
switch ($this->pageAccessService->getRedirectMode($siteSettings)) {
case 'allAccessProtectedPages':
$mustRedirect = $this->pageAccessService->isAccessProtectedPageInRootline($typoScriptFrontendController->rootLine);
$mustRedirect = $this->pageAccessService->isAccessProtectedPageInRootline(
$pageInformation->getLocalRootLine()
);
break;
case 'includePageUids':
$mustRedirect = $this->pageAccessService->isIncludePage($pageUid, $settings);
$mustRedirect = $this->pageAccessService->isIncludePage($pageUid, $siteSettings);
break;
default:
$mustRedirect = false;
}

if ($mustRedirect) {
$typoScriptFrontendController->calculateLinkVars($request->getQueryParams());
$parameter = $this->pageAccessService->getRedirectPid($settings);
if (MathUtility::canBeInterpretedAsInteger($pageUid) &&
$typoScriptFrontendController->getPageArguments()->getPageType()
) {
$parameter .= ',' . $typoScriptFrontendController->getPageArguments()->getPageType();
}
$url = GeneralUtility::makeInstance(ContentObjectRenderer::class, $typoScriptFrontendController)->typoLink_URL([
'parameter' => $parameter,
'addQueryString' => true,
'addQueryString.' => ['exclude' => 'id'],
'forceAbsoluteUrl' => true,
]);
$redirectPid = $this->pageAccessService->getRedirectPid($siteSettings);

/** @var SiteLanguage $language */
$language = $request->getAttribute('language');

/** @var Site $site */
$site = $request->getAttribute('site');
$router = $site->getRouter();

$parameter = ['_language' => $language];
// @todo: Provide PSR-14 event to modify parameter
$url = (string)$router->generateUri($redirectPid, $parameter);
return new RedirectResponse($url, 307);
}

Expand Down
Loading

0 comments on commit e854495

Please sign in to comment.