From 629541cb4cd92d7c463fa3c1f115508ac065a44d Mon Sep 17 00:00:00 2001 From: Sven Wappler Date: Mon, 10 Aug 2026 22:31:17 +0200 Subject: [PATCH] TYPO3 v15 dev-main snapshot () --- .gitignore | 1 + .../IncompleteConfigurationException.php | 23 ++ .../Configuration/RecoveryConfiguration.php | 140 ++++++++ .../Configuration/RedirectConfiguration.php | 86 +++++ Classes/Controller/LoginController.php | 248 +++++++++++++ .../Controller/PasswordRecoveryController.php | 314 ++++++++++++++++ .../FrontendUserGroupRepository.php | 50 +++ .../Repository/FrontendUserRepository.php | 141 ++++++++ Classes/Event/AbstractConfirmedEvent.php | 50 +++ Classes/Event/BeforeRedirectEvent.php | 54 +++ Classes/Event/LoginConfirmedEvent.php | 24 ++ Classes/Event/LoginErrorOccurredEvent.php | 35 ++ Classes/Event/LogoutConfirmedEvent.php | 24 ++ Classes/Event/ModifyLoginFormViewEvent.php | 42 +++ ...ModifyRedirectUrlValidationResultEvent.php | 52 +++ Classes/Event/PasswordChangeEvent.php | 53 +++ Classes/Event/ProcessRequestTokenListener.php | 43 +++ Classes/Event/SendRecoveryEmailEvent.php | 41 +++ Classes/Redirect/RedirectHandler.php | 249 +++++++++++++ Classes/Redirect/RedirectMode.php | 35 ++ Classes/Redirect/RedirectModeHandler.php | 181 ++++++++++ Classes/Service/RecoveryService.php | 132 +++++++ Classes/Validation/RedirectUrlValidator.php | 120 +++++++ Configuration/FlexForms/Login.xml | 297 +++++++++++++++ Configuration/Services.yaml | 21 ++ Configuration/Sets/Felogin/config.yaml | 1 + Configuration/Sets/Felogin/labels.xlf | 178 +++++++++ .../Sets/Felogin/settings.definitions.yaml | 107 ++++++ Configuration/Sets/Felogin/setup.typoscript | 1 + Configuration/TCA/Overrides/fe_groups.php | 22 ++ Configuration/TCA/Overrides/fe_users.php | 29 ++ Configuration/TCA/Overrides/tt_content.php | 15 + Configuration/TypoScript/constants.typoscript | 71 ++++ Configuration/TypoScript/setup.typoscript | 58 +++ Documentation/Configuration/Index.rst | 21 ++ .../Configuration/SettingsEditor.rst | 24 ++ Documentation/Configuration/SiteSets.rst | 111 ++++++ Documentation/Configuration/TypoScript.rst | 293 +++++++++++++++ .../Configuration/_SettingsOrder.rst.txt | 5 + .../Configuration/_constants.typoscript | 4 + Documentation/Configuration/_settings.yaml | 4 + Documentation/Configuration/_setup.typoscript | 5 + Documentation/Configuration/_site_config.diff | 5 + .../Configuration/_site_package_set.diff | 9 + Documentation/Events/Index.rst | 60 ++++ Documentation/Examples/Index.rst | 199 ++++++++++ .../Examples/_RedirectLoginErrorHandler.php | 157 ++++++++ Documentation/GetPostParameters/Index.rst | 31 ++ Documentation/Images/ContentElementWizard.png | Bin 0 -> 20667 bytes Documentation/Images/FlexFormKey.png | Bin 0 -> 5588 bytes Documentation/Images/GeneralSettings.png | Bin 0 -> 23503 bytes Documentation/Images/InstallActivate.png | Bin 0 -> 20379 bytes .../Images/MessagesConfiguration.png | Bin 0 -> 14820 bytes .../Images/RedirectConfiguration.png | Bin 0 -> 35115 bytes .../SettingsRedirectCustomErrorHandler.png | Bin 0 -> 37079 bytes Documentation/Images/SiteSet.png | Bin 0 -> 41353 bytes .../felogin_site_settings_error_handling.png | Bin 0 -> 46576 bytes Documentation/Includes.rst.txt | 1 + Documentation/Index.rst | 57 +++ Documentation/Installation/Index.rst | 57 +++ Documentation/Introduction/Index.rst | 60 ++++ Documentation/KnownProblems/Index.rst | 20 ++ .../LoginMechanism/Display/Index.rst | 19 + Documentation/LoginMechanism/Index.rst | 22 ++ .../LoginMechanism/LoginProcess/Index.rst | 22 ++ .../LoginMechanism/RedirectModes/Index.rst | 103 ++++++ Documentation/Sitemap.rst | 9 + Documentation/UsersManual/Index.rst | 58 +++ Documentation/guides.xml | 21 ++ LICENSE.txt | 339 ++++++++++++++++++ README.rst | 11 + .../Templates/PasswordRecovery.fluid.html | 16 + .../Templates/PasswordRecovery.fluid.txt | 9 + Resources/Private/Language/Database.xlf | 167 +++++++++ Resources/Private/Language/locallang.xlf | 172 +++++++++ .../Partials/RenderLabelOrMessage.fluid.html | 12 + .../Partials/ValidationErrors.fluid.html | 17 + .../Private/Templates/Login/Login.fluid.html | 81 +++++ .../Private/Templates/Login/Logout.fluid.html | 33 ++ .../Templates/Login/Overview.fluid.html | 10 + .../PasswordRecovery/Recovery.fluid.html | 33 ++ .../ShowChangePassword.fluid.html | 51 +++ Resources/Public/Icons/Extension.png | Bin 0 -> 1914 bytes composer.json | 56 +++ ext_localconf.php | 33 ++ ext_tables.sql | 5 + 86 files changed, 5360 insertions(+) create mode 100644 .gitignore create mode 100644 Classes/Configuration/IncompleteConfigurationException.php create mode 100644 Classes/Configuration/RecoveryConfiguration.php create mode 100644 Classes/Configuration/RedirectConfiguration.php create mode 100644 Classes/Controller/LoginController.php create mode 100644 Classes/Controller/PasswordRecoveryController.php create mode 100644 Classes/Domain/Repository/FrontendUserGroupRepository.php create mode 100644 Classes/Domain/Repository/FrontendUserRepository.php create mode 100644 Classes/Event/AbstractConfirmedEvent.php create mode 100644 Classes/Event/BeforeRedirectEvent.php create mode 100644 Classes/Event/LoginConfirmedEvent.php create mode 100644 Classes/Event/LoginErrorOccurredEvent.php create mode 100644 Classes/Event/LogoutConfirmedEvent.php create mode 100644 Classes/Event/ModifyLoginFormViewEvent.php create mode 100644 Classes/Event/ModifyRedirectUrlValidationResultEvent.php create mode 100644 Classes/Event/PasswordChangeEvent.php create mode 100644 Classes/Event/ProcessRequestTokenListener.php create mode 100644 Classes/Event/SendRecoveryEmailEvent.php create mode 100644 Classes/Redirect/RedirectHandler.php create mode 100644 Classes/Redirect/RedirectMode.php create mode 100644 Classes/Redirect/RedirectModeHandler.php create mode 100644 Classes/Service/RecoveryService.php create mode 100644 Classes/Validation/RedirectUrlValidator.php create mode 100644 Configuration/FlexForms/Login.xml create mode 100644 Configuration/Services.yaml create mode 100644 Configuration/Sets/Felogin/config.yaml create mode 100644 Configuration/Sets/Felogin/labels.xlf create mode 100644 Configuration/Sets/Felogin/settings.definitions.yaml create mode 100644 Configuration/Sets/Felogin/setup.typoscript create mode 100644 Configuration/TCA/Overrides/fe_groups.php create mode 100644 Configuration/TCA/Overrides/fe_users.php create mode 100644 Configuration/TCA/Overrides/tt_content.php create mode 100644 Configuration/TypoScript/constants.typoscript create mode 100644 Configuration/TypoScript/setup.typoscript create mode 100644 Documentation/Configuration/Index.rst create mode 100644 Documentation/Configuration/SettingsEditor.rst create mode 100644 Documentation/Configuration/SiteSets.rst create mode 100644 Documentation/Configuration/TypoScript.rst create mode 100644 Documentation/Configuration/_SettingsOrder.rst.txt create mode 100644 Documentation/Configuration/_constants.typoscript create mode 100644 Documentation/Configuration/_settings.yaml create mode 100644 Documentation/Configuration/_setup.typoscript create mode 100644 Documentation/Configuration/_site_config.diff create mode 100644 Documentation/Configuration/_site_package_set.diff create mode 100644 Documentation/Events/Index.rst create mode 100644 Documentation/Examples/Index.rst create mode 100644 Documentation/Examples/_RedirectLoginErrorHandler.php create mode 100644 Documentation/GetPostParameters/Index.rst create mode 100644 Documentation/Images/ContentElementWizard.png create mode 100644 Documentation/Images/FlexFormKey.png create mode 100644 Documentation/Images/GeneralSettings.png create mode 100644 Documentation/Images/InstallActivate.png create mode 100644 Documentation/Images/MessagesConfiguration.png create mode 100644 Documentation/Images/RedirectConfiguration.png create mode 100644 Documentation/Images/SettingsRedirectCustomErrorHandler.png create mode 100644 Documentation/Images/SiteSet.png create mode 100644 Documentation/Images/felogin_site_settings_error_handling.png create mode 100644 Documentation/Includes.rst.txt create mode 100644 Documentation/Index.rst create mode 100644 Documentation/Installation/Index.rst create mode 100644 Documentation/Introduction/Index.rst create mode 100644 Documentation/KnownProblems/Index.rst create mode 100644 Documentation/LoginMechanism/Display/Index.rst create mode 100644 Documentation/LoginMechanism/Index.rst create mode 100644 Documentation/LoginMechanism/LoginProcess/Index.rst create mode 100644 Documentation/LoginMechanism/RedirectModes/Index.rst create mode 100644 Documentation/Sitemap.rst create mode 100644 Documentation/UsersManual/Index.rst create mode 100644 Documentation/guides.xml create mode 100644 LICENSE.txt create mode 100644 README.rst create mode 100644 Resources/Private/Email/Templates/PasswordRecovery.fluid.html create mode 100644 Resources/Private/Email/Templates/PasswordRecovery.fluid.txt create mode 100644 Resources/Private/Language/Database.xlf create mode 100644 Resources/Private/Language/locallang.xlf create mode 100644 Resources/Private/Partials/RenderLabelOrMessage.fluid.html create mode 100644 Resources/Private/Partials/ValidationErrors.fluid.html create mode 100644 Resources/Private/Templates/Login/Login.fluid.html create mode 100644 Resources/Private/Templates/Login/Logout.fluid.html create mode 100644 Resources/Private/Templates/Login/Overview.fluid.html create mode 100644 Resources/Private/Templates/PasswordRecovery/Recovery.fluid.html create mode 100644 Resources/Private/Templates/PasswordRecovery/ShowChangePassword.fluid.html create mode 100644 Resources/Public/Icons/Extension.png create mode 100644 composer.json create mode 100644 ext_localconf.php create mode 100644 ext_tables.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/Classes/Configuration/IncompleteConfigurationException.php b/Classes/Configuration/IncompleteConfigurationException.php new file mode 100644 index 0000000..b5c5c10 --- /dev/null +++ b/Classes/Configuration/IncompleteConfigurationException.php @@ -0,0 +1,23 @@ +settings = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS); + $this->forgotHash = $this->getLifeTimeTimestamp() . '|' . $this->generateHash($random, $hashService); + $this->resolveFromTypoScript(); + } + + /** + * Returns the forgot hash. + */ + public function getForgotHash(): string + { + return $this->forgotHash; + } + + /** + * Returns email template name configured in TypoScript + */ + public function getMailTemplateName(): string + { + return $this->mailTemplateName; + } + + /** + * Returns TTL timestamp of the forgot hash + */ + public function getLifeTimeTimestamp(): int + { + if ($this->timestamp === null) { + $lifetimeInHours = (int)($this->settings['forgotLinkHashValidTime'] ?? 0) ?: 12; + $currentTimestamp = $this->context->getPropertyFromAspect('date', 'timestamp'); + $this->timestamp = $currentTimestamp + 3600 * $lifetimeInHours; + } + + return $this->timestamp; + } + + /** + * Returns reply-to address if configured otherwise null. + */ + public function getReplyTo(): ?Address + { + return $this->replyTo; + } + + /** + * Returns the sender. Normally the current typo3 installation. + */ + public function getSender(): Address + { + return $this->sender; + } + + protected function generateHash(Random $random, HashService $hashService): string + { + $randomString = $random->generateRandomHexString(16); + + return $hashService->hmac($randomString, self::class, HashAlgo::SHA3_256); + } + + protected function resolveFromTypoScript(): void + { + $fromAddress = ($this->settings['email_from'] ?? null) ?: $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress']; + if (empty($fromAddress)) { + throw new IncompleteConfigurationException( + 'Either "$GLOBALS[\'TYPO3_CONF_VARS\'][\'MAIL\'][\'defaultMailFromAddress\']" or extension key "plugin.tx_felogin_login.settings.email_from" cannot be empty!', + 1573825624 + ); + } + $fromName = ($this->settings['email_fromName'] ?? null) ?: $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromName']; + if (empty($fromName)) { + throw new IncompleteConfigurationException( + 'Either "$GLOBALS[\'TYPO3_CONF_VARS\'][\'MAIL\'][\'defaultMailFromName\']" or extension key "plugin.tx_felogin_login.settings.email_fromName" cannot be empty!', + 1573825625 + ); + } + $this->sender = new Address($fromAddress, $fromName); + if (!empty($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailReplyToAddress'])) { + if ($GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailReplyToName']) { + $this->replyTo = new Address( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailReplyToAddress'], + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailReplyToName'] + ); + } else { + $this->replyTo = new Address( + $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailReplyToAddress'] + ); + } + } + $this->mailTemplateName = (string)($this->settings['email']['templateName'] ?? ''); + if (empty($this->mailTemplateName)) { + throw new IncompleteConfigurationException( + 'Key "plugin.tx_felogin_login.settings.email.templateName" cannot be empty! Ensure that TypoScript is properly included.', + 1584998393 + ); + } + } +} diff --git a/Classes/Configuration/RedirectConfiguration.php b/Classes/Configuration/RedirectConfiguration.php new file mode 100644 index 0000000..cc5d3f2 --- /dev/null +++ b/Classes/Configuration/RedirectConfiguration.php @@ -0,0 +1,86 @@ +modes = is_array($mode) ? $mode : GeneralUtility::trimExplode(',', $mode ?? '', true); + } + + public function getModes(): array + { + return $this->modes; + } + + public function getFirstMode(): string + { + return $this->firstMode; + } + + public function getPageOnLogin(): int + { + return $this->pageOnLogin; + } + + public function getDomains(): string + { + return $this->domains; + } + + public function getPageOnLoginError(): int + { + return $this->pageOnLoginError; + } + + public function getPageOnLogout(): int + { + return $this->pageOnLogout; + } + + /** + * Factory when creating a configuration out of Extbase / plugin settings. + */ + public static function fromSettings(array $settings): self + { + return new RedirectConfiguration( + ($settings['redirectMode'] ?? ''), + (string)($settings['redirectFirstMethod'] ?? ''), + (int)($settings['redirectPageLogin'] ?? 0), + (string)($settings['domains'] ?? ''), + (int)($settings['redirectPageLoginError'] ?? 0), + (int)($settings['redirectPageLogout'] ?? 0) + ); + } +} diff --git a/Classes/Controller/LoginController.php b/Classes/Controller/LoginController.php new file mode 100644 index 0000000..bddb13f --- /dev/null +++ b/Classes/Controller/LoginController.php @@ -0,0 +1,248 @@ +loginType = (string)($this->request->getParsedBody()['logintype'] ?? $this->request->getQueryParams()['logintype'] ?? ''); + $this->configuration = RedirectConfiguration::fromSettings($this->settings); + + if ($this->isLoginOrLogoutInProgress() && !$this->isRedirectDisabled()) { + $this->redirectUrl = $this->redirectHandler->processRedirect( + $this->request, + $this->loginType, + $this->configuration, + $this->request->hasArgument('redirectReferrer') ? $this->request->getArgument('redirectReferrer') : '' + ); + } + } + + /** + * Show login form + */ + public function loginAction(): ResponseInterface + { + if ($this->isLogoutSuccessful()) { + $this->eventDispatcher->dispatch(new LogoutConfirmedEvent($this, $this->view, $this->request)); + } elseif ($this->hasLoginErrorOccurred()) { + $this->eventDispatcher->dispatch(new LoginErrorOccurredEvent($this->request)); + } + + if (($forwardResponse = $this->handleLoginForwards()) !== null) { + return $forwardResponse; + } + if (($redirectResponse = $this->handleRedirect()) !== null) { + return $redirectResponse; + } + + $this->eventDispatcher->dispatch(new ModifyLoginFormViewEvent($this->view, $this->request)); + + $storagePageIds = ($GLOBALS['TYPO3_CONF_VARS']['FE']['checkFeUserPid'] ?? false) + ? $this->pageRepository->getPageIdsRecursive(GeneralUtility::intExplode(',', (string)($this->settings['pages'] ?? ''), true), (int)($this->settings['recursive'] ?? 0)) + : []; + + $this->view->assignMultiple( + [ + 'messageKey' => $this->getStatusMessageKey(), + 'permaloginStatus' => $this->getPermaloginStatus(), + 'redirectURL' => $this->redirectHandler->getLoginFormRedirectUrl($this->request, $this->configuration, $this->isRedirectDisabled()), + 'redirectReferrer' => $this->request->hasArgument('redirectReferrer') ? (string)$this->request->getArgument('redirectReferrer') : '', + 'referer' => $this->redirectHandler->getReferrerForLoginForm($this->request, $this->settings), + 'noRedirect' => $this->isRedirectDisabled(), + 'requestToken' => RequestToken::create('core/user-auth/fe') + ->withMergedParams(['pid' => implode(',', $storagePageIds)]), + ] + ); + + return $this->htmlResponse(); + } + + /** + * User overview for logged in users + */ + public function overviewAction(bool $showLoginMessage = false): ResponseInterface + { + if (!$this->context->getAspect('frontend.user')->isLoggedIn()) { + return new ForwardResponse('login'); + } + $this->eventDispatcher->dispatch(new LoginConfirmedEvent($this, $this->view, $this->request)); + if (($redirectResponse = $this->handleRedirect()) !== null) { + return $redirectResponse; + } + $this->view->assignMultiple( + [ + 'user' => $this->request->getAttribute('frontend.user')->user, + 'showLoginMessage' => $showLoginMessage, + ] + ); + return $this->htmlResponse(); + } + + /** + * Show logout form. Note, that this action should never process any redirects. + */ + public function logoutAction(): ResponseInterface + { + $this->view->assignMultiple( + [ + 'user' => $this->request->getAttribute('frontend.user')->user, + 'noRedirect' => $this->isRedirectDisabled(), + ] + ); + return $this->htmlResponse(); + } + + /** + * Handles the redirect when $this->redirectUrl is not empty + */ + protected function handleRedirect(): ?ResponseInterface + { + if ($this->redirectUrl !== '') { + $event = new BeforeRedirectEvent($this->loginType, $this->redirectUrl, $this->request); + $this->eventDispatcher->dispatch($event); + if ($event->getRedirectUrl() !== '') { + return $this->redirectToUri($event->getRedirectUrl()); + } + } + return null; + } + + /** + * Handle forwards to overview and logout actions from login action + */ + protected function handleLoginForwards(): ?ResponseInterface + { + if ($this->shouldRedirectToOverview()) { + return (new ForwardResponse('overview'))->withArguments(['showLoginMessage' => true]); + } + if ($this->context->getAspect('frontend.user')->isLoggedIn()) { + return new ForwardResponse('logout'); + } + return null; + } + + /** + * The permanent login checkbox should only be shown if permalogin is not deactivated (-1), + * not forced to be always active (2) and lifetime is greater than 0 + */ + protected function getPermaloginStatus(): int + { + $permaLogin = (int)$GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin']; + + return $this->isPermaloginDisabled($permaLogin) ? -1 : $permaLogin; + } + + protected function isPermaloginDisabled(int $permaLogin): bool + { + return $permaLogin > 1 + || (int)($this->settings['showPermaLogin'] ?? 0) === 0 + || $GLOBALS['TYPO3_CONF_VARS']['FE']['lifetime'] === 0; + } + + /** + * Redirect to overview on login successful and setting showLogoutFormAfterLogin disabled + */ + protected function shouldRedirectToOverview(): bool + { + return $this->context->getAspect('frontend.user')->isLoggedIn() + && (LoginType::tryFrom($this->loginType) === LoginType::LOGIN) + && !($this->settings['showLogoutFormAfterLogin'] ?? 0); + } + + /** + * Return message key based on user login status + */ + protected function getStatusMessageKey(): string + { + $messageKey = self::MESSAGEKEY_DEFAULT; + if ($this->hasLoginErrorOccurred()) { + $messageKey = self::MESSAGEKEY_ERROR; + } elseif (LoginType::tryFrom($this->loginType) === LoginType::LOGOUT) { + $messageKey = self::MESSAGEKEY_LOGOUT; + } + + return $messageKey; + } + + protected function isLoginOrLogoutInProgress(): bool + { + $type = LoginType::tryFrom($this->loginType); + return $type === LoginType::LOGIN || $type === LoginType::LOGOUT; + } + + /** + * Is redirect disabled by setting or noredirect GET/POST parameter + */ + protected function isRedirectDisabled(): bool + { + return + (int)($this->request->getParsedBody()['noredirect'] ?? $this->request->getQueryParams()['noredirect'] ?? 0) === 1 + || ($this->settings['noredirect'] ?? false) + || ($this->settings['redirectDisable'] ?? false); + } + + protected function isLogoutSuccessful(): bool + { + return LoginType::tryFrom($this->loginType) === LoginType::LOGOUT && !$this->context->getAspect('frontend.user')->isLoggedIn(); + } + + protected function hasLoginErrorOccurred(): bool + { + return LoginType::tryFrom($this->loginType) === LoginType::LOGIN && !$this->context->getAspect('frontend.user')->isLoggedIn(); + } +} diff --git a/Classes/Controller/PasswordRecoveryController.php b/Classes/Controller/PasswordRecoveryController.php new file mode 100644 index 0000000..c4b299b --- /dev/null +++ b/Classes/Controller/PasswordRecoveryController.php @@ -0,0 +1,314 @@ +htmlResponse(); + } + + $storagePageIds = ($GLOBALS['TYPO3_CONF_VARS']['FE']['checkFeUserPid'] ?? false) + ? $this->pageRepository->getPageIdsRecursive(GeneralUtility::intExplode(',', (string)($this->settings['pages'] ?? ''), true), (int)($this->settings['recursive'] ?? 0)) + : []; + + $userData = $this->userRepository->findUserByUsernameOrEmailOnPages($userIdentifier, $storagePageIds); + + if ($userData + && GeneralUtility::validEmail($userData['email']) + && !$this->hasExceededMaximumAttemptsForReset($userData['email']) + ) { + $hash = $this->recoveryConfiguration->getForgotHash(); + $this->userRepository->updateForgotHashForUserByUid($userData['uid'], $this->hashService->hmac($hash, self::class, HashAlgo::SHA3_256)); + $this->recoveryService->sendRecoveryEmail($this->request, $userData, $hash); + } + + // Prevent time based information disclosure by waiting a random time before sending a response. This prevents + // that the response time can be an indicator if the used username or email exists or not. Wait a random time + // between 200 milliseconds and 3 seconds. + usleep(random_int(200000, 3000000)); + + // Always show the default message and never notify about a potential rate limit, because this would reveal, + // that a given user identifier is actually valid. + $this->addFlashMessage($this->getTranslation('forgot_reset_message_emailSent')); + + return $this->redirect('login', 'Login', 'felogin'); + } + + protected function hasExceededMaximumAttemptsForReset(string $email): bool + { + $limiter = $this->rateLimiterFactory->create($email); + $limit = $limiter->consume(); + return !$limit->isAccepted(); + } + + /** + * Validate the hash argument and make sure that: + * + * - it is in the expected format + * - it is not expired + * - a fe_user with the given hash exists + * + * If one of the checks fail, a redirect response to the recoveryAction() is returned + */ + protected function validateHashArgument(): ?ResponseInterface + { + $hash = $this->request->hasArgument('hash') ? $this->request->getArgument('hash') : ''; + $hash = is_string($hash) ? $hash : ''; + + if (!$this->validateHashFormat($hash)) { + return $this->redirect('recovery', 'PasswordRecovery', 'felogin'); + } + + $timestamp = (int)GeneralUtility::trimExplode('|', $hash)[0]; + $currentTimestamp = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('date', 'timestamp'); + + // timestamp is expired or hash can not be assigned to a user + if ($currentTimestamp > $timestamp || !$this->userRepository->existsUserWithHash($this->hashService->hmac($hash, self::class, HashAlgo::SHA3_256))) { + /** @var ExtbaseRequestParameters $extbaseRequestParameters */ + $extbaseRequestParameters = clone $this->request->getAttribute('extbase'); + $originalResult = $extbaseRequestParameters->getOriginalRequestMappingResults(); + $originalResult->addError(new Error($this->getTranslation('change_password_notvalid_message'), 1554994253)); + $extbaseRequestParameters->setOriginalRequestMappingResults($originalResult); + $this->request = $this->request->withAttribute('extbase', $extbaseRequestParameters); + + return (new ForwardResponse('recovery')) + ->withControllerName('PasswordRecovery') + ->withExtensionName('felogin') + ->withArgumentsValidationResult($originalResult); + } + + return null; + } + + /** + * Show the change password form if a valid hash is available. + */ + public function showChangePasswordAction(string $hash = ''): ResponseInterface + { + // Validate hash (lifetime, format and fe_user with hash persistence) + if (($response = $this->validateHashArgument()) instanceof ResponseInterface) { + return $response; + } + + $this->view->assignMultiple([ + 'hash' => $hash, + 'passwordRequirements' => $this->getPasswordPolicyValidator()->getRequirements(), + ]); + + return $this->htmlResponse(); + } + + /** + * Validates the hash argument, the entered password and passwordRepeat values. If one of the values is considered + * as invalid, a response object with validation errors in the mapping results is returned. + * + * @throws NoSuchArgumentException + */ + public function validateHashAndPasswords() + { + // Validate hash (lifetime, format and fe_user with hash persistence) + if (($response = $this->validateHashArgument()) instanceof ResponseInterface) { + return $response; + } + + // Exit early if newPass or newPassRepeat is not set. + /** @var ExtbaseRequestParameters $extbaseRequestParameters */ + $extbaseRequestParameters = clone $this->request->getAttribute('extbase'); + $originalResult = $extbaseRequestParameters->getOriginalRequestMappingResults(); + $argumentsExist = $this->request->hasArgument('newPass') && $this->request->hasArgument('newPassRepeat'); + $argumentsEmpty = empty($this->request->getArgument('newPass')) || empty($this->request->getArgument('newPassRepeat')); + + if (!$argumentsExist || $argumentsEmpty) { + $originalResult->addError(new Error( + $this->getTranslation('empty_password_and_password_repeat'), + 1554971665 + )); + + return (new ForwardResponse('showChangePassword')) + ->withControllerName('PasswordRecovery') + ->withExtensionName('felogin') + ->withArguments(['hash' => $this->request->getArgument('hash')]) + ->withArgumentsValidationResult($originalResult); + } + + $this->validateNewPassword($originalResult); + + // if an error exists, forward with all messages to the change password form + if ($originalResult->hasErrors()) { + return (new ForwardResponse('showChangePassword')) + ->withControllerName('PasswordRecovery') + ->withExtensionName('felogin') + ->withArguments(['hash' => $this->request->getArgument('hash')]) + ->withArgumentsValidationResult($originalResult); + } + } + + /** + * Change actual password. Hash $newPass and update the user with the corresponding $hash. + * + * @throws AspectNotFoundException + * @throws InvalidPasswordHashException + */ + public function changePasswordAction(string $newPass, string $hash): ResponseInterface + { + if (($response = $this->validateHashAndPasswords()) instanceof ResponseInterface) { + return $response; + } + + $hashedPassword = GeneralUtility::makeInstance(PasswordHashFactory::class) + ->getDefaultHashInstance('FE') + ->getHashedPassword($newPass); + + $hmac = $this->hashService->hmac($hash, self::class, HashAlgo::SHA3_256); + $user = $this->userRepository->findOneByForgotPasswordHash($hmac); + + $event = new PasswordChangeEvent($user, $hashedPassword, $newPass, $this->request); + $this->eventDispatcher->dispatch($event); + + $this->userRepository->updatePasswordAndInvalidateHash($hmac, $hashedPassword); + $this->invalidateUserSessions($user['uid']); + + $this->addFlashMessage($this->getTranslation('change_password_done_message')); + + return $this->redirect('login', 'Login', 'felogin', ['redirectReferrer' => 'off']); + } + + /** + * @throws NoSuchArgumentException + */ + protected function validateNewPassword(Result $originalResult): void + { + $newPass = $this->request->getArgument('newPass'); + + // make sure the user entered the password twice + if ($newPass !== $this->request->getArgument('newPassRepeat')) { + $originalResult->addError(new Error($this->getTranslation('password_must_match_repeated'), 1554912163)); + } + + $hash = $this->request->getArgument('hash'); + $userData = $this->userRepository->findOneByForgotPasswordHash($this->hashService->hmac($hash, self::class, HashAlgo::SHA3_256)); + + // Validate against password policy + $passwordPolicyValidator = $this->getPasswordPolicyValidator(); + $contextData = new ContextData( + loginMode: 'FE', + currentPasswordHash: $userData['password'] + ); + $contextData->setData('currentUsername', $userData['username']); + $contextData->setData('currentFirstname', $userData['first_name']); + $contextData->setData('currentLastname', $userData['last_name']); + $event = $this->eventDispatcher->dispatch( + new EnrichPasswordValidationContextDataEvent( + $contextData, + $userData, + self::class + ) + ); + $contextData = $event->getContextData(); + + if (!$passwordPolicyValidator->isValidPassword($newPass, $contextData)) { + foreach ($passwordPolicyValidator->getValidationErrors() as $validationError) { + $validationResult = new Result(); + $validationResult->addError(new Error($validationError, 1667647475)); + $originalResult->merge($validationResult); + } + } + } + + /** + * Wrapper to mock LocalizationUtility::translate + */ + protected function getTranslation(string $key): string + { + return (string)LocalizationUtility::translate($key, 'felogin'); + } + + /** + * Validates that $hash is in the expected format (timestamp|forgot_hash) + */ + protected function validateHashFormat(string $hash): bool + { + return !empty($hash) && strpos($hash, '|') === 10; + } + + /** + * Invalidate all frontend user sessions by given user id + */ + protected function invalidateUserSessions(int $userId): void + { + $sessionManager = GeneralUtility::makeInstance(SessionManager::class); + $sessionBackend = $sessionManager->getSessionBackend('FE'); + $sessionManager->invalidateAllSessionsByUserId($sessionBackend, $userId); + } + + protected function getPasswordPolicyValidator(): PasswordPolicyValidator + { + $passwordPolicy = $GLOBALS['TYPO3_CONF_VARS']['FE']['passwordPolicy'] ?? 'default'; + return GeneralUtility::makeInstance( + PasswordPolicyValidator::class, + PasswordPolicyAction::UPDATE_USER_PASSWORD, + is_string($passwordPolicy) ? $passwordPolicy : '' + ); + } +} diff --git a/Classes/Domain/Repository/FrontendUserGroupRepository.php b/Classes/Domain/Repository/FrontendUserGroupRepository.php new file mode 100644 index 0000000..f8060d9 --- /dev/null +++ b/Classes/Domain/Repository/FrontendUserGroupRepository.php @@ -0,0 +1,50 @@ +connection = $connectionPool->getConnectionForTable('fe_groups'); + } + + public function findRedirectPageIdByGroupId(int $groupId): ?int + { + $queryBuilder = $this->connection->createQueryBuilder(); + $queryBuilder->getRestrictions()->removeAll(); + $query = $queryBuilder + ->select('felogin_redirectPid') + ->from('fe_groups') + ->where( + $queryBuilder->expr()->neq('felogin_redirectPid', $this->connection->quote('')), + $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($groupId, Connection::PARAM_INT)) + ) + ->setMaxResults(1); + $column = $query->executeQuery()->fetchOne(); + return $column === false ? null : (int)$column; + } +} diff --git a/Classes/Domain/Repository/FrontendUserRepository.php b/Classes/Domain/Repository/FrontendUserRepository.php new file mode 100644 index 0000000..02d3cd9 --- /dev/null +++ b/Classes/Domain/Repository/FrontendUserRepository.php @@ -0,0 +1,141 @@ +connection = $connectionPool->getConnectionForTable('fe_users'); + } + + /** + * Change the password for a user based on forgot password hash. + */ + public function updatePasswordAndInvalidateHash(string $forgotPasswordHash, string $hashedPassword): void + { + $queryBuilder = $this->connection->createQueryBuilder(); + $currentTimestamp = $this->context->getPropertyFromAspect('date', 'timestamp'); + $query = $queryBuilder + ->update('fe_users') + ->set('password', $hashedPassword) + ->set('felogin_forgotHash', $this->connection->quote(''), false) + ->set('tstamp', $currentTimestamp) + ->where($queryBuilder->expr()->eq('felogin_forgotHash', $queryBuilder->createNamedParameter($forgotPasswordHash))); + $query->executeStatement(); + } + + /** + * Returns true if a user exists with hash as `felogin_forgothash`, otherwise false. + */ + public function existsUserWithHash(string $hash): bool + { + $queryBuilder = $this->connection->createQueryBuilder(); + $query = $queryBuilder + ->count('uid') + ->from('fe_users') + ->where($queryBuilder->expr()->eq('felogin_forgotHash', $queryBuilder->createNamedParameter($hash))); + return (bool)$query->executeQuery()->fetchOne(); + } + + /** + * Sets forgot hash for passed user uid. + */ + public function updateForgotHashForUserByUid(int $uid, string $hash): void + { + $queryBuilder = $this->connection->createQueryBuilder(); + $query = $queryBuilder + ->update('fe_users') + ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, $this->connection::PARAM_INT))) + ->set('felogin_forgotHash', $hash); + $query->executeStatement(); + } + + /** + * Fetches an array with all columns (except the password) from the fe_users table for the given username or + * email on the given pages. Returns null, if user was not found or if user has no email address set. + */ + public function findUserByUsernameOrEmailOnPages(string $usernameOrEmail, array $pages = []): ?array + { + if ($usernameOrEmail === '') { + return null; + } + $queryBuilder = $this->connection->createQueryBuilder(); + $query = $queryBuilder + ->select('*') + ->from('fe_users') + ->where( + $queryBuilder->expr()->or( + $queryBuilder->expr()->eq('username', $queryBuilder->createNamedParameter($usernameOrEmail)), + $queryBuilder->expr()->eq('email', $queryBuilder->createNamedParameter($usernameOrEmail)), + ), + $queryBuilder->expr()->neq('email', $this->connection->quote('')), + ); + if (!empty($pages)) { + // respect storage pid + $query->andWhere($queryBuilder->expr()->in('pid', $pages)); + } + $result = $query->executeQuery()->fetchAssociative() ?: null; + if ($result) { + unset($result['password']); + } + return $result; + } + + public function findOneByForgotPasswordHash(string $hash): ?array + { + if ($hash === '') { + return null; + } + $queryBuilder = $this->connection->createQueryBuilder(); + $query = $queryBuilder + ->select('*') + ->from('fe_users') + ->where($queryBuilder->expr()->eq('felogin_forgotHash', $queryBuilder->createNamedParameter($hash))) + ->setMaxResults(1); + $row = $query->executeQuery()->fetchAssociative(); + return is_array($row) ? $row : null; + } + + public function findRedirectIdPageByUserId(int $uid): ?int + { + $queryBuilder = $this->connection->createQueryBuilder(); + $queryBuilder->getRestrictions()->removeAll(); + $query = $queryBuilder + ->select('felogin_redirectPid') + ->from('fe_users') + ->where( + $queryBuilder->expr()->neq('felogin_redirectPid', $this->connection->quote('')), + $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT)) + ) + ->setMaxResults(1); + $column = $query->executeQuery()->fetchOne(); + return $column === false ? null : (int)$column; + } +} diff --git a/Classes/Event/AbstractConfirmedEvent.php b/Classes/Event/AbstractConfirmedEvent.php new file mode 100644 index 0000000..3b94ead --- /dev/null +++ b/Classes/Event/AbstractConfirmedEvent.php @@ -0,0 +1,50 @@ +controller; + } + + public function getView(): ViewInterface + { + return $this->view; + } + + public function getRequest(): ServerRequestInterface + { + return $this->request; + } +} diff --git a/Classes/Event/BeforeRedirectEvent.php b/Classes/Event/BeforeRedirectEvent.php new file mode 100644 index 0000000..71634d4 --- /dev/null +++ b/Classes/Event/BeforeRedirectEvent.php @@ -0,0 +1,54 @@ +loginType; + } + + public function getRedirectUrl(): string + { + return $this->redirectUrl; + } + + public function setRedirectUrl(string $redirectUrl): void + { + $this->redirectUrl = $redirectUrl; + } + + public function getRequest(): ServerRequestInterface + { + return $this->request; + } +} diff --git a/Classes/Event/LoginConfirmedEvent.php b/Classes/Event/LoginConfirmedEvent.php new file mode 100644 index 0000000..bf4cdd2 --- /dev/null +++ b/Classes/Event/LoginConfirmedEvent.php @@ -0,0 +1,24 @@ +request; + } +} diff --git a/Classes/Event/LogoutConfirmedEvent.php b/Classes/Event/LogoutConfirmedEvent.php new file mode 100644 index 0000000..fe404a8 --- /dev/null +++ b/Classes/Event/LogoutConfirmedEvent.php @@ -0,0 +1,24 @@ +view; + } + + public function getRequest(): ServerRequestInterface + { + return $this->request; + } +} diff --git a/Classes/Event/ModifyRedirectUrlValidationResultEvent.php b/Classes/Event/ModifyRedirectUrlValidationResultEvent.php new file mode 100644 index 0000000..cc9429f --- /dev/null +++ b/Classes/Event/ModifyRedirectUrlValidationResultEvent.php @@ -0,0 +1,52 @@ +redirectUrl; + } + + public function getValidationResult(): bool + { + return $this->validationResult; + } + + public function setValidationResult(bool $validationResult): void + { + $this->validationResult = $validationResult; + } + + public function getRequest(): ServerRequestInterface + { + return $this->request; + } +} diff --git a/Classes/Event/PasswordChangeEvent.php b/Classes/Event/PasswordChangeEvent.php new file mode 100644 index 0000000..fd53c75 --- /dev/null +++ b/Classes/Event/PasswordChangeEvent.php @@ -0,0 +1,53 @@ +user; + } + + public function getHashedPassword(): string + { + return $this->passwordHash; + } + + public function getRawPassword(): string + { + return $this->rawPassword; + } + + public function getRequest(): ServerRequestInterface + { + return $this->request; + } +} diff --git a/Classes/Event/ProcessRequestTokenListener.php b/Classes/Event/ProcessRequestTokenListener.php new file mode 100644 index 0000000..48e1b14 --- /dev/null +++ b/Classes/Event/ProcessRequestTokenListener.php @@ -0,0 +1,43 @@ +getUser(); + $requestToken = $event->getRequestToken(); + if (!$user instanceof FrontendUserAuthentication || !$requestToken instanceof RequestToken) { + return; + } + $pidParam = (string)($requestToken->params['pid'] ?? ''); + if ($user->checkPid) { + $user->checkPid_value = $pidParam; + } + } +} diff --git a/Classes/Event/SendRecoveryEmailEvent.php b/Classes/Event/SendRecoveryEmailEvent.php new file mode 100644 index 0000000..192e5ca --- /dev/null +++ b/Classes/Event/SendRecoveryEmailEvent.php @@ -0,0 +1,41 @@ +user; + } + + public function getEmail(): FluidEmail + { + return $this->email; + } +} diff --git a/Classes/Redirect/RedirectHandler.php b/Classes/Redirect/RedirectHandler.php new file mode 100644 index 0000000..6185cfb --- /dev/null +++ b/Classes/Redirect/RedirectHandler.php @@ -0,0 +1,249 @@ +userIsLoggedIn = (bool)$context->getPropertyFromAspect('frontend.user', 'isLoggedIn'); + } + + /** + * Process redirect modes. This method searches for a redirect url using all configured modes and returns it. + */ + public function processRedirect(RequestInterface $request, string $loginType, RedirectConfiguration $configuration, string $redirectModeReferrer): string + { + if ($this->isUserLoginFailedAndLoginErrorActive($configuration->getModes(), $loginType)) { + return $this->redirectModeHandler->redirectModeLoginError($request, $configuration->getPageOnLoginError()); + } + + $redirectUrlList = []; + foreach ($configuration->getModes() as $redirectMode) { + $redirectUrl = ''; + + $type = LoginType::tryFrom($loginType); + if ($type === LoginType::LOGIN) { + $redirectUrl = $this->handleSuccessfulLogin($request, $redirectMode, $configuration->getPageOnLogin(), $configuration->getDomains(), $redirectModeReferrer); + } elseif ($type === LoginType::LOGOUT) { + $redirectUrl = $this->handleSuccessfulLogout($request, $redirectMode, $configuration->getPageOnLogout()); + } + + if ($redirectUrl !== '') { + $redirectUrlList[] = $redirectUrl; + } + } + + return $this->fetchReturnUrlFromList($redirectUrlList, $configuration->getFirstMode()); + } + + /** + * Get alternative logout form redirect url if logout and page not accessible + */ + protected function getLogoutRedirectUrl(RequestInterface $request, array $redirectModes, int $redirectPageLogout = 0): string + { + if ($this->userIsLoggedIn && $this->isRedirectModeActive($redirectModes, RedirectMode::LOGOUT)) { + return $this->redirectModeHandler->redirectModeLogout($request, $redirectPageLogout); + } + return $this->getGetpostRedirectUrl($request, $redirectModes); + } + + /** + * Is used for alternative redirect urls on redirect mode "getpost" + */ + protected function getGetpostRedirectUrl(RequestInterface $request, array $redirectModes): string + { + return $this->isRedirectModeActive($redirectModes, RedirectMode::GETPOST) + ? $this->getRedirectUrlRequestParam($request) + : ''; + } + + /** + * Handle redirect mode logout + */ + protected function handleSuccessfulLogout(RequestInterface $request, string $redirectMode, int $redirectPageLogout): string + { + if ($redirectMode === RedirectMode::LOGOUT) { + return $this->redirectModeHandler->redirectModeLogout($request, $redirectPageLogout); + } + return ''; + } + + /** + * Base on setting redirectFirstMethod get first or last entry from redirect url list. + */ + protected function fetchReturnUrlFromList(array $redirectUrlList, string $redirectFirstMethod): string + { + if (count($redirectUrlList) === 0) { + return ''; + } + + // Remove empty values, but keep "0" as value (that's why "strlen" is used as second parameter) + $redirectUrlList = array_filter($redirectUrlList, static function (string $value): bool { + return strlen($value) > 0; + }); + + return $redirectFirstMethod + ? array_shift($redirectUrlList) + : array_pop($redirectUrlList); + } + + /** + * Generate redirect_url for case that the user was successfully logged in + */ + protected function handleSuccessfulLogin(RequestInterface $request, string $redirectMode, int $redirectPageLogin = 0, string $domains = '', string $redirectModeReferrer = ''): string + { + if (!$this->userIsLoggedIn) { + return ''; + } + + // Logintype is needed because the login-page wouldn't be accessible anymore after a login (would always redirect) + switch ($redirectMode) { + case RedirectMode::GROUP_LOGIN: + $redirectUrl = $this->redirectModeHandler->redirectModeGroupLogin($request); + break; + case RedirectMode::USER_LOGIN: + $redirectUrl = $this->redirectModeHandler->redirectModeUserLogin($request); + break; + case RedirectMode::LOGIN: + $redirectUrl = $this->redirectModeHandler->redirectModeLogin($request, $redirectPageLogin); + break; + case RedirectMode::GETPOST: + $redirectUrl = $this->getRedirectUrlRequestParam($request); + break; + case RedirectMode::REFERRER: + $redirectUrl = $this->redirectModeHandler->redirectModeReferrer($request, $redirectModeReferrer); + break; + case RedirectMode::REFERRER_DOMAINS: + $redirectUrl = $this->redirectModeHandler->redirectModeReferrerDomains($request, $domains, $redirectModeReferrer); + break; + default: + $redirectUrl = ''; + } + + return $redirectUrl; + } + + protected function isUserLoginFailedAndLoginErrorActive(array $redirectModes, string $loginType): bool + { + return LoginType::tryFrom($loginType) === LoginType::LOGIN + && !$this->userIsLoggedIn + && $this->isRedirectModeActive($redirectModes, RedirectMode::LOGIN_ERROR); + } + + protected function isRedirectModeActive(array $redirectModes, string $mode): bool + { + return in_array($mode, $redirectModes, true); + } + + /** + * Returns the redirect Url that should be used in login form template for GET/POST redirect mode + */ + public function getLoginFormRedirectUrl( + RequestInterface $request, + RedirectConfiguration $configuration, + bool $redirectDisabled + ): string { + if (!$redirectDisabled) { + return $this->getGetpostRedirectUrl($request, $configuration->getModes()); + } + return ''; + } + + /** + * Determines the `referer` variable used in the login form for loginMode=referer depending on the + * following evaluation order: + * + * - HTTP POST parameter `referer` + * - HTTP GET parameter `referer` + * - HTTP_REFERER + * - URL of initiating request in case plugin has been called via sub-request + * + * The evaluated `referer` is only returned, if it is considered valid. + */ + public function getReferrerForLoginForm(RequestInterface $request, array $settings): string + { + // Early return, if redirectMode is not configured to respect the referrer + if (!$this->isReferrerRedirectEnabled($settings)) { + return ''; + } + + // Early return, if redirectReferrer is not enabled in current context (e.g., after a password reset) + if (($request->getQueryParams()['tx_felogin_login']['redirectReferrer'] ?? '') === 'off') { + return ''; + } + + $referrer = (string)( + $request->getParsedBody()['referer'] + ?? $request->getQueryParams()['referer'] + ?? $request->getServerParams()['HTTP_REFERER'] + ?? '' + ); + + // If the current request was initiated via sub-request, we use the URI of the original request as referrer + if ($originalRequest = $request->getAttribute('originalRequest', false)) { + $referrer = (string)$originalRequest->getUri(); + } + + if ($this->redirectUrlValidator->isValid($request, $referrer)) { + return $referrer; + } + + return ''; + } + + /** + * Returns whether redirect based on the referrer is enabled + */ + protected function isReferrerRedirectEnabled(array $settings): bool + { + $referrerRedirectModes = [RedirectMode::REFERRER, RedirectMode::REFERRER_DOMAINS]; + $configuredRedirectModes = GeneralUtility::trimExplode(',', $settings['redirectMode'] ?? ''); + return count(array_intersect($configuredRedirectModes, $referrerRedirectModes)) > 0; + } + + /** + * Returns validated redirect url contained in request param return_url or redirect_url + */ + private function getRedirectUrlRequestParam(RequestInterface $request): string + { + // If config.typolinkLinkAccessRestrictedPages is set, the var is return_url + $returnUrlFromRequest = (string)($request->getParsedBody()['return_url'] ?? $request->getQueryParams()['return_url'] ?? null); + $redirectUrlFromRequest = (string)($request->getParsedBody()['redirect_url'] ?? $request->getQueryParams()['redirect_url'] ?? null); + $redirectUrl = $returnUrlFromRequest ?: $redirectUrlFromRequest; + + return $this->redirectUrlValidator->isValid($request, $redirectUrl) ? $redirectUrl : ''; + } +} diff --git a/Classes/Redirect/RedirectMode.php b/Classes/Redirect/RedirectMode.php new file mode 100644 index 0000000..8be65f5 --- /dev/null +++ b/Classes/Redirect/RedirectMode.php @@ -0,0 +1,35 @@ +getAttribute('frontend.user')->userGroups; + if (empty($groups)) { + return ''; + } + $groupUids = array_keys($groups); + // Take the first group with a redirect page + foreach ($groupUids as $groupUid) { + $redirectPageId = (int)$this->frontendUserGroupRepository + ->findRedirectPageIdByGroupId($groupUid); + if ($redirectPageId > 0) { + return $this->buildUriForPageUid($request, $redirectPageId); + } + } + return ''; + } + + /** + * Handle redirect mode userLogin + */ + public function redirectModeUserLogin(RequestInterface $request): string + { + $userUid = (int)$request->getAttribute('frontend.user')->user['uid']; + $redirectPageId = $this->frontendUserRepository->findRedirectIdPageByUserId($userUid); + if ($redirectPageId === null) { + return ''; + } + return $this->buildUriForPageUid($request, $redirectPageId); + } + + /** + * Handle redirect mode login + */ + public function redirectModeLogin(RequestInterface $request, int $redirectPageLogin): string + { + $redirectUrl = ''; + if ($redirectPageLogin !== 0) { + $redirectUrl = $this->buildUriForPageUid($request, $redirectPageLogin); + } + return $redirectUrl; + } + + /** + * Handle redirect mode referrer + */ + public function redirectModeReferrer(RequestInterface $request, string $redirectReferrer): string + { + $redirectUrl = ''; + if ($redirectReferrer !== 'off') { + // Avoid forced logout, when trying to login immediately after a logout + $redirectUrl = preg_replace('/[&?]logintype=[a-z]+/', '', $this->getReferrer($request)); + } + return $redirectUrl ?? ''; + } + + /** + * Handle redirect mode refererDomains + */ + public function redirectModeReferrerDomains(RequestInterface $request, string $domains, string $redirectReferrer): string + { + $redirectUrl = ''; + if ($redirectReferrer !== '') { + return ''; + } + + // Auto redirect. + // Feature to redirect to the page where the user came from (HTTP_REFERER). + // Allowed domains to redirect to, can be configured with plugin.tx_felogin_login.domains + // also avoid redirect when logging in after changing password + if ($domains) { + $url = $this->getReferrer($request); + // Is referring url allowed to redirect? + $match = []; + if (preg_match('#^https?://([[:alnum:].-]+)/#', $url, $match)) { + $redirectDomain = $match[1]; + $found = false; + foreach (GeneralUtility::trimExplode(',', $domains, true) as $domain) { + if (preg_match('/(?:^|\\.)' . preg_quote($domain, '/') . '$/', $redirectDomain)) { + $found = true; + break; + } + } + if (!$found) { + $url = ''; + } + } + // Avoid forced logout, when trying to login immediately after a logout + if ($url) { + $redirectUrl = preg_replace('/[&?]logintype=[a-z]+/', '', $url); + } + } + + return $redirectUrl ?? ''; + } + + /** + * Handle redirect mode loginError after login-error + */ + public function redirectModeLoginError(RequestInterface $request, int $redirectPageLoginError = 0): string + { + $redirectUrl = ''; + if ($redirectPageLoginError > 0) { + $redirectUrl = $this->buildUriForPageUid($request, $redirectPageLoginError); + } + return $redirectUrl; + } + + /** + * Handle redirect mode logout + */ + public function redirectModeLogout(RequestInterface $request, int $redirectPageLogout): string + { + $redirectUrl = ''; + if ($redirectPageLogout > 0) { + $redirectUrl = $this->buildUriForPageUid($request, $redirectPageLogout); + } + return $redirectUrl; + } + + protected function buildUriForPageUid(RequestInterface $request, int $pageUid): string + { + $this->uriBuilder->reset(); + $this->uriBuilder->setRequest($request); + $this->uriBuilder->setTargetPageUid($pageUid); + return $this->uriBuilder->build(); + } + + protected function getReferrer(RequestInterface $request): string + { + $referrer = ''; + $requestReferrer = (string)($request->getParsedBody()['referer'] ?? $request->getQueryParams()['referer'] ?? ''); + if ($this->redirectUrlValidator->isValid($request, $requestReferrer)) { + $referrer = $requestReferrer; + } + return $referrer; + } +} diff --git a/Classes/Service/RecoveryService.php b/Classes/Service/RecoveryService.php new file mode 100644 index 0000000..fd59b6a --- /dev/null +++ b/Classes/Service/RecoveryService.php @@ -0,0 +1,132 @@ +settings = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS); + } + + /** + * Sends an email with an absolute link including the given forgot hash to the passed user + * with instructions to recover the account. + * + * @throws TransportExceptionInterface + */ + public function sendRecoveryEmail(RequestInterface $request, array $userData, string $hash): void + { + $receiver = new Address($userData['email'], $this->getReceiverName($userData)); + $email = $this->prepareMail($request, $receiver, $hash, $userData); + + $event = new SendRecoveryEmailEvent($email, $userData); + $this->eventDispatcher->dispatch($event); + $this->mailer->send($event->getEmail()); + } + + /** + * Get display name from values. Fallback to username if none of the "_name" fields is set. + */ + protected function getReceiverName(array $userInformation): string + { + $displayName = trim( + sprintf( + '%s%s%s', + $userInformation['first_name'], + $userInformation['middle_name'] ? " {$userInformation['middle_name']}" : '', + $userInformation['last_name'] ? " {$userInformation['last_name']}" : '' + ) + ); + + return $displayName ? $displayName . ' (' . $userInformation['username'] . ')' : $userInformation['username']; + } + + /** + * Create email object from configuration. + */ + protected function prepareMail(RequestInterface $request, Address $receiver, string $hash, array $userData): FluidEmail + { + $url = $this->uriBuilder + ->reset() + ->setRequest($request) + ->setCreateAbsoluteUri(true) + ->uriFor( + 'showChangePassword', + ['hash' => $hash], + 'PasswordRecovery', + 'felogin', + 'Login' + ); + + $variables = [ + 'receiverName' => $receiver->getName(), + 'userData' => $userData, + 'url' => $url, + 'validUntil' => date($this->settings['dateFormat'] ?? 'Y-m-d H:i', $this->recoveryConfiguration->getLifeTimeTimestamp()), + ]; + + $mail = $this->templatedEmailFactory->createWithOverrides( + $this->settings['email']['templateRootPaths'] ?? [], + $this->settings['email']['layoutRootPaths'] ?? [], + $this->settings['email']['partialRootPaths'] ?? [], + $request, + ); + $mail->subject($this->getEmailSubject()) + ->from($this->recoveryConfiguration->getSender()) + ->to($receiver) + ->assignMultiple($variables) + ->setTemplate($this->recoveryConfiguration->getMailTemplateName()); + + $replyTo = $this->recoveryConfiguration->getReplyTo(); + if ($replyTo) { + $mail->addReplyTo($replyTo); + } + + return $mail; + } + + protected function getEmailSubject(): string + { + return LocalizationUtility::translate('password_recovery_mail_header', 'felogin'); + } +} diff --git a/Classes/Validation/RedirectUrlValidator.php b/Classes/Validation/RedirectUrlValidator.php new file mode 100644 index 0000000..16155d5 --- /dev/null +++ b/Classes/Validation/RedirectUrlValidator.php @@ -0,0 +1,120 @@ +isRelativeUrl($request, $value) || $this->isInCurrentDomain($request, $value) || $this->isInLocalDomain($value)) { + $result = true; + } + + // Allow to change the validation result via a PSR-14 event + $event = new ModifyRedirectUrlValidationResultEvent($value, $result, $request); + $event = $this->eventDispatcher->dispatch($event); + $result = $event->getValidationResult(); + + // URL is not allowed + if (!$result) { + $this->logger->debug('Url "{url}" was not accepted.', ['url' => $value]); + } + + return $result; + } + + /** + * Determines whether the URL is on the current host and belongs to the + * current TYPO3 installation. The scheme part is ignored in the comparison. + */ + protected function isInCurrentDomain(RequestInterface $request, string $url): bool + { + $urlWithoutSchema = preg_replace('#^https?://#', '', $url) ?? ''; + $siteUrlWithoutSchema = preg_replace('#^https?://#', '', $request->getAttribute('normalizedParams')->getSiteUrl()) ?? ''; + // this condition only exists to satisfy phpstan, which complains that this could be an array, too. + if (is_array($siteUrlWithoutSchema)) { + $siteUrlWithoutSchema = $siteUrlWithoutSchema[0]; + } + return str_starts_with($urlWithoutSchema . '/', $request->getAttribute('normalizedParams')->getHttpHost() . '/') + && str_starts_with($urlWithoutSchema, $siteUrlWithoutSchema); + } + + /** + * Determines whether the URL matches a domain known to TYPO3. + */ + protected function isInLocalDomain(string $url): bool + { + if (!GeneralUtility::isValidUrl($url)) { + return false; + } + $parsedUrl = parse_url($url); + if ($parsedUrl['scheme'] === 'http' || $parsedUrl['scheme'] === 'https') { + $host = $parsedUrl['host']; + foreach ($this->siteFinder->getAllSites() as $site) { + if ($site->getBase()->getHost() === $host) { + return true; + } + } + } + return false; + } + + /** + * Determines whether the URL is relative to the current TYPO3 installation. + */ + protected function isRelativeUrl(RequestInterface $request, string $url): bool + { + $url = GeneralUtility::sanitizeLocalUrl($url, $request); + if (!empty($url)) { + $parsedUrl = @parse_url($url); + if ($parsedUrl !== false && !isset($parsedUrl['scheme']) && !isset($parsedUrl['host'])) { + // If the relative URL starts with a slash, we need to check if it's within the current site path + return $parsedUrl['path'][0] !== '/' || str_starts_with($parsedUrl['path'], $request->getAttribute('normalizedParams')->getSitePath()); + } + } + return false; + } +} diff --git a/Configuration/FlexForms/Login.xml b/Configuration/FlexForms/Login.xml new file mode 100644 index 0000000..69a2279 --- /dev/null +++ b/Configuration/FlexForms/Login.xml @@ -0,0 +1,297 @@ + + + + + LLL:EXT:felogin/Resources/Private/Language/Database.xlf:tt_content.pi_flexform.sheet_general + array + + + + + check + + + + + + + + + + + 1 + check + + + + + + + + + + + + check + + + + + + + + + 1 + + + group + pages + 3 + 22 + 0 + + + + + + + select + selectSingle + + + + + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 250 + + + 0 + 1 + 1 + + + + + + + + LLL:EXT:felogin/Resources/Private/Language/Database.xlf:tt_content.pi_flexform.sheet_redirect + array + + + + + select + selectMultipleSideBySide + + + + groupLogin + + + + userLogin + + + + login + + + + logout + + + + loginError + + + + getpost + + + + referer + + + + refererDomains + + + 8 + 0 + 8 + + + + + + check + + + + + + + + + + + group + pages + 1 + 1 + 0 + + + + + + group + pages + 1 + 1 + 0 + + + + + + group + pages + 1 + 1 + 0 + + + + + + check + + + + + + + + + + + + + LLL:EXT:felogin/Resources/Private/Language/Database.xlf:tt_content.pi_flexform.sheet_messages + array + + + + + input + 30 + + + + + + text + 30 + 5 + + + + + + input + 30 + + + + + + text + 30 + 5 + + + + + + input + 30 + + + + + + text + 30 + 5 + + + + + + input + 30 + + + + + + text + 30 + 5 + + + + + + input + 30 + + + + + + text + 30 + 5 + + + + + + input + 30 + + + + + + text + 30 + 5 + + + + + + + diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml new file mode 100644 index 0000000..8948bf3 --- /dev/null +++ b/Configuration/Services.yaml @@ -0,0 +1,21 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + TYPO3\CMS\FrontendLogin\: + resource: '../Classes/*' + + feloginPasswordRecovery.rateLimiterFactory: + class: TYPO3\CMS\Core\RateLimiter\RateLimiterFactory + arguments: + $config: + id: 'felogin-password-recovery' + policy: 'sliding_window' + limit: 5 + interval: '15 minutes' + + TYPO3\CMS\FrontendLogin\Controller\PasswordRecoveryController: + arguments: + $rateLimiterFactory: '@feloginPasswordRecovery.rateLimiterFactory' diff --git a/Configuration/Sets/Felogin/config.yaml b/Configuration/Sets/Felogin/config.yaml new file mode 100644 index 0000000..c1b6240 --- /dev/null +++ b/Configuration/Sets/Felogin/config.yaml @@ -0,0 +1 @@ +name: typo3/felogin diff --git a/Configuration/Sets/Felogin/labels.xlf b/Configuration/Sets/Felogin/labels.xlf new file mode 100644 index 0000000..56de2a0 --- /dev/null +++ b/Configuration/Sets/Felogin/labels.xlf @@ -0,0 +1,178 @@ + + + +
+ + + Frontend Login + + + Frontend Login + + + User Storage Page + + + Define the Storage Folder with the Website User Records, using a comma separated list or single value + + + Recursive + + + If set, also subfolder at configured recursive levels of the User Storage Page will be used + + + 0 + + + 1 + + + 2 + + + 3 + + + 4 + + + 255 + + + Display Password Recovery Link + + + If set, the section in the template to display the link to the forgot password dialog is visible. + + + Display Remember Login Option + + + If set, the section in the template to display the option to remember the login (with a cookie) is visible. + + + Disable redirect after successful login, but display logout-form + + + If set, the logout form will be displayed immediately after successful login. + + + Email Sender Address + + + email address used as sender of the change password emails + + + Email Sender Name + + + Name used as sender of the change password emails + + + Reply-to email Address + + + Reply-to address used in the change password emails + + + Date format + + + Format for the link is valid until message (forgot password email) + + + Layout root path + + + Path to layout directory used for emails + + + Template root path + + + Path to template directory used for emails + + + Partial root path + + + Path to partial directory used for emails + + + Template name for emails. + + + HTML emails get the .html file extension, plaintext emails get the .txt file extension. + + + Redirect Mode + + + Comma separated list of redirect modes.\ +Possible values: groupLogin, userLogin, login, getpost, referer, refererDomains, loginError, logout.\ +Warning: redirects only work if neither the plugin nor the page it is displayed on are set to `hide at login`. + + + Use First Supported Mode from Selection + + + If set the first method from redirectMode which is possible will be used + + + After Successful Login Redirect to Page + + + Page id to redirect to after Login + + + After Failed Login Redirect to Page + + + Page id to redirect to after Login Error + + + After Logout Redirect to Page + + + Page id to redirect to after Logout + + + Disable Redirect + + + If set redirecting is disabled + + + Time in hours how long the link for forgot password is valid + + + How many hours the link for forgot password is valid + + + Allowed Referrer-Redirect-Domains + + + Comma separated list of domains which are allowed for the referrer redirect mode + + + Path to template root (frontend) + + + Path to template directory used for the plugin in the frontend. Extends the default template location. + + + Path to template partials (frontend) + + + Path to partial directory for the plugin in the frontend. Extends the default partial location. + + + Path to template layouts (frontend) + + + Path to layout directory used for the plugin in the frontend. Can be used to introduce a custom layout. + + + + diff --git a/Configuration/Sets/Felogin/settings.definitions.yaml b/Configuration/Sets/Felogin/settings.definitions.yaml new file mode 100644 index 0000000..714c00f --- /dev/null +++ b/Configuration/Sets/Felogin/settings.definitions.yaml @@ -0,0 +1,107 @@ +categories: + felogin: ~ + +settings: + felogin.pid: + default: '0' + type: string + category: felogin + felogin.recursive: + default: '0' + type: string + enum: + - '0' + - '1' + - '2' + - '3' + - '4' + - '255' + category: felogin + felogin.showForgotPassword: + default: false + type: bool + category: felogin + felogin.showPermaLogin: + default: false + type: bool + category: felogin + felogin.showLogoutFormAfterLogin: + default: false + type: bool + category: felogin + felogin.emailFrom: + default: '' + type: string + category: felogin + felogin.emailFromName: + default: '' + type: string + category: felogin + felogin.replyToEmail: + default: '' + type: string + category: felogin + felogin.dateFormat: + default: 'Y-m-d H:i' + type: string + category: felogin + felogin.email.layoutRootPath: + default: '' + type: string + category: felogin + felogin.email.templateRootPath: + default: 'EXT:felogin/Resources/Private/Email/Templates/' + type: string + category: felogin + felogin.email.partialRootPath: + default: '' + type: string + category: felogin + felogin.email.templateName: + default: PasswordRecovery + type: string + category: felogin + felogin.redirectMode: + default: '' + type: string + category: felogin + felogin.redirectFirstMethod: + default: false + type: bool + category: felogin + felogin.redirectPageLogin: + default: 0 + type: int + category: felogin + felogin.redirectPageLoginError: + default: 0 + type: int + category: felogin + felogin.redirectPageLogout: + default: 0 + type: int + category: felogin + felogin.redirectDisable: + default: false + type: bool + category: felogin + felogin.forgotLinkHashValidTime: + default: 12 + type: int + category: felogin + felogin.domains: + default: '' + type: string + category: felogin + felogin.view.templateRootPath: + default: '' + type: string + category: felogin + felogin.view.partialRootPath: + default: '' + type: string + category: felogin + felogin.view.layoutRootPath: + default: '' + type: string + category: felogin diff --git a/Configuration/Sets/Felogin/setup.typoscript b/Configuration/Sets/Felogin/setup.typoscript new file mode 100644 index 0000000..e6a0616 --- /dev/null +++ b/Configuration/Sets/Felogin/setup.typoscript @@ -0,0 +1 @@ +@import 'EXT:felogin/Configuration/TypoScript/setup.typoscript' diff --git a/Configuration/TCA/Overrides/fe_groups.php b/Configuration/TCA/Overrides/fe_groups.php new file mode 100644 index 0000000..1cf6528 --- /dev/null +++ b/Configuration/TCA/Overrides/fe_groups.php @@ -0,0 +1,22 @@ + [ + 'exclude' => true, + 'label' => 'LLL:EXT:felogin/Resources/Private/Language/Database.xlf:felogin_redirectPid', + 'config' => [ + 'type' => 'group', + 'allowed' => 'pages', + 'size' => 1, + 'relationship' => 'manyToOne', + ], + ], + ]; + + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('fe_groups', $additionalColumns); + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('fe_groups', 'felogin_redirectPid', '', 'after:subgroup'); +}); diff --git a/Configuration/TCA/Overrides/fe_users.php b/Configuration/TCA/Overrides/fe_users.php new file mode 100644 index 0000000..38e0436 --- /dev/null +++ b/Configuration/TCA/Overrides/fe_users.php @@ -0,0 +1,29 @@ + [ + 'exclude' => true, + 'label' => 'LLL:EXT:felogin/Resources/Private/Language/Database.xlf:felogin_redirectPid', + 'config' => [ + 'type' => 'group', + 'allowed' => 'pages', + 'size' => 1, + 'relationship' => 'manyToOne', + ], + ], + 'felogin_forgotHash' => [ + 'exclude' => true, + 'label' => 'LLL:EXT:felogin/Resources/Private/Language/Database.xlf:felogin_forgotHash', + 'config' => [ + 'type' => 'passthrough', + ], + ], + ]; + + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('fe_users', $additionalColumns); + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes('fe_users', 'felogin_redirectPid', '', 'after:usergroup'); +}); diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php new file mode 100644 index 0000000..89f7543 --- /dev/null +++ b/Configuration/TCA/Overrides/tt_content.php @@ -0,0 +1,15 @@ +` is included, +the settings for EXT:felogin become available in the editor. + +You can find the available site settings in module +:guilabel:`Sites > Setup > Settings` + +You can change individual settings here. If the site settings are writable +you can hit the :guilabel:`Save` button and the settings will be written +directly to the site settings. + +If the settings are not writable you can click the :guilabel:`YAML export` +button to export the settings. These can then be added by a developer with +sufficient rights. + +The available settings are also described in detail in +:ref:`configuration-site-set-settings`. diff --git a/Documentation/Configuration/SiteSets.rst b/Documentation/Configuration/SiteSets.rst new file mode 100644 index 0000000..733c496 --- /dev/null +++ b/Documentation/Configuration/SiteSets.rst @@ -0,0 +1,111 @@ +:navigation-title: Site Sets + +.. include:: /Includes.rst.txt +.. _configuration-site-sets-include: + +============================================ +Site set configuration of the Frontend Login +============================================ + +.. versionadded:: 13.1 + Site sets were added. + +The system extension :composer:`typo3/cms-felogin` provides the site +set "Frontend Login". + +The different methods of setting are taking precedence in the following order: + +.. include:: _SettingsOrder.rst.txt + +.. contents:: + :caption: Content on this page + :depth: 1 + +.. _configuration-site-set: + +Include the site set +==================== + +Include the site set "Frontend Login" via the :ref:`site set in the site +configuration ` or the custom +:ref:`site package's site set `. + +.. figure:: /Images/SiteSet.png + + Add the site set "Frontend Login" + +This will change your site configuration file as follows: + +.. literalinclude:: _site_config.diff + :caption: config/sites/my-site/config.yaml (diff) + +If your site has a custom :ref:`site package `, you +can also add the "Frontend Login" set as dependency in your site set's configuration: + +.. literalinclude:: _site_package_set.diff + :caption: EXT:my_site_package/Configuration/Sets/MySite/config.yaml (diff) + +.. _configuration-site-set-settings: + +Settings for the "Frontend Login" site set +========================================== + +.. versionadded:: 13.1 + These settings were added with the site sets in TYPO3 v13.1. + +See also: :ref:`configuration-examples-felogin-pid`. + +If you plan to migrate from TypoScript setup settings to site settings see +:ref:`configuration-migration`. + +These settings can be adjusted in the :ref:`settings-editor`. + +.. typo3:site-set-settings:: PROJECT:/Configuration/Sets/Felogin/settings.definitions.yaml + :name: felogin + :type: + :Label: max=36 + :caption: Settings of "Frontend Login" + + +.. _configuration-migration: + +Migration from TypoScript setup settings to site settings +========================================================= + +The site settings are named like the TypoScript constants used before +site sets. However the TypoScript constants are not always named the same +like the :ref:`TypoScript setup settings `. + +For each :ref:`TypoScript setup / FlexForm setting ` +we list the corresponding site set setting in the overview table of the configuration values. + +For example, the setting :confval:`felogin.pid ` sets +setting :ref:`pages `. + +Bear that in mind when migrating from TypoScript setup to site set settings. + +.. _configuration-examples-felogin-pid: + +Example: Set the user storage page using the site set settings +============================================================== + +After you :ref:`included the site set ` you can use +the :ref:`site set settings ` to configure +the frontend login plugin's behaviour and layout site-wide. + +See also :ref:`Adding site settings `. + +You can add the settings to your :ref:`Site settings ` +or to the settings of your +:ref:`custom site package extension `. + +To add the settings to your site settings, edit the file +:file:`config/sites//settings.yaml` in Composer-based installations +or :file:`typo3conf/sites//settings.yaml` in legacy installations. If +the file does not exist yet, create one. Use the setting +:confval:`felogin.pid ` to set the storage folder. If +its subfolders should also be included, additionally use setting +:confval:`felogin.recursive `. + +.. literalinclude:: _settings.yaml + :caption: config/sites//settings.yaml | typo3conf/sites//settings.yaml diff --git a/Documentation/Configuration/TypoScript.rst b/Documentation/Configuration/TypoScript.rst new file mode 100644 index 0000000..b642827 --- /dev/null +++ b/Documentation/Configuration/TypoScript.rst @@ -0,0 +1,293 @@ +:navigation-title: TypoScript + +.. include:: /Includes.rst.txt +.. _configuration-typoscript: + +============================================== +TypoScript configuration of the Frontend Login +============================================== + +.. contents:: + :caption: Content on this page + :depth: 1 + +.. _plugin-tx-felogin-login: + +TypoScript setup / FlexForm settings +==================================== + +Most of these plugin settings can be set with the following methods, the top +bottom most taking precedence: + +.. include:: _SettingsOrder.rst.txt + +See also :ref:`configuration-examples-flexform`. + +.. confval-menu:: + :name: typoscript + :display: table + :type: + :Site set setting: + + .. _showforgotpassword: + + .. confval:: showForgotPassword + :name: typoscript-showForgotPassword + :type: bool + + If set, the section in the template to display the link to the forgot + password dialogue is visible. + + .. important:: + Be aware that having this option disabled also prevents the plugin to + display the forgot password form. For instance if you access the link + directly. + + .. _showpermalogin: + + .. confval:: showPermaLogin + :name: typoscript-showPermaLogin + :type: bool + + If set, the section in the template to display the option to remember + the login (with a cookie) is visible. + + .. _showlogoutformafterlogin: + + .. confval:: showLogoutFormAfterLogin + :name: typoscript-showLogoutFormAfterLogin + :type: bool + + If set, the logout form will be displayed immediately after successful + login. + + .. note:: + Setting this option will disable the redirect options! + Instead of redirecting the plugin will show the logout form. + + .. _pages: + + .. confval:: pages + :name: typoscript-pages + :type: string + :Site set setting: :confval:`felogin.pid ` + :TypoScript Constant: {$styles.content.loginform.pid} + + Define the User Storage Page with the Website User Records, using a + comma separated list or a single value (page id). + + .. _recursive: + + .. confval:: recursive + :name: typoscript-recursive + :type: int + :Site set setting: :confval:`felogin.recursive ` + :TypoScript Constant: {$styles.content.loginform.recursive} + + If set, also any subfolders of the User Storage Page will be used + at configured recursive levels + + .. _redirectmode: + + .. confval:: redirectMode + :name: typoscript-redirectMode + :type: string + :Site set setting: :confval:`felogin.redirectMode ` + :TypoScript Constant: {$styles.content.loginform.redirectMode} + + Comma separated list of redirect modes. Possible values: + ``groupLogin``, ``userLogin``, ``login``, ``getpost``, ``referer``, + ``refererDomains``, ``loginError``, ``logout`` + See section on redirect modes for details. + + .. _redirectfirstmethod: + + .. confval:: redirectFirstMethod + :name: typoscript-redirectFirstMethod + :type: bool + :Site set setting: :confval:`felogin.redirectFirstMethod ` + :TypoScript Constant: {$styles.content.loginform.redirectFirstMethod} + + If set the first method from redirectMode which is possible will be + used + + .. _redirectpagelogin: + + .. confval:: redirectPageLogin + :name: typoscript-redirectPageLogin + :type: integer + :Site set setting: :confval:`felogin.redirectPageLogin ` + :TypoScript Constant: {$styles.content.loginform.redirectPageLogin} + + Page id to redirect to after Login + + .. _redirectpageloginerror: + + .. confval:: redirectPageLoginError + :name: typoscript-redirectPageLoginError + :type: integer + :Site set setting: :confval:`felogin.redirectPageLoginError ` + :TypoScript Constant: {$styles.content.loginform.redirectPageLoginError} + + Page id to redirect to after Login Error + + .. _redirectpagelogout: + + .. confval:: redirectPageLogout + :name: typoscript-redirectPageLogout + :type: integer + :Site set setting: + :TypoScript Constant: {$styles.content.loginform.redirectPageLogout} + + Page id to redirect to after Logout + + .. _redirectdisable: + + .. confval:: redirectDisable + :name: typoscript-redirectDisable + :type: bool + :Site set setting: :confval:`felogin.redirectPageLogout ` + :TypoScript Constant: {$styles.content.loginform.redirectDisable} + + If set redirecting is disabled + + .. _dateformat: + + .. confval:: dateFormat + :name: typoscript-dateFormat + :type: date-conf + :Site set setting: :confval:`felogin.dateFormat ` + :TypoScript Constant: Y-m-d H:i + + Format for the link is valid until message (forgot password email) + + .. _email-from: + + .. confval:: email_from + :name: typoscript-email-from + :type: string + + Email address used as sender of the change password emails + + .. _email-fromname: + + .. confval:: email_fromName + :name: typoscript-email-fromName + :type: string + + Name used as sender of the change password emails + + .. confval:: email + :name: typoscript-email + + .. confval:: email.templateName + :name: typoscript-email.templateName + :type: string + :Site set setting: :confval:`felogin.email.templateName ` + :TypoScript Constant: {$styles.content.loginform.email.templateName} + + Template name for emails. Plaintext emails get the .txt file extension. + + .. confval:: email.layoutRootPaths + :name: typoscript-email.layoutRootPaths + :type: array + :Site set setting: :confval:`felogin.email.templateRootPath ` + :TypoScript Constant: {$styles.content.loginform.email.layoutRootPath} + + Path to layout directory used for emails + + .. confval:: email.templateRootPaths + :name: typoscript-email.templateRootPaths + :type: array + :Site set setting: :confval:`felogin.email.templateRootPath ` + :TypoScript Constant: {$styles.content.loginform.email.templateRootPaths} + + Path to template directory used for emails + + .. confval:: email.partialRootPaths + :name: typoscript-email.partialRootPaths + :type: array + :Site set setting: :confval:`felogin.email.partialRootPath ` + :TypoScript Constant: {$styles.content.loginform.email.partialRootPaths} + + Path to partial directory used for emails + + .. confval:: forgotLinkHashValidTime + :name: typoscript-forgotLinkHashValidTime + :type: integer + :Site set setting: :confval:`felogin.forgotLinkHashValidTime ` + :TypoScript Constant: {$styles.content.loginform.forgotLinkHashValidTime} + + Time in hours how long the link for forgot password is valid + + .. _domains: + + .. confval:: domains + :name: typoscript-domains + :type: string + + Comma separated list of domains which are allowed for the referrer + redirect mode + + +.. _configuration-examples-typoscript-constant: + +Example: Set the default storage page via TypoScript constant +============================================================= + +You can use the :ref:`TypoScript provider ` +or other means of :ref:`setting the TypoScript constants `. + +.. versionchanged:: 13.1 + It is recommended to use the :ref:`configuration-site-set-settings` + instead, as TypoScript constants will be phased out in the future. + +.. literalinclude:: _constants.typoscript + :caption: config/sites/MySite/constants.typoscript + +.. _configuration-examples-typoscript: + +Example: Set the default storage page via TypoScript setup +========================================================== + +In order to set the default storage page to a more dynamic value, use +the TypoScript setup. Use the :ref:`TypoScript provider ` +or other means of ref:`setting the TypoScript setup `. + +.. literalinclude:: _setup.typoscript + :caption: config/sites/MySite/constants.typoscript + +.. _configuration-examples-flexform: + +Example: Override the default storage page in the plugin's FlexForm +=================================================================== + +If you set any FlexForm setting within the content element representing the +plugin to a **non-empty value** it will override any other setting not matter if it +is made via site settings, TypoScript constant ot TypoScript setup. Empty values +take no effect if a default was set by other means. + +In the backend module :guilabel:`Content > Layout` edit the content element containing +the login form. Go to tab :guilabel:`Plugin` and sub tab :guilabel:`General`. +You should see a form similar to the following: + +.. figure:: /Images/GeneralSettings.png + :alt: A screenshot showing the "General" tab of the plugin settings + + Settings in the tab :guilabel:`General` of the plugin tab + +Choose the desired page or pages in the field with label +:guilabel:`User Storage Page` (key :confval:`settings.pages `). + +.. tip:: + It is sometimes hard to determine, which label in the FlexForm corresponds + to which key in the :ref:`FlexForm reference `. + + Turn on the :confval:`backend debug mode ` + to get a visual hint in the backend for the keys of the FlexForm field. + +.. figure:: /Images/FlexFormKey.png + :alt: A screenshot showing FlexForm Field with key `settings.pages` + + The corresponding FlexForm field :confval:`settings.pages ` + in backend debug mode. diff --git a/Documentation/Configuration/_SettingsOrder.rst.txt b/Documentation/Configuration/_SettingsOrder.rst.txt new file mode 100644 index 0000000..4722845 --- /dev/null +++ b/Documentation/Configuration/_SettingsOrder.rst.txt @@ -0,0 +1,5 @@ +* The corresponding :ref:`site set setting ` +* The corresponding :ref:`TypoScript constant ` +* Value set in :ref:`TypoScript setup ` in the + scope :ref:`plugin.tx_felogin_login.settings ` +* Setting from the :ref:`FlexForm of the plugin ` diff --git a/Documentation/Configuration/_constants.typoscript b/Documentation/Configuration/_constants.typoscript new file mode 100644 index 0000000..77e3b45 --- /dev/null +++ b/Documentation/Configuration/_constants.typoscript @@ -0,0 +1,4 @@ +styles.content.loginform { + pid = 42 + recursive = 255 +} diff --git a/Documentation/Configuration/_settings.yaml b/Documentation/Configuration/_settings.yaml new file mode 100644 index 0000000..686ffcb --- /dev/null +++ b/Documentation/Configuration/_settings.yaml @@ -0,0 +1,4 @@ +felogin: + pid: 42 + recursive: 255 + diff --git a/Documentation/Configuration/_setup.typoscript b/Documentation/Configuration/_setup.typoscript new file mode 100644 index 0000000..0d023a1 --- /dev/null +++ b/Documentation/Configuration/_setup.typoscript @@ -0,0 +1,5 @@ +[{$tx_my_extension.settings.feature1Enabled} == 1] + plugin.tx_felogin_login.settings.pid = 123 +[ELSE] + plugin.tx_felogin_login.settings.pid = 42 +[END] diff --git a/Documentation/Configuration/_site_config.diff b/Documentation/Configuration/_site_config.diff new file mode 100644 index 0000000..fa699e4 --- /dev/null +++ b/Documentation/Configuration/_site_config.diff @@ -0,0 +1,5 @@ + base: 'https://example.com/' + rootPageId: 1 + dependencies: ++ - typo3/felogin + - typo3/fluid-styled-content-css diff --git a/Documentation/Configuration/_site_package_set.diff b/Documentation/Configuration/_site_package_set.diff new file mode 100644 index 0000000..6636a50 --- /dev/null +++ b/Documentation/Configuration/_site_package_set.diff @@ -0,0 +1,9 @@ + name: my-vendor/my-site-package + label: My Site Package Set + settings: + website: + background: + color: '#386492' + dependencies: ++ - typo3/felogin + - typo3/fluid-styled-content-css diff --git a/Documentation/Events/Index.rst b/Documentation/Events/Index.rst new file mode 100644 index 0000000..4a2f1f7 --- /dev/null +++ b/Documentation/Events/Index.rst @@ -0,0 +1,60 @@ +.. include:: /Includes.rst.txt + +.. _psr14events: + +============= +PSR-14 events +============= + +The following PSR-14 events are available to extend the extension: + +AfterUserLoggedInEvent +====================== + +Trigger any kind of action when a frontend user has been successfully logged in. +:ref:`More details ` + +BeforeRedirectEvent +=================== + +Notification before a redirect is made. +:ref:`More details ` + +LoginConfirmedEvent +=================== + +A notification when a log in has successfully arrived at the plugin, via the +view and the controller, multiple information can be overridden in event +listeners. :ref:`More details ` + +LoginErrorOccurredEvent +======================= + +A notification if something went wrong while trying to log in a user. +:ref:`More details ` + +LogoutConfirmedEvent +==================== + +A notification when a log out has successfully arrived at the plugin, via +the view and the controller, multiple information can be overridden in +event listeners. :ref:`More details ` + +ModifyLoginFormViewEvent +======================== + +Allows to inject custom variables into the login form. +:ref:`More details ` + +PasswordChangeEvent +=================== + +Event that contains information about the password which was set, +and is about to be stored in the database. +:ref:`More details ` + +SendRecoveryEmailEvent +====================== + +Event that contains the email to be sent to the user when they request a +new password. :ref:`More details ` diff --git a/Documentation/Examples/Index.rst b/Documentation/Examples/Index.rst new file mode 100644 index 0000000..f4b2b0e --- /dev/null +++ b/Documentation/Examples/Index.rst @@ -0,0 +1,199 @@ +.. include:: /Includes.rst.txt + +.. _examples: + +======== +Examples +======== + +In this section some common situations are described: + +.. contents:: + :local: + +.. _login-and-back-to-original-page: + +Send visitors to login page and redirect to original page +========================================================= + +A common situation is that visitors who go to a page with access +restrictions should go to a login page first and after logging in +should be send back to the page they originally requested. + +Assume we have a login page with id `2`. + +Using TypoScript we can still display links to access restricted pages +and send visitors to the login page: + +.. code-block:: typoscript + + config { + typolinkLinkAccessRestrictedPages = 2 + typolinkLinkAccessRestrictedPages_addParams = &return_url=###RETURN_URL### + } + +On the login page the login form must be configured to redirect to the +original page: + +.. code-block:: typoscript + + plugin.tx_felogin_login.settings.redirectMode = getpost + +(This option can also be set in the flexform configuration of the +felogin content element) + +If visitors will directly enter the URL of an access restricted page +they will be sent to the first page in the rootline to which they have +access. Sending those direct visits to a login page is not a job of +the felogin plugin, but requires a custom page-not-found handler. In this sense, +we refer to :ref:`felogin-how-to-implement-403redirect-error-handler`. + + +.. _login-link-visibility: + +Login link visible when not logged in and logout link visible when logged in +============================================================================ + +Again TypoScript will help you out. The page with the login form has +id=2: + +.. code-block:: typoscript + + 10 = TEXT + 10 { + value = Login + typolink.parameter = 2 + } + [frontend.user.isLoggedIn] + 10.value = Logout + 10.typolink.additionalParams = &logintype=logout + [end] + +Of course there can be solutions with :typoscript:`HMENU` items, etc. + +.. _felogin-how-to-implement-403redirect-error-handler: + +Custom error handler implementation for 403 redirects +===================================================== + +This section explains how to utilize a custom error handler +to catch 403 restricted page errors and allow to forward +to a login form, and then redirect back to the originating +page after successful login. + +.. rst-class:: bignums + +#. You need the following site settings in the error handling + + .. figure:: ../Images/felogin_site_settings_error_handling.png + :caption: Error Handling tab of site configuration module + :class: with-shadow + + :guilabel:`Error Handling` tab of Site Configuration module + + There you add the custom 403 error handler and configure + the error handler, you create in the following steps. + + .. todo:: Future TYPO3 versions may do this automatically + see https://review.typo3.org/c/Packages/TYPO3.CMS/+/81945 + + .. seealso:: + :ref:`Error handling in site configuration ` + +#. Look up the page ID where a login form (like with EXT:felogin) is placed + + This page ID is needed in the following step, so that the error + handler will know, where to forward an unauthenticated user to, so + that a login can be performed. + + Ideally, this should be done by configuring a page ID via the + site settings, and referring back to a named ID. See + :ref:`PHP API: accessing site configuration ` + for more information. For reduced complexity, this example uses + a hard-coded page ID. + +#. Create a new error handler :file:`RedirectLoginErrorHandler.php` + + Create a PHP error handler class like the following in a custom + extension, like your own :ref:`sitepackage `: + + .. literalinclude:: _RedirectLoginErrorHandler.php + :caption: EXT:my_sitepackage/Classes/Error/PageErrorHandler/RedirectLoginErrorHandler.php + :language: php + + Adapt the constant :php:`PAGE_ID_LOGIN_FORM` to match the + page ID from the previous step. + Since there is no proper way how to do it otherwise, we put in the page ID + of the login form hard-coded into the file :file:`RedirectLoginErrorHandler.php` + and define a constant :php:`PAGE_ID_LOGIN_FORM` for it. In the example + above, this is set to `656`. + +#. In your EXT:felogin plugin, make sure you selected "Defined by GET/POST + Parameters" as first redirect mode + + .. figure:: ../Images/SettingsRedirectCustomErrorHandler.png + :caption: Plugin > Redirects tab of Login Form content element + :class: with-shadow + + :guilabel:`Plugin > Redirects` tab of :guilabel:`Login Form` content element + + You need to configure the login form that receives your redirect in a + way, that allows to evaluate submitted URL parameters. In `EXT:felogin`, + this is achieved via this :guilabel:`Redirect Mode` (which can also be set + through TypoScript configuration, see :confval:`redirectMode `. + + Your login form will probably also need to define a specific target page + for normal logins (independent from the error handler redirect), so you + should also add a `redirectMode` like `login` to your list, and set + a target page in :confval:`redirectPageLogin `. + +#. Testing the custom error handler + + Clear the caches, for example via the backend module + :guilabel:`System > Maintenance`. + + Then open any access-restricted page + in an incognito browser window to be sure that + you are not logged in yet. Here we will use the example + URL :samp:`https://example.org/restricted/page`. + + When everything is configured correctly and if you are not logged in + yet, then you should be redirected to your login page like + :samp:`https://example.org/login` (example page ID `656`). + + After entering proper frontend user credentials, you should be redirected + back to :samp:`https://example.org/restricted/page`, the page where you + wanted to get to initially. + + .. hint:: + + When you have multiple site configurations, be sure to access + the correct one. This means where both the login form is located, + and the custom error handler is configured for. + + .. hint:: + + Do not copy the generated link from the address URL after you clicked + :guilabel:`View webpage` from the backend, and then just paste it into + the URL bar of the incognito window. The reason is that when + being logged in to the backend, a possibly simulated frontend user + login can affect your tests. + + .. hint:: + + Do not get confused when the URL + :samp:`https://example.org/restricted/page` will be forwarded to a URL + like + + :samp:`https://example.org/login?return_url=https%3A%2F%2Fexample.org%3A8443%2Frestricted%2Fpage&cHash=d0e92f9f9f7b3ca98a2e5e688ad22de9` + + when you want to access the restricted page in the first place. + These are the `getpost` redirect parameters that are evaluated by + `EXT:felogin`. Now type in the user credentials of the already created + frontend user and you should get redirected to the desired + page :samp:`https://example.org/restricted/page`. + +This example was taken from +`[FEATURE] Introduce ErrorHandler for 403 errors with redirect option `__ +which works in TYPO3 v11 and v12, and has been integrated to TYPO3 v13, where it can be used +without a custom implementation. diff --git a/Documentation/Examples/_RedirectLoginErrorHandler.php b/Documentation/Examples/_RedirectLoginErrorHandler.php new file mode 100644 index 0000000..dbaee1d --- /dev/null +++ b/Documentation/Examples/_RedirectLoginErrorHandler.php @@ -0,0 +1,157 @@ + 't3://page?uid=' . self::PAGE_ID_LOGIN_FORM, + 'loginRedirectParameter' => 'return_url', + ]; + + $this->context = GeneralUtility::makeInstance(Context::class); + $this->linkService = GeneralUtility::makeInstance(LinkService::class); + $this->errorPageController = GeneralUtility::makeInstance(ErrorPageController::class); + + $urlParams = $this->linkService->resolve($configuration['loginRedirectTarget']); + $this->loginRedirectPid = (int)($urlParams['pageuid'] ?? 0); + $this->loginRedirectParameter = $configuration['loginRedirectParameter']; + } + + public function handlePageError( + ServerRequestInterface $request, + string $message, + array $reasons = [] + ): ResponseInterface { + $this->checkHandlerConfiguration(); + + if ($this->shouldHandleRequest($reasons)) { + return $this->handleLoginRedirect($request); + } + + // Show general error message with a 403 HTTP status code + return $this->getGenericAccessDeniedResponse($message); + } + + private function getGenericAccessDeniedResponse(string $reason): ResponseInterface + { + $reason = $reason ? ' Reason: ' . $reason : ''; + $content = $this->errorPageController->errorAction( + 'Page Not Found', + sprintf('The page did not exist or was inaccessible.%s', $reason), + 0, + $this->statusCode, + ); + return new HtmlResponse($content, $this->statusCode); + } + + private function handleLoginRedirect(ServerRequestInterface $request): ResponseInterface + { + if ($this->isLoggedIn()) { + return $this->getGenericAccessDeniedResponse( + 'The requested page was not accessible with the provided credentials' + ); + } + + /** @var Site $site */ + $site = $request->getAttribute('site'); + $language = $request->getAttribute('language'); + + $loginUrl = $site->getRouter()->generateUri( + $this->loginRedirectPid, + [ + '_language' => $language, + $this->loginRedirectParameter => (string)$request->getUri(), + ] + ); + + return new RedirectResponse($loginUrl); + } + + private function shouldHandleRequest(array $reasons): bool + { + if (!isset($reasons['code'])) { + return false; + } + + $accessDeniedReasons = [ + PageAccessFailureReasons::ACCESS_DENIED_PAGE_NOT_RESOLVED, + PageAccessFailureReasons::ACCESS_DENIED_SUBSECTION_NOT_RESOLVED, + ]; + $isAccessDenied = in_array($reasons['code'], $accessDeniedReasons, true); + + return $isAccessDenied || $this->isSimulatedBackendGroup(); + } + + private function isLoggedIn(): bool + { + if ($this->context->getPropertyFromAspect('frontend.user', 'isLoggedIn')) { + return true; + } + return $this->isSimulatedBackendGroup(); + } + + private function isSimulatedBackendGroup(): bool + { + if (!$this->context->getPropertyFromAspect('backend.user', 'isLoggedIn')) { + return false; + } + // look for special "any group" + $groups = $this->context->getPropertyFromAspect('frontend.user', 'groupIds'); + return $groups[1] === -2; + } + + private function checkHandlerConfiguration(): void + { + if ($this->loginRedirectPid === 0) { + throw new \RuntimeException('No loginRedirectTarget configured for LoginRedirect errorhandler', 1700813537); + } + + if ($this->statusCode !== 403) { + throw new \RuntimeException(sprintf('Invalid HTTP status code %d for LoginRedirect errorhandler', $this->statusCode), 1700813545); + } + } +} diff --git a/Documentation/GetPostParameters/Index.rst b/Documentation/GetPostParameters/Index.rst new file mode 100644 index 0000000..3fab211 --- /dev/null +++ b/Documentation/GetPostParameters/Index.rst @@ -0,0 +1,31 @@ +.. include:: /Includes.rst.txt + +.. _get-post-paremeters: + +======================= +GET and POST parameters +======================= + +The extension uses several GET and POST parameters to define or override +redirect settings. + + +.. _noredirect: + +noredirect +---------- + +.. container:: table-row + + Parameter + noredirect + + Evaluation + GET and POST + + Data type + string + + Description + If set to :php:`1`, no redirect will be processed after a successful + login. diff --git a/Documentation/Images/ContentElementWizard.png b/Documentation/Images/ContentElementWizard.png new file mode 100644 index 0000000000000000000000000000000000000000..bfa2067caee05edb050ca53665164683572f07d5 GIT binary patch literal 20667 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 G`2G)adnkqg literal 0 HcmV?d00001 diff --git a/Documentation/Images/GeneralSettings.png b/Documentation/Images/GeneralSettings.png new file mode 100644 index 0000000000000000000000000000000000000000..b75d14e3c6589355acb0714a4c8c2c0196fc71fc GIT binary patch literal 23503 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 literal 0 HcmV?d00001 diff --git a/Documentation/Images/MessagesConfiguration.png b/Documentation/Images/MessagesConfiguration.png new file mode 100644 index 0000000000000000000000000000000000000000..01d6635348389c9228646e52d99ac14bfdd6b99e GIT binary patch literal 14820 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 R&;kwuX{cx^mnm9>{5N&Y0KWhL literal 0 HcmV?d00001 diff --git a/Documentation/Images/RedirectConfiguration.png b/Documentation/Images/RedirectConfiguration.png new file mode 100644 index 0000000000000000000000000000000000000000..1a689363c551fcda16f108257987f15a6b78fecb GIT binary patch literal 35115 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

LbihBIZe!|ARo4u6n> zk)w4nmE5T&Z$@xVZ#14%2&W6re%*9_x;N4_&W%KPI=TkDy;#&$IVfiV!@_FaCZ1u0 z0#`?(N|olzhxw&-3Wi-fYryr)e>TX%|3dlu+2Iouo^u!*9!UlK0BTgKLEN#F^7_?f z4_CjM$wI^V=uv!<|HgtmfV9U%yQMb8_}|(Eef#j1R0&$xH6ts*S6skky_|iwT6|i} zRIRg~pNedMBxES^Z8


TN}n^F#|J>mLzQc={4B0#fa<;ba#;JBPUDeLK9DqIo|F}NSM z`47=)>{eOR#*h9?3CK1uiyu>_z{GYF5NZ6DK)IoO0i(=5|3bD9Dnmj?HXbKk&Gnf4 zhYEAmIb+HQsl;S@-c8vgb`HwCXg`kKHgS)&lBkvs4_NDN+P;gxo6Z#*2zl6P9x>Np zO#50?C_YEqs_*Oir0=Es$}JpWiRG<+xt>NT#_{C~xm`rJgWu(eL-qP;k2?|A*`D#r zX3v!&UG4Wwal$C+1W22Vrh>k2H-zc9!#5@-Uk~7tt~`2IqEzp35?PyHg;gBvo>M_^ zW7IZM`_}^|7xi$0I-mU^^$jF51^=+Inv=o>1BMD#Cq4rq@G}Bl;7BkxyUFc%K^zE$ zpCtH<4Dv8js2&U+qptT z8tP-rJ@>|r4klU#l2l?U24YD*mR_AHKtUa`22Ye1qi{$Q@wcaNit$XxO^&T7LC>B8J50!F#==%BY zvu(<g9Sxt2*B9{mfsqMG z#b_K(fMq5-9pvz5lz%f6W+I!65A- z(pz};-0x^9_L0s|pGehRkfeVb9BCqy!Y&-(TF)->x8|5zqJUrbFPKO#4Mi-iZkirG z2fh3wK{qZ6Nl=IX6-5^>kovzO=kZDPanF-)6n`UYiwOnn{vS}4^1J&7o(2B}&p^dl zYAdLP@h|i?k%i6z$gjTfzWM0-^ir|b6&&+e?!U5Ae*hjh2L=U%0PFjo@j<6!3y@Xp zjw7W5&LMKY!mWWgN&aHkNE_Dr)-ox2r|7VZ@TOcKxy60qkNtl#ThdUaMrX(2@zKqC z@BP!C_6R86vJ*(X_#9uj?u!`B?-$O0wFA7W^c^}a5y+%?O)p>tXnLxJ4^*9ARom+a zPNqElLi4ST=2$A^UwB{i$e>)`j!z<=CGy0D*=ww?_&{DPE+O}n?_QgKQkKF~hdJB4 zN=mJ@;jDM|%CN5NuZb&F=Fpu_{oYQ}&{(G!z`Foenx$0$roZa7&W{Zq+E``Hh{j0Hb(T2UFNvF-(2w3&ZHix2CKNw1Uy3*db z0Erv;;1f_`KWv`x(YD#V-lyK)G{g-^J6J1(dv&3I}m;fBRagcNBITtUqUF5hn_5p2qdH5x0K?&NH)}Vlv&XdSd zDS`%y-@$gT%7qtexim{FD>ta8H3=lGXO)qqv@#e`9o@9HNy5rTKpBwTCZxd$S(s>F zf3`GFxeu#!=-6E0lX>u0GE~Lh+^u|5gL^N#nTz^A82a1ZJSconi0^DrBxm3>c@e(h zRy_h5$r!0E$NrWg&3ZljM4M~{O(VTd+Lg_3BYbh{$pL)u5~aB36fe~GvbT(x;;~7S zT25YaTvtUhL*I+O;dQz0w)&AE4tE*mw)TR-00ECV$AsQ4sip#JQhGPDrq@4o`yyGf z_NZIzdkI`Rxh=*HYcC2F>PD|9UZWL~@sgWf-G5vdTTwvO+{>2A?lbr%JoJrXbTsu? zMx6ss0Mvmv^ujTCu>_uzmh7qm7tV%g0be;-2Mn6MjBl?mJtKOe&F%ED zmYHI-i9+7daV}9!P_g|^mTGO(j#brLf{Wn(gEk`)!bPRC2sT*_`WAI;}| z&-pY;B{LKOu7-z{L^($>AhjZ1CN-4O8XarByRSC-f0g&uQBk&EyQ3nCA}AvvsS-mo zfRX|#A`B_rFtoI!(h7=_(hNvQmoy9=BPHDp^3n_`Eq(4$-(P)ao%Q{5&N^qEe`XOg z&vVan?|biS*R^-QHiiad6IuF}l;A0c<{ewu4k&PiorC!hr%1n#t{rS(zJ}0J3-VI( z_PcO(@t$A>!aM7ET;L;DXW=m9J)CwUW5h5>G+kz7Ufjtl1?n`1)Tlae$D+0{QW-W+cax5=Xf4I()9;jR_H)nY+LiP`)H)fwJnqAS<|cKw{hA?BLpve z;ISm@`&@pkB$_A&cCR)QMWXruZO53AobxRruSayW$y!m^H)sJPE_pwMq#I z+EPT@fhySFVR8*a?}H`DvxDruGerGC(A3XPVDo@J$NY&q^NRod3l5+|=@sC=l1)5l zrT3s?BL|U}^}<89`e$=j740{W>RqiC4mLjjJ3Pd*g;xxU3CKCC6MpBu=VGNf3nwpe zRXcOHlR4bJ6e+&)55ELl802&|S9#5fzC#@8)x&j^TN#~yj_|^~LYe{u1rB!11xx-B zc>dZ^AVn0!WkXiWVKa*IA!il>Cp9L$t=Y+y?SgL9pM~l1L zCA&rT4WoFYS}PXyA{tsB6&w8RQ_U*CXF&0UefuneuqOyq99=XK6YERxSa{!uBvLS( zyKev4S4_O1%x4~55(ts=@mf!|MM~TI!M(+ z210+=S};9uWf9(8CH_b)iZI0vx=9=~0D=<`4)Pu3~jyL{{ ztP!Rb$-e%+MFR(%@y3&sz;bWJQ(`L)xjWcNIvm?i?gK_BpiwG&`Ag9R&65F6B1GK> zP0MF%`1{KE?ZXWHBi1bbZ{;40r%}e}ZV9_N#RN(!N{H-PjWlGL!4H}DFg{ZjOnI9m9~Z$=lZKe*Efu-5qPOVO=~^xIQZ zY#6em)Fn!`<*>uh3%UaSiOkrDTiF|O9wLUb?wJxk z0`Xg~0!KZrrFu=-9{@e`YtLoi_8DqvcPApmOQGi6Qn4}FMq+(yGLA8h((xmGk&YzG zF+QJNpa)k=}?xZF9rpU&s=Hxmutyug0d_t7_~_;8D3} zfsmmgJ3)!6=MQ2Y)1;Z+C}Iw&9=s$?q-B+*C4$xLWFr#RT!W*GRgwy0t+L*%xL4HS z_tnwWZ-G!YPUbBmk#pvaYLS;eO&3+$0QpLf@ zIp)5HszbMFtPNbT{)59i&-5!FjHb;j&Bs_cW82))pe$qthU)X>p93ln?g>g3Cb~;H zMZ`*c8{&1zabqJ!pjC1cWS`*{BzR#`-OI@Zjw*LQ ze<>e9^8}{fLOqnU&+vM{TQ!$xu84rb?1#zBo(Ndd-R$gee&*=R^)xn5%3vOAC3DOk z6&o3hHTuBaNF&BiS9K>Ps>Ia9DiNH&ft8eCrQ*w@u1vPO@HX)<4%Hl(NRCUB0W60G zKRl52o?1A^{TK1SWNQC{h9|HvM(MT|93-+?%ilUHljBl5WvxHhDuC3?@{@Vp+GmP^ zz`ig4^cZ|2`+mJNo9!Sod)YC%FRcZsb@-7adZTDp_WQCygl|Nrh*Vh)rm)cqgP;c$mJ)`6IW-@ zz-erDq6&DOoGou3VVHSp{pe%oOGc;X(%3C+L$@lsnbg%cTM9ChvDws;O5>k$qtS8{ z#x8HASvVOaCVMPxv|=k7=Xnyxnnx99^bCy1E{2u4QXGV&=2*Q=2z)}reard5%fk-e zCO@x5{k6zA&EiR?+6ny&SpD3+E#L|KlB`X_^cLBR*$Tubw+H2;#h)ncu3T}CMQUMt zy~B|>>^iyhX)FXPdklRsza9C#@S{fM&}=W@sj{H0zkFoA6=KA5axaZohNfBE8v!(@ zBhcZqukbI_1DESR)HP1ezx}NXaR!lq0KXpf+v-7oOVr&Rej;JU4*;`;JA;EM+U__}U7{#m`H@)4K(-O2_FO$2-3bIxFX`OKFj* z+zQW|Fb)?D7s{x*)>8CX*RkW?M{E6DG~VcyRN=$H1To$~$EPwd4`(@oLH)?!4nK`D ztVWR?fswY}pJQSTm94fMKNLD(5?#sWTfsBhe!C8jVvMYjw#ZIdoq3-`g&NN8*0|hR z&~T@yp>=Hema1ycL#`s1n#XrchZe^^WTb$t0oz4^{iFpte*1*0I1={|uXBwzb4SY6 z=LxlS`948zQXUamrxx_tuk%y>Yx>80u9WKP8Z?kvF(ay{{)^8o#K8+Y8KJSTW`btg zG4w!y+Rmz$4Nq&U^}X30Ye#%7x6aBLgHIh_19M-k9d35+1h)!qtwfb=_D^sYM+G_0 zkY4CXeZPwL4wG8d=s9uQiMQWJyS}rjOoqeB>K4Cg3QtCBot%Ot9~zfW#L1wxlDDF^ zRmE1CO!ngmlnR$RgVnnq()Rj; zH#j&jZ^u0jLnFMjDOBFUIocT;t$$_pZ!#k8a>%^v3$7hmN+>p^hNWE&_PFK7#QuFSni(4*THqUE&CVp5Ibvfr!>N$)sT=K5mL_ms=iUF1Y( zxD?S9VV&|_Ekty%2tbqzd`y`r*B6j>LKFq)qwNMj=BI=E^sz>hi~uRU;VhV^TRy+Zy1)*&OMQ zP#>oBlrQE;m+N*2tl$$cQFE?G#@*m&@eqnL?p%`!<8!?+vw~f$%#(9Xf1;DQ<2H{- zv~Vl>w)w&ox%|)*gIm<+(P2V*Y!BKF${v)xFrgak()7n#12)!1VK*(pEB{;;Ar}cE zOsZY!PF4V-u<(MOb_~fAb0Jrm96V@1qOxF@-}`oB$^7ikZ}jH8u@xw%2hu}*U$n8S z4AwjF8O#3ZIk0<7g34N*cxeiyqOJB#4XyP9saLQpQb%0Ap^h4M%?*004Kgi5^ncFQ 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 Q1VbPQ3Hc{^kCER00}qn?Bme*a literal 0 HcmV?d00001 diff --git a/Documentation/Images/SettingsRedirectCustomErrorHandler.png b/Documentation/Images/SettingsRedirectCustomErrorHandler.png new file mode 100644 index 0000000000000000000000000000000000000000..c6f5969ea32fc592d2fe03f9638ffaa198113d59 GIT binary patch literal 37079 zcmc$`cT`l(mp0laP!Ld&Ebx*gBRMC@Q8F|+H?bv4Mi3DY5Rjaj92*3h)Fed#$xW90 zlA*~t!#%CPcfOgqciowLzcuUo!_}Tsr^2qiYuB@%+C}&)HF-Q7avTr{gr}$=qX`1t zeFFmBd2#!c`Puyko-L;@L?q24u)*yLTYinmW2-Mv~=RQ#7lbWK8l=d5wtr@2;Mx*|# z7Z+nY`I0rGMh9BBYkQr}9^j z;$Qnx46NK$Zyh!zzdR<8`|ANJ{@YMxR6eO;VyNVT)DvliwOjO=>AhDKVa;QK@a9He zuM_dYMz26Gf3)@qx@O$OVM}-C$nr$!l3L<=PXZV-2t+P}!blzT{xJgc2s6LSj`@X< zO5tLD$>si2u__ka&>lJwjVVMi;$g#Yj4jh*U`IcRB1w$*^mXrJ3g`y?P?JOEZp_NH zB`}XSTSM*CV7Gd06TLtwhv9D7NMhEcaxwjq;SURv-yb^Ner9w+BM@(84AlHe9xnp^ zjs?F?zO3GlEqg8g^R3148^=&3_qd0vmQ7(}Mw8IV_2$Tr7VF5D?OO46{*pv4GIySl z19c&#-mSSc9vfpxCO+%%y4ggWn_YsNU#2LWI;FTYwK)AY>A4-E9Y~5XhjC*;y{%5e z;m#w3#k=Rn-1Fw^$eQxYh|bO71lGiJdshB-<0TgeQ|c*9N5z92!Q!j-dme&;9vIfq zBi9wp$i)*i=uHNXM3ZWj?iS2i_e}h2GGs|JqS%0KZPCOIg+ru`3)VrorgV3Nzqzkf z1pcD#uRp|D?61WFX@ANT#!tDcUP_qyfo6F80sCnP35Nnv}!kFMfM-i-S}=xglomH`K}%%p|Rlf_(Vi1T=!2xh3~=hq-EnY zgbMGI+F?h$w0*$hUDBB3t`obTEOw5}&8J=X=D|AlOgD@J%bF*yf)2Z?0*%O}?wLn# zF4&_B(WO`C(&SawDW3{XlmSf}8EZK*C==X{Rj{qMrv{h=($ zMX!`hg{emHzy=&j4#e^rdmRdyXgL;gwr6hG`*X#s?X3 zU!6v6Wpx?Na=DpCN}v}r`(7w&66vua0?i2Y9uEBAh2Thk79)abQ{39_pN1wLG)9-zD$+snujypCcul{i0@xVG$s z<+rY`ByBR1*2j@*SY%(_3F3%)NR4=B_oK$>E*23~N!^2vlAL#$#rM||-PTlU`*RlL z>gNtBWTC5#%Pa3q5t}FAB0~8k^5O>N&Fa9eO5;&mrHrS+#6Y(&UTOqKYx~8e+5r>x zK!$|d?o{cV&*i=Vb?fD>m$=u$VI_&FXxx@y(Gu05pi+o#gLAgWNy38PA$K-wD|Lk#)J77I>~_dKPozG-I80h3>?soJ!g6xuTY| zZkq&sP?DxLSRcbm=-l$hJ(SMFh-&HNqo-?*ssnvGD~yloS~FwY(ypDYYdL|jf)H}? zQmh9PzSqwq^}ltFT`TF5VP1nRsX{QafK-@%%LL;62*Ws15FQ=m7Vsna{XQ7;h~oO6 zEdJvC0KC(5uvjmEE5e`11Uwg96&6ZzVH9T2nW7y|+=(>b)|0 zP|@VKeOfupNl7U`^kO~JT@%Sd+5aBaFwAr(X}*WvYM49JifXBE`oM{+=0NwxG$JiW z@y4nscV;KW^JDq-1u-b-8=ya{$AR+lJbiCQ?anWstX`59Jk>4@b&|{ zzO`vd5Qx+S=n>FQH;10n5k@O-2AX`tmDvcDuxP)>N?CuG@!EfHJBxI?(JWYv&o1
?|00AK3I3kUUy^E5Ixv%0&I=n z=^%L09ck?e;rvd870kVc>M9xqGlWB_gI$=RQ%N~I;+|zIRYBN^_^X=F`dCD8Z)JWO z`>2L>8}xOzKnOyq-)yzVP>rp$+}!o1x{Mo!M{wQUP7ol*y1DfgNier3f+@R`+B+=Z zLnr~g7&EGZtfT$&_g8ku{^(Sg4A^A9Q+T5$5q^UUvftwPE)H-GY|TRwyR^NYZkwEB zyb>Ig>gk=&k>#N{*e~WfZ4%=moI5bi?e9owkF?>p4viukhFOafCQ5uFs{QfkW{hJq z%a{e4?2?%xCAWIb{zEJYJvws1^!4b7Hnlr~=M&gZHn z_IhTFs;bKqZ>C|sJn!5&O^68;(Y@XsW13mqalFcS!`i!@zYP%+@~s;&V!G(iyWmHy z^B8gQyOk0L`m9*yyza@JSWt^DF%=)|^6&4ihI&>MX>B~8zcy@w^ZrfQ@OA}m8SzSt zjb)9(G~go<)Wdv5v|`=nJJI{lVzKiwR#W78tW_WQK;|&Nff>EyuBW0Ca9b- z%SGGtvShWjCd z1YA>|x);eaS~cPF_o!x~j*oKiSe?X{w8jq1+Mams3EOdZut!(pQn9Kd(x)x*t?hNwukbz4&z6s{$C6u8PGZnY(j2U#M$8FN4Uv>e z=qS{~cuw?Kc}UQYPhU%4Tj3hd2HWF+Y~X{p(Zm)NmXAYmCU!{XwjhoD7iY%EZk`rY zt#0ZI|88IwI76-tdG1u^MvDo!OPs(BoVrIZ6_yRwopkE@%pwVq(7yeq777L~OM?dR(n=QN9bRZ38ndlT+f)F%(Yik|34h&W$UTvCJ;%4+q_hsmxtw zA4$B+%TjZlg?Brr*;k^59ym$9yo!9aBkW}#HyEn%`F;G@3rhhlUR3Lv%aHXp* zM`FudX3B2Ysk=>#aPMhvDQICOJ2h3()qLrJBHwiHd{A7zNgb9r!xgz+MbySzni)8* zU>tH~sN7#bt}vv|B(@_L=A4$Y$IwopIm$K=NO|Wva+lJRi6Jx9-F-BRzN@iq*D`#0 z!f}M|w@q6fiGZ`|O&n^hik&#>%#XAxUHM2R-9yn7AIH~SvC(mRHU{~1OS9Ut^LaCa z5z4#LMwj_KbLQSwXh2&B_AWUu9Sl$FXA$utzjQ&U(E?NwN795y#BEl}wl&puv>#OZ*|PEM>5+X<_5{cc(Ue@9H}Xr1xk( z^(ANFxj}C9DZx(<=8|j}Wss{_`Lithzs59jKXn$=>CEW1HfZ<4OC51XcQ3gAW(t>( zYV+h1QVnn~h+jTP9;+NxsaxEcVOXsr_&1lITv~7eMM#@I-sGXL z#&y#dI310vv9hZaq}U~AvuZNXU5D$T_RqTgDtEU%s?ii7{HA2ofxE-kfnWK~VF{`g z8f?i6+G!JGtE`C|I+kZLrQOP$%wr$ACU#zR62I3;5^C+T9~$SJ<+lmfeQIM_Y`a_6 zERG21M8=&G6SYe`k~og2L$avcT-K%1&VbV|t&l8g@5B?%KaUEao-$-TXmc-U9iB0l zZbMA9My#`Tx|xIVsqdR__Smw-1(i}4l($GR{y5}{6yuh?UPG4=U4^?5z1Kq5mJA=k zN3(9p7v3084L_cBba5|Hd(M{eZ6Qj7V?F-iT~N?`lqf`%9;0L8HkeRJp^bW$L3SdE zzEvdRPdZCe=)}lIt>) zb5t6c^7wLpdq>gWvA;00o&p*6JWp+FI{NX{dQyxAKsCQd{1}0S@r>OvX|==SPgmef z{{SqjzW_WI1LM1o5r=USkWCo8qai;2`&BFS-kt`iX%ig9TfMe4*YO;r{}Y z|52d-UjXPnIOG$s>aBBBr`8>C4#o(zKHHtVL;TN+3_#Et+ksgz-|H6Cb!Y40fcO;o z_ue}(-o2Jo2g#kHD=%War>i;*hR85@w{dQ!akbI6aMc!=B=AY>etg#D5|hMPmwEv3 zU#%k^W#JGzw%?%(=-K~d$nrlL5B=xH4L`v=UeAOPvzs8+hH9{tIY(bCZGR`7&&Gsk zDrHz9WAio24Dk?IaWV~*&r$>`zCALrTtvI%l_#VxzhIvz=IqJu$q2gUqekdDR;dfX z5f5ya>Gt2;by=Uj|Ddt7I#_D} zcY6vHzAk{EmcZze08K)eHBBCsOa{ww_wi@ew#1m7TnGXh2@E)gIyzxhhPjb zmin&YKWj`8&$tt;l~h#6!7h!xiNEeHADSunoECnMeUo;4$mt|lxyoq-GigKR@xFI(zEZx&B$(X zj9MtT^-{twOnAc*v8?A%xBk`irN753gEg2=x3YmEIl`R|X!AI3s&s>reJXereM)DK z`vg%EAJZC16!V8xORe0MVl6JPRD7cG9vAHGs2s1O6LQUvRlu^-e%86|8|2J+Rqv2g zh5tMwI8jlGX7nKiVrYylE44S8<|)IiF74MREfF0LFcgBMDlRob`h%t)+a9}&|7Apy zlhCrM$Km*~Uq~#v8Xdx$b|gA6n9nv?tlZM{Dz-{S2$FBQJIvs%9|6QTJet!zHdKTG ze&NshFM|^Yq>oz?rvz{n_D~!be^`}N@`qqmmcWw=MFT(bV$AeVrknjsbuKvIiHve@ zB?F7;VBMyj5gte}g;r+c9v{chJTNqnmc7c(Z=dmXiT1xod#t>GGy_p-`xLbG4yJ|0 zj(dr0?Y!0|!HMqY33_T`2ffvEH`fHm+gBH2zQ-6Q_v`7WbXq%E?nru)E>43SGL!F8 z%1`Fkhi#8{B)$aR#6(m1D^j%{Po4qP2c}8T;!D?vJfbePI3xPjpNlp-&U|DD`umxJ zdl51(*PZzvV!k0&k29rjS4gzm9n-axQr@2{t;kHgZob^_Dx1TUbM<3NV`YX%{NWwJ zV`S9M%!-WG@lo;kHNRcL7&NV78Z9Y(| z6lnK+WA$YF%J(`BLtF-RG5jg4ybp%9UiCXvG`9fGzbpwT192J9k1HU_uE!C7IH$k= zo6NTpK6rJYH8#PF9C6xokcb5WB|qJI2(F^?->PYPef!8nr-y4GJz#5uwSrQ@bLBT{ zfxt)Kme|5Ffqa^!@osaaH2meDQgsWquRDV>&=;C zqRJ$CDZDykQ5Sc>SKad`JqIAri_v}&FuRs_(#qlbxJkgeN}}B4)@daVAJhrsoO4H0 zVMiSs6?JEs@B6@e$L$k5tA*^=LiuH*`v)d>PHKQ}Iy4-DbuaX$jz!+Re^;(&lG*Wj zIbGC+zqf0okS$CR_<~df{s64C1oTj~`NHY+HVvkh5k>GA@6}^|o*}IY6u5)33&Hap9XlRdwo-Np3wIIc)_K69~{pV`D~au zjSzS=D|>`sR3{cH(E7K}qkg;{RVFs&_JwJiC=&~<4A)8c?@?yW{zZUacCky@$^#Ub zTU7~RMD6J2#fGc)kg%IPWizOjsNf1D=7%`F+12A{p<83(}`|>>}j(U#Wjxm zGi~bV@iQGI+nHW}Em#&en80Rq?S$!wA64uax+%Jx0}@n?jx?ikQiaxAUIRQ(OU-7v zo#-O}s^K1r665f`%A|I~tP}ew$E!Sxw~|_`jy)nR>#mPqFmv=dbw@-(=L(EpgdG!< zWop=|ZV9HstfjT@^E2X}p{%=&DRm&!dUxTPF!bclw;t7Tod6~1zW&`Xi;b#u4BZXP zA_<~5oGbq3>&FW+HLua)lg87Tt>T9}IEHP|b>&vE5i$Y!LnwipjGh$E zON6hP9D_G7HkG_$JaB**d`IYAsE58>*m8xzBc?jR&22j~+zn{;2uI>fxW0s#QdZT^ zLBo9!@cfu=dj<#Lo47W7DOM}`!N$i-55W9zYohb`K1DGaz7%c0t|z`vhJP6eAFXV~ zW-@ER&o70uzb$P&rcj@yYWG#N6$QFQfV>dtU+`;t)@Xgm#DaA-8!Q+y^eBL{nBoF= zLuM?l@3wi#x%OD_?I^+Z>?1wwgVY);H_ez7Pp|6dc?)ciP%XQ9o^mx)mt1Dt)mju{ z5myI=Gr^qca&Y{CFR~jc+B6Jw!&Omd5ccMbbO5P zg^<#Hu+iMdOa$Q2U#_NALdAvXr2?r^KXk5s^&_<+@8S>J*!iO6=VdCR=K@0Ch*dVBO{7m{vcXk&mtJNmy`KIy75aYWw0TKi4$W zdn+r0S)LoCrE)twu-xVCWR$XDqpn)F$X#~x>comoy#Ym(tGaP0gR*>}d=J-zoGtqe zk+^?hPlDg&H(Ga(2jHBN$47;@{?RO{eCpq6-rWp`UUjYHWl~8ge^&DkJ1`t!21ky@ zwUR&&5|~Z7tBt59pN)*4KoeXsZh>(ESjdVAveE0G`?`Md1P0Jew*#(Ua^vy8xrar? zIqIIBJYdoOsv z{(UNoahVuF{>#(Z|KjlW|75WfE|~L~g!d68fpNeLeCOi(z=xYRGfv|H*29sV>eize z`OK~nERd_MF=(J!J6_g#+tmdDwHw1lmI#Zw#Fu?e>eH1I=^C4@EMp`DAikByHj@eg zew;Rjgx$EAvw}Ynzs!WT+1RgZ^X(AE<%6)sGhs((*sXg9fqsix15KY2B6l_ex372v zE@x_YtdSAYNH?!1pyDml*ngrGNeO`)(VMSdXDV7hLj_c`1_wG zykzpnPEUz4pUa#6AXVz~CG`Q=zcZU$%HfAQ%3fMnGEHquOKX-c*Yg4Ry<#55eu65; z<6uV>;-16t5g|p)Xm4b##Kj+7dKZo=S>`yL$Kxe_v)P2&Ix@A=auSw$RWRjnMaQhsUrF>v%CK?I)z+Q6LUEY9EV9dL6#XfmZy6e2mfngD!D3Q>vcj zt(wHvdRCs`usy~gZz6s)D^ahOq@VArwTG{6jTOHZCj&E)Vr9(dZT|6fm}YbY2Yk^N zk}^8f7RN`Sqh7^t%+0%qBa-S$i4exC70gMx2Y*x1!E^SF0o%j2pr4Yx+VZT&SC(#m zboc8BGuq4SrFPLK?W-YyG%M-N2XKay&p!MMR92>ZD%j77Y`n@dX3kJzX{t8yV+$Mw z1$PSt({l`%UEZ>+Q(z#888=`D&8sIBVlL>99A}4H1SbBSFOf1Vmj`n@q=-a`SM(gz z((eYOi&LWPf=j3o3w0MyAMl@FCu?#-h%!EZ$@7h?AQ5`5JeR7P+d20BP^`Ct(Q=p@^Z9v%qp}i z;~907w74R4|858te3L^9mEB~6a;53k9v17G1Yi`dr5y^*^~;C~!4{8agf5D{mH&Lm z3kbE4)g#fe|b+d;lq?8EiipKO*3ALi+zN|I?KG3%D=G586hyk#+a zGsgU~QT-+g#SnPdP%*pfW#}HBfc5YuLFk4zios&o^+10$9-%f4)8Uv9)Y9QOqlDvk zF`Z$-^hOE2l)L$KuKnTtcU*k)w+s`clz;t2|LyB6q?h|sm6Xa3sq*`~&Mj`0&{$wGY6 z7O9D9xADG4SU-93W5m0ipxl!jw2*bw^ZcTIi)>+TwA z;#$95C)eXiLc}|n;=sy%P6_{u5NuPyZKX_~m3CHW!>Z}^psBzAxK=j#`$yYs?Y?Zd zG}C{9PhZBwE?oby@y!|*NcgI$@Y$-D=;5FPwE4~15w*U{_rR9<R|CgkJ6u-SzT&RH#tJH@|AtZjS1<^hD}VfcHcYXvsCAI-7SwVs9&)MhSwzZrYy^< z7845-#yGs+!DZ$61qy2ET5a&d?-_XQ@*-<@9lOH67)>Y`FjD&SDW_ZsrJ-9vz30Ot1~T`Yndwwr;+r|U3MUouUPBqvT}~~ z<5LhSiysS~>=qGeaa4M2LCmRe&)@h^NvgCdso~lCkv#lZrSjq~j+Oj6v6VUcE?=j$yd zLoY#+65z*(CC$7FJT$ot2gM%Catm#R)~oa8Mr@nSdx|8^U}p|4gV!a~%A+qRQAfFl z5jx#a#cl2xH4a~4`S#B8uzVa)kdzhmsljCIz*c?|+k>ppQIgN68d)+07Mw?R6`VLk zz7xlbI=SB~lo|9A52asuJXS&LVY3Gs^Tc)B0$o8mDcOCQBW{jfbP$Y`2RoC}{l8%7T$kfb2ZOG!{h9t^tiYi@0!)g)rxxa}^W9kq z^O_FaNxa~9!~*pao+T#`7@qx1Aei0Et&g#o;UGwpyd;# zvx1Qp$gJd{r(Nj?kVm=sD?DRr)zfk6YLkaEUC3>ll1zL3IVh;$XJ?t;uWtErzuoT6 z3cvfd)IBM5@+NVqQ+3PHW>4Wz7SgG5LuP^4R2SjhaHXCLN zof;8;B4-MF^LGpT%h^fS@uv+ao9}l)Dg+HU?yU$903$LOXxYr?TQXJg-vZ&viN9OU zt>2fprWD$bYjOvUYuTRm#aqgow%pA2-I*JA9siswA8mUFXn~@E*d2*D8i|9|xLrIu zsREfTE#>Nqf2xjwR9a4L->Xl`r}R7D?cZvwb{;`kPGLR)MH@X{LVhx4Mnhhrg#Fe& z7`0W80ePr2)ITTc*fRZB&bAD_tfe5g9Or5sf;b;3t>)KFz(Am3m2%uW0Qra~<=}i` z;%s~C>+Or~q}JoYK-Zef-tOf)2I7fFg@@bF0I#=DTOn6egR!r>I{H(;n+Prl*5yId zh!`CNLcX(kO56VQ9`GGdZP%lvJYQf-(CyqYF_<{$nR`z` z9+Sr}hi(HgTF}?e@f*^BdUNrlHm-f^cJ;h&nSDzayO@+ux^lh`-q%-ZE8Ty~24rZ` zflYk=o@F<<3+6hRYZN-nV+52Iqyp3}2I{uprBxSzKnJUn4$e5tJ+V)WrNk4f)z{f> z*pkbbJYK8b0)57NEky&c&gZ*pbRt!smleE=;*F!0>=FZsdqLx}nAWOpaXbgiTax-P z35$=Jz@w@(RHN+kO`SQ>@i zie)9{1k>xz(i4=wVe_p~kAdqW-n18#p{Oi=C8p7cF?$i*5kahIUaS~gX7gDd%J+6u z>m@(kfSzd*S3dhs{f+Z2{|MK!v9+yeSVkjG-uXo@2 zmiPKY%Plc0Jv#5y<*e=5lNN%afp_nkKI?2d2W?nfIdnI;Rm`{#tCs4*eXh?|JebTga*KvCPb+;#_Z3HDE8bBqhO&A68~rpd9j{#O-5PH>&;v` zJp&qVKOg_xmnLB9e>56Kpm!;PQCGL}#qkvvD>g`_2vF}ZB|-)XswwsJ6{^GCKGinb zOOANy`M9ZL3Gr$|01_XQP=Id=ala2{%~v)2cEY4;nxE;##&$@JSo$Dr6pCX*rJ~*) z7Rg`-Rkp`w_k|d0se=crN*l)Rit0hm*EiORYTcJ37RK^FwjILXY)33ot@BOsE`#RTAzALS)i zIEKU(m0Si^jWuP)KhIr93y|}cp4thKA*r1{4LiSTs=(8YiG7nu1*L@IVh5jf35cS3 zQI_`ZoeE(i(t?cUh-`1;#u6r>5mAIqeg#y?ujfpIAI?VAsaWeVVt~3Jmakk6_>!=S z)S~n)Sdf%%@HcufHKb7VccyMSWYk+kUynvi-t)k%z*mpTYrf@4hl&}bhl4KZwD)R;>1i8DwKVAKJ95m5!YLg(WKd-G zyec8CDzNd+-{_u+E(r#|V0z1BEJmUva?V%jEVNPkm}I#PvFU7Znz~ZoLeI>}Vmre{ zhv$zX+I%u6s)oP1e)b|}aegS({+0C^JxL6%9cjPmQQI>{kHe+T&gKD+LgB8IDvyz2 zoS}l$MeH%hzd{`|_WyLwl z`$vxRjf%j{%IGYR*Nn$FCi$M|_HVsB4c2{L*)yC>cnM^Fwv5t>7~EBEa2VD`vDc5f zRmyShkmmJx6>F7+U$vCTl-eT-IQE8yCk=LD? zWw8B$r<8@yl;SoOpBJ6^?zH}-VOyI?Op8`c`@Cg8PgN&V#Z@$YJz4lu*6!i6d_u@E z-;4q|!ebhw+>Cy`&2sVZA!j3b*D%}72#wym9*zsX6SYL_)dAC=EF&-e2$N_y=5>yS z>DSngc0^J9qY>^SDOL{2VLk_`|0M{Ir~>_Ob;K?ERx#F6nt;h{Wb6cyc@;3C@ijGT ziAE}pc*dj^xBhjm}&vzP_e}el<;bFFJ94JWq-73^cv1(gv5LomQVZxAETV zp%;8b(mpst$C1wTc)IC(U-WcNhFWf^c9+ZT^Y%!17hP6Qfc+BC}{K1@v3;; zadpL}~1*Ve>)IgbPIYULQOMv6F0Xly!s$eEybY#*D!W|(hO z5%&_;MV1O@D~q@npGBp|oRf(D;e-HdS4#i8nNr`l=Fgms*5Im7uPQlC+^dn66Z012 zmFM_iU%Q$52D*A$rZJK!5PI#}im6uKmcTwVtt+nb|NJ!P!;N~=bIEFT11oE>^wNRmhCgnpZ+ykaRcI{s0xwTsTfvC*%roGJ73-F#7 z%>_pFyB&n;ept!kRHt0D8#xMS-b^$oFOxeJgh;n<2ksu;G0K zJAd!o1*$Y~{2ZleG&#iFcj9%-2^pK-ZpO}9A#lA7qW!;>&A*hdh0Y{I-3M{?Eg}EX z3)}P=Bm{^M)R%C4utjIBkhA?Q(6a{Gp8x{X9Fh9ny|>@Ct%ZJn-YwK$G&~TgyDA;%C?`u|&V8H$G;0Q%ksU5Mfr82?BjF19*}@_r3lC@Zj$oUO|}Y z`hDf=_q03VfagSfj!PxpczbTIdBjkkMM9hIgCGKDh@=6(v!$ego6QIm=kIT~?t=$1 z1y9<=I>*J%hB`tDSEE~wLkLNZn{R_4LjP7F5F_kgjlv`Hn8_-;C$-@#KVWil`WT2C zNX$TA4?mR#8R25J)X4rbnbl1FT?rmjZno8|93ZpFpEZ)@_d{mJX(30)n9FADPgtRG z*m|Og&692^hnSxDf|jwQU(H^Ac8`<2BkKDsZE(O0C8nFU$+?tUWQ8~Wf?RWku0G<8FTui zZo?Q<#*pq?Qa2+%SiHP`GA8~;YB(T%PWTHUcI{)lR1q_0k{VcDc=_|4rwCo*Ij4gw z#RIwG)n#dq163=_7x1&=NaJo}kLt>fgbF`;Uwd>i9kMxM5ncR&$3P)OH43ZesuycP zIkDVu!yd_u79!SDK;0((0W6t`hFmv!(;kjWAm{30G7)-xUJ)=7+j-9L&obdXl2T6i zb+6epw8vF~n0UiC!A}MGyjv&DreWv%`w0yl4t#q{MQaobK4lCfM>-Z~=#h@X`&^`+ z7_o6SvUKG`iQ4fin%e|p%P%Eph<7uPax1*3Exon-;kX|AHd8CCT)TG(PU*=S|Yjo*!fB z5a}LMRZ_AG@A6r+V`QoGk)>#qtaoRjY*LB5HZTuxERQ*#tj~xRhiZE^Dk)t3`*>LJ ze;}G9>Krh9((*D;5c6K~&7K~OwUA~G>pzYJhd~kY0t*+6yjNGixgh1;`Bykjfm-aN z%a#)Q$6@g{G3d&*Ty3u!heuWF@y(mrrSjUJ^cu0@t|7>*X7z}Qij7BzAPol=2&Lfb z-JHk(-Jc;^?rSQ8CoVy ziE$w6=gJ|epTmUj!ZY2;T^#mKN7&{TSuS@cS@+YJSU}p?>}kad3)iu%Mh+!a#VC>6 z>-yHdqs(2}4?9Q8o+%HxTI;a}f9hvhd0iPAvZ0&&lHf6-ghJ(f;vkRIqhsMQVCX0X z6mlC$VbtyFTtD9d^lM3iI4)~F&54}z7;GoG8A#)3flTQ5DiNLU{VcKGK{{U188is} z_`;q`ja`A*~ zp1O53y;Nz@X2U*kV!igjofD4`A=B`!DQiYOV%+VIHGId0{|lc)+?12BC;o#_&hWq# zZ=k*AX3noNIPRYf6 z7fu{EGAPvXvDF2a|1P^3%|kN8zrcZaMpe4$X{f2F+lr%ZL*p3%*o6{$!xMO7?f-o+ z6sE%vPPUSFi2wDay&6W@wWW^0r~lT2FzFy8ZOfvs;JRbeiTccISP3md(Li)~Sy_-z=Q_HIj(n${ zN8v++fDOd#@clzD9{6uqzEbb`D5qziJsINX@hHmmjcIJ6K0}QyE$|LQ<*gDoW?f%Mn)Y zFL?5_NaXTxPn`6j(Z4Dsn!^%fXBN3cHsc1~2gE05)+@dW^C-}$A|*IE`i4vnYgU~wL@pRe zfgE-=%pa469=SHX68d_GS|9#(uqjy?=94tk;ygR#e~{m5?Ypu4^~cxso<*(oRy!tk zg#BURB8pq_>G~IC@vZ#un$fseV(5FdYK>7~Fe2{E{sZ(xhmK6ScM3oNfZ*~Ora(xC zdp}CLXyZ`4zymAddOl8P^E}`~#uU?vuzE$xavOUn0#pOF6c7deOM~tN5@l+DU=gtb1gi+e$mPjP@ zd9KAZDWPt6V_ec;+9ZrfuV@`v3rp;=e~`wO^nFsm;4XF-xv*)jNY{eChhnk`yYlUj z#3LamCeE^FX0^)uyvL#&ozb-9io0j{bfnB@(ZcI{f~Vr7I;v^| z+`M3#SOIss*DU9CxFBfo9C!F_gmF{efQ{h1B&)}XQHai+UILQw?PG?UdKU0$^N7@_ zQ3`OaVpag!sfA5+T<>B^$-fD6pQkG==bb6qRBz6<9(t|`KZ84X-HZ{(e|)M2)0$AUDt9C8ByZrRII| zNg2WMru~9w`y_JLm&8bzP;j+Tb1a)D{+KnmYg?4zktwC7CPb4Q!>g zWmi-t$DmK1j<*1RE*C)*3XRByE69{4l)lUXt=N} z7Q1L6bg@WH@&4n$6Bd<_N*sx8Pp}S$46Nfw5fK0*W-xpKGW*Sm=~k?(_Oxd&KJH6x z(NEQzLw6aL&Yt{@B+9^s5K!jYDAiRIszp7gQXn|ko#f;8tcmPnDlfkLU_T`MaCkej zFatQEBG_DHb-e24u@K3Xb{tjI5PLy+EI)4f(6`-ul8hs@yOZ{)^gR~hF(v{6w!chw z@NUG<*cSRytH#>s!FKj~9ZwwPgPeQDQVgH0z8TjPRQwvWy))xF=EMqRKi0kXQThlJ z|8iC3VtYl!HIR`^<1sW&nl=38p5(;i_`+qmXLcomxYu^FDDLJy8)iGv^jL&t0#iOB z7oO$Lxk<#N+iJKlZ*f(Ueai_G`vLY{TFC22&#)qOpXj~uixWzOJFc_2u}tcIv{Y4@ zfJX%B-zUIc+r&3Kl|y-;@0I%Ei~eXfEQ za*v)l#pO(qYq>;uTfZc$WzWh>!$mXBB=oF8JYi222x%~vM1C7#J6|Qq__Td<`5!1p zFRER(9%|n}E9(cb`>0;rG@vNrZGHq|^L5kB{J=!opCc&gv zIl)fGQ$5Fc`7<))z4VmYX7&8Qhjo=0SiTo;^S*qAD2Ej8&&P;kr}}+k5@WVRr{~SQ zU1JrWrHmU|w8d}xj+y!a9P#nzZeRQB5mBTHxzQPpC! zu}_(4Ie!tA{*6!TdgJ`KRy_B|2}^ke2;*P_~m% zmQg}(w{0HqXE=nYgF(iD2T#k!JF-ZDs)#ijH6#>Ckn3M=hgi|6BQ&4CwIC#}1< ztN31SvNp{9ibh<+_1v|FDZGtGDEc z_eQFRJ$Ko*(ubdQ{mtTXYw?tb>=M_8ncjllcjvw4ZvTAt8w(SU({TC0(&JxM_aAg3 z{>FJJ(&gH!@XBuBUc)E(R zORxo>*qwd*Gvm83>fbN`j~el#W;{R+8$RH-Qc;ED(d&z1*|z+N<~JDWXh-xB>>UT= zfZDr%ah8c(#;NO|G@X$5&7-aF1VLr)QE7eSJnVZi&6jZa=?plL zGi%rA&g6H$dBsJE>x8sNqw=vLyDD#OT4V&ehy7peeP>it-L^KqsHg}i2q;y$(v>D4 zASfzQrJB%`5<-_QT|q!WK!JoN5Tz4}gwUG`NG}4RNRtksNpAw*+UR-Dd(J)Qjyt|O zzA9zZ`D=SHDH$aK#P6#?RNFQHKE%zp2O|~7 z1qxbJdp7HWuM4IrmJwA&BBHz7QS@u0fq~v|v#gXioXEPqGsGy~au!`CzSsU)Tca)u zr5QFK%9Lx4Va|=^3E#1zZlV-P4q3s&`Q&_SvopKVsyYl ze8SJWaw3nc`W@Q!pq%aXln64_+W4$)S>q{LEQ0QnN1Y8_tj_&=?7%?}?Q9A~H zy$`XUBvO0E()@gwbhk5w%PKTB4R&735KM*E<~5ZzF{zB_=JWz99+A7WrqrZ)%HE1~ z^j(wpM>FL*5<49UN4orcmDW>gGBb0t+oEUFvtFy0GfBkXAn}HZfNtCK`sw1#+*aOLtbHvmX3y}ox&&Sf9ESF?+0FE?iqBTk*?O7lU}NU7i+DZH>0U>T~g;+tj;n`US7_=w>O((t_O zctR}JlFUZxl(!(UR?Er!rw9u(Z;-++8Dj`3tw8OC*W(D96BzYFF$PB$gEg+C*Wo=I z&dVa-D5v>(x;$2h8%0rOABZ`2Iuu$-8NZ&pGv!JNb`%ti!*Z6$*%6kFq6g~>{Ev*q zh;8~6PK3K~am&^sU=jx2gv>$^W`Rrr$h3zfLf~e{N?U^T=Acvi!a%Y8(r~3`AM_&H zuEbtWdb_fHIq7}>w3YF1d+`G9)(_?5;^0*zFR{%}V9oJ{j7WGOW}S+Rie=6E=;3># z;@h_Mnl*!bhlwe8S^IP)5nLcM8LS2a!gHow zc8dnF`#ni!LisjcX3Jvf;N|8)zyCh0vengRLdI?2;-17nS@XirgW5Yi+kWpPx+0UF z9HdLNHkE~!kd|@eqAd1U%cdXNvbKnGTLgvLVpRV&Utj=DOyexFoRiClp)|I;LxWzQMM%>)1`Nf)HtA@)ngBlbu z?X|Ice3Km?x>-DCFSa~M3tq2Bmh&WPtOQqwZbeX~`vuDeGo?#a-c`6HG**DulKvTW zhq$>H^-8ITKX{E2?(RQDxF)$l2sg;%VXGFSkHZ!0T-Fl|*qEKn)hk;5pe)X)X_UxX z;6e_kNXicLerOv1>aQ!;#@+u>(65zR((r*>N%G|9r=F@=r3R1a$7W5W>}chc3oWbd zro+tXHWfJ@y-Ug&3aN+XedeB|b+ggta1}Ak8kFhR?h_7jU02mo8rIMc$LL79!vbj3_h_{7~p%I}YMaE{p?&wtbq@wyQHdH^N1pce$xYGKnZU|04fQ>wk|W?xy$VM~W zs6#VeQn$`X$+zW_4f#+UZ#sh^_}+Q+QVf}ZSm%2^at1tuEKDzZ@VN+40uv)i2&d4-<&O7>j_k0c0p3A$<=2xUro_)L$sjy zdUqoNv9%ID18ed}w_nEv+~h}g1Ph2d;!+soLu?}?_F#sG*%;u980q8uB;xtQh9b&5 zF4#&$9vSNj+MjnUFi|5;>q{bMZ?{MdFJURo7@WhcbBAhlVTq~9Ht&)u8N|C-U694f z=}ic}^tcqC$?pDBMH&=xC*iJt05qa9fHm99JItNKPmP+n%#$(>nAw1hPwCfFMWI(U z_dcW!N0Ay$*RzA7ueP2{hK)YC_Jm+gUp1hWcg|Hm|Du{PuGzX^7F9gL>j$ff zJ&h?Y2^r`Pd)M*vh)gkEUa4z%JX7wu=Rg+8IUMyfee&zx1e#8&&gMi}nJLdrYgrhD zx?jGA6(=tDFtM+VDUp9Bhi&R#s zu{S!+fl3_SfVG8EutopO)o~oN2o=ts!Hz9)BR#gQ?`e8G%I=kp$ra12n*}QoiO;u* z8(!5EDSPfQ5)TtW)z1?VrDRjbxqONO`(_E6=h|`iibRp?1?w`Sf2su#;08oio$nPx z_`GM8joWzLib>>^BU*4MJ#N1H1sX=K1eQ(bT6wH`%|?;9q(%&To~UNz3uiyW>Z>E> z7u^fK+<0leuNI0o@Yce0ACGKXe2VPGC&`E1Nz305gex#Vh_?$nApOzQh6HYVrfAc%5v%WosCH zi*Dn4*s0ZH$aO1O7DbEjKHTG=5I1~8vU6FhIs8)I2V0K0q0oz#Jub7n68QOC?HQ|H z`PkRYJVin-~=m#?H`2exGteNyDzv?P{C2 zXVA5o0u`2sx(0LaTCn4>#lb9iW24>yRKiFKGH5=(Ir-F z)x{q-ls_*q=EZSExvwr?KqXAGGGbBNE>flCx}6L&)|}j}cfiQMDOs)VuByd7)Ar2D zvC|VWDr+a;t|Ql&TyXQJpBJEAN*t+IfSpY|H)CaKpUSEBg!4{#&a8iye1Gg_PF-QeHBsN?Oa&*^zIk1M?9gm=Ebm;GIP631$V9m z4{LkbbMx;^IdpqcCkT(Da{Yr>)3jfSE~qDlou(DObwxx+^%x?$BQ2@%S}HKbLB6(m z4YPJXi-%2}e-wfv5_rE*u6)NJoHm>>G)P` zpJaUQ17u~06*s11!G=nHgW=M9t}L`yENE`%+Mkyo=gWrGsQ(EJOcg3V#QY$;3or~-!%yi89+Fw(VrT*HAXXHL>st5JTcDK5V^`xMZ5@EiPWW7Y8 zII_TA8qu!TiPey#6qhN`Tx3jIDt=bM;7P6$oJk39m)U&#FQ&h-usf#*rypbk%x3r~1yT5Ko~_TB>!Q!*$xB2p{L28^7*-W+iwiMgo7j6W(-cxYt~9WP1X z0)zuM<3LStzMp7_VZrrQqpRc^PSw~4O7S{24m2%-5?K1=M8nOX9S{0V?S=EFgvuRZ zZ<5Exu1Vhes#9#5vO5)bwRw_-&t|AmW7tJwN|e>} zCKiSE(o9Ppag}Iqf_7UN^=5DY%;c-Oi^Phcl9oFa^Xy9&z0QRvi)*nIku(Q9N3HTE zTJDwFdsU4b@AP?V`%n{g5r!2!iK;_ESDJ!WhJTobR3 z6)gNw>mb%&Q@tinPV*9D{@6GqG&Iz9%l3mOtnIb@T)OX$1#5_vEZhsDruv0}2L4c=NCfwkm;Z9@{98%+g(%nIA)hN|3mz~rWP=&l5@`~9op6xpn3jJ#pNN$#oxmEIbr{` z3~YPeoAnTu54Syz>W@A+{2BwUq~cnbQ6AKkaZ zU#jx9U(X#`$8BH|_>b)5jI{A~=f9R$PQm{Cag3KfcdW~;v1#{R$-b-n7;k|tC5qXJ z>uHUh`d$sAa*|oG|ZXJDLIgib+2wtXQR+}@E&T8wU>xtg% zESqf9>9i=%n@hjoXWi8LO0@`U(C)oCrt+ofQ8$rEN3onA$;H#AuIg~A2;Xx$B}=9=~~cFTsS8=u)_ zS?=rBC_ajl@H48pFQd)3WJ16D02P!-kM-4>@rchETJLD8nUzvuw*M?_I{abM%2@2N z*r~3nA;k@fE}W0K6fL^Ddllh&y2~V{X8Y7=3igw$RJsTCb6fGYENfvo-4UK z6S%gyyMao=tY&K@SI`NOiqR%#ao(vjF$TY4bWC{8TeIa461v;r2r zrsLjZIVs1=83fTwMUGWluG-C?yO%>utMho3Tv)@TG|Uw`5|pISDvIaf#f9a*@Qf=h z*91VMg8^@n7aZ2Vlbgcs*_Sx8QeoP77tpW`wG*A<*880`dmVx@q;!pWutpvC0yQ?x z>KeOcIFavM4z&#cez>@6bp1h=Q$npuUmoD&uj`%=#~)(N`FdsSNvx09SMO`fsiL{( zLg(6Q>k;*1kKesvuy)J&BCHy{Ljk{H7?tXD{;v9(k$XMwZeIM=@aAdJIVYwNU5D&_ zHQi8*xhvC@*(~CiJh|;**k#xmSQ4j0)mzKN1*P_ua@T0^^Ek0w>&b}nu_XIsyR_b#<$*SpEGLSpg{!lyq z4MN17ue3Y~rvZpdci|hXI7~q92{@ARaLOm(x*kH}eg!1~c4IR7ARSPo>+LLz>?Z*DCJ@>i9ESqKcoix3 z0`k3&{?k#AKHl12kSF(e1Pv8@kSz{TduT#%#ot+2S60i_G-eC6q-OSxKVJJcy>n3~ zLJsz?yneG^&tR?$S(5DARLrr9WT=~SiHC^BsKaP2C}jqa?(QMQaCGkSsPaJ-+F7Pp8;A6 zV{^~H2h<^g%0WSE3KC&;P^PHr`%HsHS?P(6?CVKW$z4q1MM&H9M;*@rnBpYwseo)T zl8-<8*IVs_0JYq@@?kAnKiT?GD0bbHCW>U1bvCOn8iHAqJau133HdIB>w4YuK}`OK z8zD7Ol6j1TgNLBTk3R&bMp8THLYB)W@h^b3EeBN6U}$>y)Ig?evO1G$uGqZ zW4J&WB|H6-Me8FU?>0a+j_RO9jrnkZEPwPh*ZJDE1t;mE1@zortjP3M{1S<9-h`>H ztj#2cp6rv!aktK;U$E(ZJej~WfM7e7Z`%1hso&eQE48mdkbJ!UCLFf?0Tn(-H`s6r zQnrv;MsoA;F~Pqirw?ZWX$s*(WIAM{f7JNz8;^X%Z#NT)_W(o~uL2=4f3Mm{JPZQt z{;KQya{;@i!gg6&+0h)6?;xH1^qs-x)*IHhFZ7H-uZgYhgDot-xe}1ZTyjU3hFp3X z=nQy)m=0@W_7*TO09fnqjnnG0LT8#xFQ3e7a*@xa>|cL>*iqoCp6`zp06wp&qa_jM zsw$d{XG1oc?nV3!QVpfr&isaLr{v`UJg>tl{o;=QWKz^$fY;DnueTt0c=uo6;m}ES zW2~QM8UT_Til*BTy>OC`_&3(i{#J7eou#jLhwnT63tT@5?{&|yLHbQ5szx$mDfu1bhW{;XU>tsUhZOoO6%N)MTq4Y;c7Px;G z0FaIx$|fK^_&?hx;h%XyA+i5o@6iBoXlC?a9FiD0*zs8<*U>N_D+h-{6Zky6(e^1yq5cHaA^Ie$KwwXP1=E zZmXMqam05khOhr%@V@)bGnDW4M~Q0stkBLXv1m}rfP{!6?g^>pkz%78-tt$OZQPhm zy?wfKAJEp}Lh{X8_dBs1g_flYeSp1aWq;WY5Ld-WES!WV`Tk&(JE)hCU2h?Wm2S1| zPY=sE)r{Egs_EKIHtSY@W^r|2px=y>ti7nLKcZb9uudwnb7{y*kfb+uACc#DhBq+H zXk{9kbQ4s3{z<_}6oc0;n3&a~NgSh24CCGVmd2fSEuo2fm@Y@tNIh7G8!U9Li1sY%Cd>* zytkyowmdkl=zS!HW36}y? zG&*vP`Hb)Em86L*+R+;~;WSpSjLMRoud${vD>$Y#ZN3npV0zv_;ERYrFET#hVEjF%v1I7#s7$6TG*p3(~n- zS-x#Q8i`Z7l`vHRVr617ih%P@5s(>G@ARpv@6SjY;^yOoyw<+yyEOJJEgozh%&nHy z5lpH8GU4|^xp3{y!YwgZTMWgbNgOU8b8VxR}uXR%Z}7p8(A8o+p~*S3-3z1 z?v(9yB3HGyc*V50vh7havXzsG^)y;A=|0chP2+ak=?(8BmxG1z=jtZ=cyti#>)lS) z&4?v`>pSi5rlz|Z+8(BBVS;)x)xKu4#DO_YKr9+rEA%e`H4>Xb09kM2v3 zfAD^;*XkDPuD$eW;RUm6b}t04-e>F?9{=W0Txv4XQZxJy;0J4Nd9vP9VurY%Q{}q3rTWoK?%Um-2j8U(O}LtM-}SaW z3Sc%0rTu9oHd6ULIwjbs4b3u8$xGEMgUlp&eIJvrbF5%L&q;_d)E3h-TGPsD=t|25 zaUgZV)k>|>0lpK27C;l_Si)s3p5>o5t-uu;wvZkAvMG64wjt)O-Ym*-^gKl z*qJ>q%je)ceRI=B{A3Q!etSZXvYvn!QW{Uw6P%rOZ}0#VQ+|N;Z1d-SA&*+ZSFWV0 zy-z^5-HpB*;Jd%OcP!_Fu3!vTrm=O}=fwaU0izkvAB(CtKl7D+>r9nwE)ymPt)|$( z3zKWcI*n+TMSBzZQc^ro-XDepzd4v#SK0Sh^_R(AUl^>i=ONg4G!2UoEwAb|zFZB} zRy-#p?N78!NmF1J=bf`(sq&W4?YN`<$L;ppi2~tjQU1F5Av>wrVPq6}J2#(y*6jGU z+A$wUWn8$;=FabZXV*5sGwSm~$PYE^esi?o92NncL*v@($F z)g(n|Y+jYk7IOU*oG4uRG9W`Z2;($YtQ#~$Ry4aYwnl@><3sBxVQ6&|lyyf*e z^)9CBt}j&*ge7M$sIN zA6kK{0HGFY_s31TlWS74vK!XknZ{?e`G-opnZk^MB~q&b22EB~W*!w|bgta!8o+b1 zf^$oG<_Hm?>fYd(rnkR2g1g<>*zT{pL6Be7oY4`_O(`ZJxd=`QkBx?AxlK>s<%PZF zG+jD;(bC>mPoINt^kGS-xq^-F-L8}B6yhW2J!w|Hh02fM$0Y}++71?vk9w(c*mkfg zF86=@VJV+KzJgu21PV+1)nv=;-&MT55fN8)eJO=iA=7i`u~9pQt9!zk)yGE8^Rlh6 z&W{`&N|D$vXRb#$#Z{1b?OlKGEaTsQ|9QWRk}NYZs@brB_*hfGlT5dL;;DRdEvZwp z;*g7jW&J7RNOD3js?2bN-ZS&|^K#{JYr18QZiyCU;-!4K+z(ISXTdI@ZT(hF^(e0J zCEx1^hEPr}6e+)iCWGU7%lqk$Ps?CVbC*GLI&WnjxsBRxd^-Q)SUV=uG|6uNxoj_R z0ZFn7Ig$Sf-`BSD%G{D;*`=KC&vsgP4W^$Rd*^?TURow{GwRQ(f> z)3JDsmhia~W9joMCKG+P@A$5-8>$CbX@y||wlxM9AM}Y8S5?y3k3W3&YAS`4M3@au zi?3Z3O8B`d&9XC7SZq}BbB8LsWK?eC@$R~tozE<)3nm6xR55aZQxf_^*b$mCXaLw( zOO`{QB)2@NU%WqCZ?`wpthd*OWAu!$(uBFbVTLGDNJubeBbo8y_Fgzd6>lW7`DV5} zboKo3Q8Iy-N-$Rj5*Sc`Bsa#n#gLU-KVLpuGPmqJF~SCMgLY&qQNWF>T&yFaWpPAO zIj1_$kv%dQC9%xxO;j2Va25e}zVnd``2980;=mNnPqQNxo5a+m%5}g_oXnHSjdJOU z`0IUZo5$sTi0E~zz{0fAhMyNZwR^6CF-T6EYWnNGP#UXT+V|(bx6WBULx=kkl<(_0 z`<}~s!(#F`9U0#|rtFwr6*9jBScn@DILp!;tpkWGpM>E~$JJm2RkqQX=DiL#gVJERGjkz3`9pqGzJbe?3#<+}(?9WUz)BEh|ExD+dAI-_#4Drw}!4%rJasguh;c4T0 zZjc8I%11!X;<`0&o4=%~BlZBT?RQaJpu3#;G+U8DDofC@97$>K1wb4Xbpy}Pd zcuk5TW2NkbP+{V93l@{|ba)kxI(e5F93&njA1@UOAOk#gKk3 z1K!v5iv?qRiNP`b(uV8r9C6XwKf<{TN^52nR!eSoT>Zp|TVIN*b?4OiV{-jP^v*d3+~7 z&t#gT<^wroX8NJvJbVSwj!qw}4r}oYzkaY@*I&7^)|}+ql$tHp>pP%xVy7xuhZ!I7 zaLQH1G$K=j68?xj`2?Jen?MC0{0ec%e$m4Ep|^Z}$LG@3D=&`{rPZ07F3&k7ZL2*I zL$V|L8zz#~2CsxF5!~?F?2ZxRJ*VMm4Asey-B>5E-7UWtRSUCbiiD*F7;QuUt!MmLGiRdA-t< z_SaQs_Un0oJppI_B^~$Kkr!a&!Dq1< z=V*z1N%c!}0FotWi2on`>3=hG>zf@BP$yMDrfYT~g{MD2`qvY3LZKPpZvVe%y!gM@ z-Hs2&6gnW5-z)aCq|K+&VI_#F&9(`EdvP)pa4UANJ!*{GOO2jtCKYl0F2dN_<<5E$ zJh(GlLztfo1tei7loxK&&ZXHt~Qd$H!r+#49rk`T0=2nNe#H<}wJZH`nc~BB zsjqCvx*nB)_iwU}1io|$MxK+7y}s^AAcrqHTrt&7E+nwVc>*QL5p^YHE$x0B%ay96+xg0A>2f9xv+Dj`YK$CyKV3VGiE4bwB z%s0U09oMSgk$FA-EdwBP9XVIP-d+$&K@EG@ap=~IX>GKcoa#+zO@<*?qlD6bDoNQK3^9fZL@F{w#=BI@TM2D8W52BU4 zHTU81CP(M)xBAArdsU!($(`u=z*~G$XSc*Cf}cuU=*PpsdCQSjcjP^A z@tBqzRe$0opCZ$jNnR49iK6lICLWAIrbfJK5Wwqces{1m{JfChN#}+PWLStR!L3h9 z7%XvRiySj4?^xG_HR7q1bZqVUYMDML#sBomtquha+^#}O_V$>)AMMUP*yrqqg@red z$B}HDZit-*Dw^cjBf5ih*iSy|_n|Dqd6D1l(!cBR{%_tc1O&+--DkHs3`mtq4u%Cb zZTq0^Ko}L>W*h>ID#%VMpcM=3{Y6y@=tTjAk_+G*1PFuS@uN^e zvorxRxKFG15O8H}Jp<=&fYvs@5~AWDAqsrHYBNIt?3_(y=n*i`kna-RuXaMh*I|0i zL@9lHQxe+~aPZV`#h`&63jZ1gqGkXezSUt>D|$Q!FnP_rTD)!!eEsKY``k); z;?BNHuc6z3ZSmY^-n_Pz;9El2WHoDC^vQU;#8H9oIuhgcKDx1X-BetlWh z-4fIVA|@}>;H$1}T4h$q9@>jvfVMi@MT`G8+>7a1e(18~^|de6RSx6D!R1Co@#svN zC4ZEEPiEq;VKrG^$P*%Wkm(fcFtl(+B zoc#4gxs@B=a`cN40iP1whPMNRysq%6fZiWk88R2S_ z5Fe>PV2z(NATMJKv=SKpdUZYIgxiX~aXa7x1AW~Te=QPd=e?g_&(eI#zkIQ54)oD( zKBd*agbb*C?}w&R6z?p-(BeYBN+P$l5u6LpZ$;s0jDnx>&ZFjy7Ikb?1FnD>eq{f( zastKKOKSxAeDDK@GD;uE@!O`)q2oQB#u^s1}JaBOcHBd5PV!o?$8s9YFy1e-!2T z^?jh{_g-mx&fdI*-0o*`p_!E>-vhERN|QUyr!XV)QvA?afeFyAsz~>Z#DK^97geb%_WaO3a?hohN+5yG2 za$C}AiXX}mgX!G*Q?r`WwpL~%04csCb?vn4($LQzlqVS;w`@Ae%`IdBkSWV}fB(@KnP&u81sUxt`cGKiV~9eeE;kaD z=s_NmT8isw6C;;3G?g1}hnhZm;F?{&z)4PJ?$F4aD)-dOtd%+=**{q#e@4u zh_4Ir*%^FGqa}44Awo>e?;EbaAr19a_pk!WzSR4ll)XU8<0Fd~Egeg)EGel2wH!pn z+@Ejj*24fsdg{|yCbf%udwrXcGNGMNyU^KU+8ARf1Md;3kK$yvw|Uk97EFm|V6%J-xZ&62AIzJD7<=q^Gsw^aY zonX2TjC&%b(!`Pd&W~sU%3>oYl71YM<3NP}2q?3Al$j?DpSq!!&9_)&Shj)T-K-A| zC?jRR5GHiG^e#aKr^TIs_MelDVhw}zmayXSFo`gJSx?yv%kPO%RL%fKX}puFoMPZP zvMc*qXO0t~}N5$w5QO5wWta7thS+ zL}(62V-l&X7)p4=sI;r)VCuw}ZG5z7)zpxzerFai&Ykx~ z4Gn+YG(`~f?$9oyIb5=rc%T*g`(Y>b7BjEEP7jyczm=iU^>O*jY(yTBjM3tIV)u28 zy?ry8OjDvCx+RT93$4Wc?)veZGvb{XS}TTDG65Q!;7ceb!J|2xvvn9+YdVyznIo5b zN(+~W)=nBbByJC{Uf-EX7PN*c)*fC~KFws$1XJJe0^cK(>5kdiYxK~p?;ifj+ZQ!y zs$O9n)vW@0K&*DDlDYvvPv=X}4ePZZ=xZc!kIQqN9Tj=yF!svb*ps7g5BQkdeKrcD z-F!GaGt-`phjwup6R5=7{ys99ymG)9lx=tM?EDbRLEj)puz(G`e~US1>)La^-Zs`oUUzL%v6ZRex9l_`&=!1o;vN&f`k*L(e@` z1?|>p@$jvY~F$C zewA4o07uV8PC4hZx7W9={CzDA<06iy!YsXT9-WFH!q4%}>6iEOn#5xyuoZkANz?BE zHeI?9vUCHH!;$yE2@Aa=4FC6jRBOF`oxs!MzRMuUK=Kg@j`h}&5qAR;iv7z<&}Wkg ziGb1m-F~|{`HkCbrlUR3K`Q(XByPbe&DJ;pt-woj$HoU{w+4G5Dd4^jtPg;JTman> z8efe?)h!SC|_Q%a0+G(i}1@yp%% zMIoksJ)P|`%q&9MJ-_lJ&|5{Udoy>+g8{c3Flt+UOOUg1d-hfN2Ts*Yc1}4jhMqi8 zEZHo)Hq=bNKk8qFfH*IJ!W=t;|G5Dw*7CwJ<}0X^aP>T+M`LKA+X7l~gXO}?>&=LjjfsXD>cdf%c zPol!)r#l$NB-zP<)bV2MxRs{C;-`D!zGX+S7%0^M6F~9-Mi80Z`2v?kB&|);N_8Bq zoml``ni@5JWyt!^2S?fO9nWFcsx$tiDP~K(8ctY3z9iFoeCKaNQ~_7{M$X3krY#-v_!$4!|W}P4mRYZKB+vm=D@&O_|GL- z$?2Dd*Zh8D3kHAPc7XwN{I7&wZEP7v%;ERnK(-(&oL;cv&1B?1OHn-Qumhx9ZdsE3 zqu@bico!L^#o1J5GlM^c32Hw3n~V8BN~Fp3M(M^-cf{Go65N|ZIrRl5c70d^6q^vL zdd%O<8>#$-og>1*oC7k|LCalgd@UG`GZsHyg?^>*<#RNY4tjbL>^837<}bASGr;aA zn(ei^&E~AZJOuZm?>`oTRyD>T=M=mR3@~+QfQLbK4L}V6WDNx)^tnosi2 qS-=!6=B!RDAxfTM*2jIf4vuWY4Kry{jGMtgBua{Ew{jI8`uz_o#e$yz literal 0 HcmV?d00001 diff --git a/Documentation/Images/SiteSet.png b/Documentation/Images/SiteSet.png new file mode 100644 index 0000000000000000000000000000000000000000..7b4a9e2caabbf559980e497975a95e99cd145eb9 GIT binary patch literal 41353 zcmeFZXIxWVw=as10@9_4fPjtOlqy}Cpfn*MNEM|hy@!s1fPfUGNpI474}@X_L~5kB zK#&fB&V3po)H5!EAg z6+I%Ni)%zgf2m&n3wQ$)dn^h3x!|s+rbJXRczqpsxMZuSrAS0n9ZPX$Nen!bxu`#L zCnBQmApE<~?ObF9yrlC`HSz#C+jxL2-K>e!+^nsg++R6+m>XOMy5tZ&Qc=|RHs3lY zt7BAcme@dx9-VYU{L-;VS9B9Nz0X3Q(I9F0ss1~?YNp2xla23TX`4rF|Bf{osnzDHR%I^1;NK z@YA>?#!(w$m6dn8?e{|&%YLxa=D1jto|!ML4|1Sj4C6-=S_zICU_Gw4Y`@K;d4=y) z3~w8&Sp1?)_e4rg!?TEMj7jhT=S|2(pkdv8w!nRhbBvtT5-!}T7v-uSzcKQ(uKX1h z-$fW3&>*`j=S=SC&C#vY)sTi`WS9i|ki#eO!%g=#mpPc>DL{ z>fI9DlyjJ`XWMZRd5*=zXBBqKe@}NKdDDG#txU3~AK&tN8$CO{LbmrT+Bn-wrSFLo z#DIh_Bk_9s_RY%c9z~ZIzSlfVoB#*Pt0Yj2{)P6aYzZ={yYz>yeD7Dt5Ro}#`%u*!plGB>HR+9hgs~lPu!m+op(hp<9Kn#h4Wq@7}C_WvUSQ{C^ zecNT)3<~&oAi_+lzR#_rFW}>! zA5lR|r6LtUlH1P|?Bi00^A}&j0p)%$R$qjds^605rq?yfyMhoWhbD+vyBIQyRbDY2 zEV~|9^ghuxp<2}U{=)|9!Z}`1r}fORM~W1e3F|$ej}M?>PCIP3?0wf@hXXfq1WY#B zW_YbHCm%I8zz-#fgVrvbtA`#W6qzd9VV|bl#_hi=jm3AoM`IDghtEOx^WgZyeKR~Z zOa`yk5slv;nZsw1CD*h2;N+9p+&>q`sgPpgzf11aJ(db|SMIQ3RCXLtslS5Y)!DzJ zHDJSRxC_f@t_~c(vC9C^BSu5es)TkmbddUrpUs_;M~AQZr=Ql1`(Gcao>65o^*r~K zJlL9P1aHsD`5kT2p5>4p+-4jG>Ax+Bpt4ueGIwp?d4K!+S@FQc#CaB8ZVmaPq#du& z58|$udCK&Ch^xTZoTufx)5$et)x?VT<03@~gU})C&4S{?Uk#QK5$%eZPT2?76T$`6 zVm(8&LB7g|u|&F$7`hEEO>jD0i7lB*{V?MG=rG!m2h1{ep36T&M)pul+>${26Z(p2 zwb^p{(>F(e622<9q_cb=FqV@#a7LX1YQ~*R+hY&cN7TX(HG_)&GRW(FvA|A`G#yJLuArVUkC7IQjDd4J=1m7^997@W!pQCqf4%B2PO%zO zmd97CSGKV|u#B}$_K1yc-_nKw8AuwNlqWz85#L%uMNq*FC#MfRt271$T6U;rKS5$l ztlxQ%>QzZ0+s3M(G0B$Dhu-boc*l(;8|9|>7yDFbfp5cHyur}OA*Y5IQn1O*lEuw? zFI{X$wL7%Z<@iF0!T0Qdt!b051AiNh6sC9fc}Kp^tJ_rO)PC}jZ3f(m+X&BX(Tv$} z!TtEPsBrE*u46CxshA@`{KX`Nn%A08Nh0DV-sgMvh1-Tg7KN)#mayTp%Al$(`NH>h zoUWSPP7~%c!hz-I8>N-(qBi}T^Kg)koT@^Yj!Mug`su1LG+0>C1@3Xjg;R=8<;p5r zVP8S39y@rZvs-oqrwFv)SYqhwwrm)bgg_^%0DkN`c!bg(zJSdZ_;*abl!s+FD$y*w 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
+ + + Website User Login + + + Login Form + + + Login/logout form used to password protect pages allowing only authorised website users and groups access. + + + Redirect at Login to Page (felogin) + + + Forgot hash + + + General Header + + + General Message + + + Redirect Header + + + Redirect Message + + + Welcome Header + + + Welcome Message + + + Login Success Header + + + Login Success Message + + + Login Error Header + + + Login Error Message + + + Status Display Header + + + Status Display Message + + + Logout Header + + + Logout Message + + + Forgot Password Header + + + Forgot Password Message + + + General + + + Redirects + + + Messages + + + Display Password Recovery Link + + + Display Remember Login Option + + + Disable redirect after successful login, but display logout-form + + + FE group select mode: + + + Show all + + + Show selected + + + Don't show selected + + + (from Typoscript) + + + FE group selection: + + + no group + + + Using fieldlists below: + + + User Fields/list: + + + User Fields/details: + + + Redirect Mode + + + Defined by Usergroup Record + + + Defined by User Record + + + After Login (TS or Flexform) + + + After Logout (TS or Flexform) + + + After Login Error (TS or Flexform) + + + Defined by GET/POST Parameters + + + Defined by Referrer + + + Defined by Domain Entries + + + Use First Supported Mode from Selection + + + Disable Redirect + + + After Successful Login Redirect to Page + + + After Failed Login Redirect to Page + + + After Logout Redirect to Page + + + Template File + + + User Storage Page + + + + diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf new file mode 100644 index 0000000..636f0f3 --- /dev/null +++ b/Resources/Private/Language/locallang.xlf @@ -0,0 +1,172 @@ + + + +
+ + + You are now logged in as '%s' + + + User login + + + Enter your username and password here in order to log in on the website + + + You have logged out. + + + You just logged out from your user session on this website. You can login again or as another user by the form below. + + + Login failure + + + An error occurred during login. Most likely you didn't enter the username or password correctly. +Be certain that you enter them precisely as they are, including upper/lower case. +Another possibility is that cookies might be disabled in your web browser. + + + Login successful + + + You are now logged in as '###USER###' + + + Current status + + + This is your current status + + + Username + + + Password + + + Login + + + Stay logged in + + + Logout + + + Send password + + + Reset Password + + + Change your password + + + Please enter your new password twice. + + + Ensure that your new password matches the following requirements: + + + Error: there is no prefix for the link. Please set one of the following in your typoscript: plugin.tx_felogin_pi1.feloginBaseURL = http://yourdomain/, config.baseURL = http://yourdomain/, config.absRefPrefix = / + + + The link you clicked is not valid. Please repeat the forgot password procedure. + + + The passwords are not equal, please enter your new password twice. Password needs a minimum length of %s chars. + + + The password length is too short. Please enter your new password twice. Password needs a minimum length of %s chars. + + + Your password has been saved. You can now login with your new password. + + + Change your password + + + Enter new password + + + Repeat new password + + + Your email + + + Forgot your password? + + + Your password +Hi %s + +Your username is "%s" +Your password is "%s" + + + Your password +Hi %s + +We couldn't find a username for this email address and so cannot send the password to you. Probably you misspelled the email address (upper/lower case makes a difference) or maybe you even didn't register yet? + + + Your new password +Dear %s, + +This email was sent in response to your request to reset your password. Please click on the link below. +%s + +For security reasons, this link is only active until %s. If you do not visit the link before then, you will need to repeat the password reset steps. + + + Please enter the email address by which you registered your user account. Then press "Send password" and your password will immediately be emailed to you. Make sure to spell your email address correctly. + + + Your password has now been sent to the email address %s + + + Please enter your username or email address. Instructions for resetting the password will be immediately emailed to you. + + + An email has been sent to the address stored in your account and contains a link to reset your password. If you do not receive an email, your account or email address was not found. + + + Return to login form + + + Username or email address + + + Your new password + + + Password recovery link + + + Your password recovery link is expired. + + + New password and new password repeat cannot be empty + + + New Password must match repeated password. + + + <p>Dear %s,</p> +<p>This email was sent in response to your request to reset your password. Please click on the link below.</p> +<p>%s</p> +<p>For security reasons, this link is only active until %s. If you do not visit the link before then, you will need to repeat the password reset steps.</p> + + + Dear %s, + +This email was sent in response to your request to reset your password. Please click on the link below. +%s + +For security reasons, this link is only active until %s. If you do not visit the link before then, you will need to repeat the password reset steps. + + + + diff --git a/Resources/Private/Partials/RenderLabelOrMessage.fluid.html b/Resources/Private/Partials/RenderLabelOrMessage.fluid.html new file mode 100644 index 0000000..9ba8ad4 --- /dev/null +++ b/Resources/Private/Partials/RenderLabelOrMessage.fluid.html @@ -0,0 +1,12 @@ + + + + + {settings.{key}} + + + + + + + diff --git a/Resources/Private/Partials/ValidationErrors.fluid.html b/Resources/Private/Partials/ValidationErrors.fluid.html new file mode 100644 index 0000000..1799e3f --- /dev/null +++ b/Resources/Private/Partials/ValidationErrors.fluid.html @@ -0,0 +1,17 @@ + + + +
    + +
  • {propertyPath} +
      + +
    • {error.code}: {error}
    • +
      +
    +
  • +
    +
+
+
+ diff --git a/Resources/Private/Templates/Login/Login.fluid.html b/Resources/Private/Templates/Login/Login.fluid.html new file mode 100644 index 0000000..94078b7 --- /dev/null +++ b/Resources/Private/Templates/Login/Login.fluid.html @@ -0,0 +1,81 @@ + + + + + +

+ +

+

+ +

+
+ + + + + + + + + + + + +
+ + + +
+ + +
+
+ + +
+ + +
+ + + + + + + + + + + +
+
+ +
+ +
+ +
+ + + + + + + + + + + + + +
+
+
+ diff --git a/Resources/Private/Templates/Login/Logout.fluid.html b/Resources/Private/Templates/Login/Logout.fluid.html new file mode 100644 index 0000000..bcd3883 --- /dev/null +++ b/Resources/Private/Templates/Login/Logout.fluid.html @@ -0,0 +1,33 @@ + + +

+ +

+

+ +

+ + +
+ + + +
+ + {user.username} +
+
+ +
+ +
+ + + + +
+
+
+ diff --git a/Resources/Private/Templates/Login/Overview.fluid.html b/Resources/Private/Templates/Login/Overview.fluid.html new file mode 100644 index 0000000..ce48806 --- /dev/null +++ b/Resources/Private/Templates/Login/Overview.fluid.html @@ -0,0 +1,10 @@ + + + +

+ +

+
+ + + diff --git a/Resources/Private/Templates/PasswordRecovery/Recovery.fluid.html b/Resources/Private/Templates/PasswordRecovery/Recovery.fluid.html new file mode 100644 index 0000000..11810ea --- /dev/null +++ b/Resources/Private/Templates/PasswordRecovery/Recovery.fluid.html @@ -0,0 +1,33 @@ + +

+ +

+

+ +

+ + + + +
+ + + +
+ + +
+
+ +
+
+
+ +

+ + + +

+ diff --git a/Resources/Private/Templates/PasswordRecovery/ShowChangePassword.fluid.html b/Resources/Private/Templates/PasswordRecovery/ShowChangePassword.fluid.html new file mode 100644 index 0000000..a079538 --- /dev/null +++ b/Resources/Private/Templates/PasswordRecovery/ShowChangePassword.fluid.html @@ -0,0 +1,51 @@ + +

+ +

+

+ + + +

+ + + + +
+ + + +
+ + +
+
+ + +
+ +
+ +
+
+
+ + +

+
    + +
  • {passwordRequirement}
  • +
    +
+
+ +

+ + + +

+ diff --git a/Resources/Public/Icons/Extension.png b/Resources/Public/Icons/Extension.png new file mode 100644 index 0000000000000000000000000000000000000000..7b9e4367b7e72fa748c1550123bd41ce38d030a5 GIT binary patch literal 1914 zcmb7EX*3(?8vY_2DzubRiq_0X&DQGTQcGhUw6?0HtueG(HPliSu06KPR8^*y(pqbq zDpiBg+7eWW4AF>G$bwp8jU^TIVduPF}z zP;{`jaRUG%`9gpkR06^E*W4u_eb>^-5`d;0nBb<2q(0$q@8$$REF1t-8UTBe7K#Y~ z(g1*EKLAV$0Zz6^y4xyu-2AVr(s9eY7wLn`j26yLBo@D&A50*Yevb*cHke*bZ=Yo|g(4w|MSC()Z_@MNJU0C4WFupH zK`0UpuTE%o-hMZa;|cle+%3bN`#<6`xq`ih8LUxH#HId(4@<;vFv0rWL5;IL0+Dco z$9_nzjUyJXaW_A0Fx&=`dzqtrq2T#cvs$PB&%93$aZdzC!1EYLo!p#-cL$mFMy_x+mUh=> zwijpE%njc5iLSd-o1dq*7u)A?0e?Pr>Q4+C$$K^3%@+v_53?^f|in1|7V$ty{ zbG}Mn7x6YD z&_)u|0LZP&b~d%xwr}@Mb|BpT`U3!9hxZ?ZNJ|t*95>=%W9k0S$u(+5w5o^dz$R`z z;7q2noZblB{s4MZ?Gap4TG}eB;wz=9r>dFRHdnCrS5lA0D)*%La7`&`pOww16iQ6k z7X8ooq$I34Cvjvw&*&WCe(~?p0~*;&a0O^ye*Q^gnH2Y-NELYQr3*FQ2HGb}{y|H@ zRgF2r{o4=Z;%*zuNdeT-zTW@uWFEJO>V+Lq@hxT(1HbVtHMpP^7WcO`v6bxL5GHLq9LcQV!UeS{E^p z9dTbkMyD2|%aO-&v=MX$r#md!N0+J*D9fF;KAsyH&)zInnG$z>pq(?AF#M!Gby67= z`bIuQ+bF8{GJuAWETklR- z{7b$;xkmZNW`51}{>H$#;4Ybw8;SwrHUu`fMFO{(RR*efa8fJzx3AkBV_U0wFM_3dZLX4Wfo4Trw+AEy zAmke8SLy>G}u31l46#i_s^CWXWU0?ZKhH^7V5`wukashYj<89Hv>0M`z@N#Nfe~E)|6g zv4QNyqHj&@alB%+kDV%TPTLH*hGxHtcTv;wn@)~hc}6t91y1nWmYT{gr9x2hW7de0 zg6WK8ED#s!>=h|wBT&oqqp{oJ0*GUd;GT}2w%@V8(((8E7Fs|d-n^76gdWDE+RSp4 z90aG%{=%@!EUB8f{D?L;q=G5)(~|lR@!#3)|D|LUhQ<|!_TE0Lv7a1ilH_>2q~^}clM>KtYxhQnriGk3( ['login', 'overview'], + PasswordRecoveryController::class => ['recovery', 'showChangePassword', 'changePassword'], + ], + [ + LoginController::class => ['login', 'overview'], + PasswordRecoveryController::class => ['recovery', 'showChangePassword', 'changePassword'], + ], +); diff --git a/ext_tables.sql b/ext_tables.sql new file mode 100644 index 0000000..07d2f22 --- /dev/null +++ b/ext_tables.sql @@ -0,0 +1,5 @@ +CREATE TABLE fe_users ( + # type=passthrough needs manual configuration + felogin_forgotHash varchar(160) default '' , + KEY felogin_forgotHash (felogin_forgotHash) +);

F!}xR|U|0dQEq}@f1)jRF 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 DQ&y?K literal 0 HcmV?d00001 diff --git a/Documentation/Includes.rst.txt b/Documentation/Includes.rst.txt new file mode 100644 index 0000000..2362507 --- /dev/null +++ b/Documentation/Includes.rst.txt @@ -0,0 +1 @@ +.. You can put central messages to display on all pages here diff --git a/Documentation/Index.rst b/Documentation/Index.rst new file mode 100644 index 0000000..b551e40 --- /dev/null +++ b/Documentation/Index.rst @@ -0,0 +1,57 @@ +.. include:: /Includes.rst.txt + +==================== +TYPO3 Frontend Login +==================== + +:Extension key: + felogin + +:Package name: + typo3/cms-felogin + +:Version: + |release| + +:Language: + en + +:Author: + TYPO3 contributors + +:License: + This document is published under the + `Open Content License `__. + +:Rendered: + |today| + +---- + +This extension provides a template-based plugin that allows website users to log +in to the TYPO3 frontend. + +---- + +**Table of Contents:** + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Introduction/Index + Installation/Index + UsersManual/Index + LoginMechanism/Index + Configuration/Index + GetPostParameters/Index + Events/Index + Examples/Index + KnownProblems/Index + +.. Meta Menu + +.. toctree:: + :hidden: + + Sitemap diff --git a/Documentation/Installation/Index.rst b/Documentation/Installation/Index.rst new file mode 100644 index 0000000..783c44e --- /dev/null +++ b/Documentation/Installation/Index.rst @@ -0,0 +1,57 @@ +.. include:: /Includes.rst.txt + +.. _installation: + +============ +Installation +============ + +This extension is part of the TYPO3 Core, but not installed by default. + +.. contents:: Table of contents + :local: + +Installation with Composer +========================== + +Check whether you are already using the extension with: + +.. code-block:: bash + + composer show | grep felogin + +This should either give you no result or something similar to: + +.. code-block:: none + + typo3/cms-felogin v12.4.11 + +If it is not installed yet, use the ``composer require`` command to install +the extension: + +.. code-block:: bash + + composer require typo3/cms-felogin + +The given version depends on the version of the TYPO3 Core you are using. + +Installation without Composer +============================= + +In an installation without Composer, the extension is already shipped but might +not be activated yet. Activate it as follows: + +#. In the backend, navigate to the :guilabel:`System > Extensions` + module. +#. Click the :guilabel:`Activate` icon for the Frontend Login extension. + +.. figure:: /Images/InstallActivate.png + :class: with-border + :alt: Extension manager showing Frontend Login extension + + Extension manager showing Frontend Login extension + +Next steps +========== + +:ref:`Configure the Frontend Login `. diff --git a/Documentation/Introduction/Index.rst b/Documentation/Introduction/Index.rst new file mode 100644 index 0000000..4fc9489 --- /dev/null +++ b/Documentation/Introduction/Index.rst @@ -0,0 +1,60 @@ +.. include:: /Includes.rst.txt + +.. _introduction: + +============ +Introduction +============ + +.. _what-does-it-do: + +What does it do? +================ + +The Frontend Login for Website Users (felogin) extension is a general +purpose extension for frontend logins. In addition to the actual login +box, it includes several methods for redirecting after login/logout +and includes forgot password functionality. + +.. _screenshots: + +Screenshots +=========== + +.. _general-settings: + +General Settings +---------------- + +.. figure:: ../Images/GeneralSettings.png + :alt: General Settings + + The plugin's general settings + + +.. _redirect-configuration: + +Redirect Configuration +---------------------- + +.. figure:: ../Images/RedirectConfiguration.png + :alt: Redirect Configuration + + Configuration of the redirection options + +.. hint:: + + Be sure that in the overall `Access` tab under `User Group Access rights` the content + element and even the page itself is not set to `Hide at login`, otherwise the redirect + to the given page will not work. + +.. _messages-tab: + +Messages Tab +------------ + +.. figure:: ../Images/MessagesConfiguration.png + :alt: Messages Configuration + + Configuration of the various messages (screenshot shows not all options) + diff --git a/Documentation/KnownProblems/Index.rst b/Documentation/KnownProblems/Index.rst new file mode 100644 index 0000000..c814b45 --- /dev/null +++ b/Documentation/KnownProblems/Index.rst @@ -0,0 +1,20 @@ +.. include:: /Includes.rst.txt + +.. _known-problems: + +============== +Known Problems +============== + +- If there is more than one felogin plugin on a page the password + recovery option can cause problems. This is a general problem with + plugins, but in this case the cause is a small hash in the forgot + password form which is stored in the frontend user session data. + With multiple instances on a page only one of the hashes is + stored and only one of the forgot password forms will work. Make sure + there is only one felogin plugin on the page where the password + recovery form is displayed. + +- If usergroup access rights of the plugin are defined to + :guilabel:`Hide at login`, all felogin code (e.g. redirects, PSR-14 events) + will not be executed after a user successfully logged in. diff --git a/Documentation/LoginMechanism/Display/Index.rst b/Documentation/LoginMechanism/Display/Index.rst new file mode 100644 index 0000000..b68440c --- /dev/null +++ b/Documentation/LoginMechanism/Display/Index.rst @@ -0,0 +1,19 @@ +.. include:: /Includes.rst.txt + +.. _display: + +================== +What is displayed? +================== + +If there is no frontend user logged in, the login form will be +shown. + +If there is a logged in frontend user, the logout form is shown. + +If the forgot password link was used, the form to reset a password +based on username or email address will be shown. + +If the password reset link was followed from an email, the form to +change the password will be shown. + diff --git a/Documentation/LoginMechanism/Index.rst b/Documentation/LoginMechanism/Index.rst new file mode 100644 index 0000000..9fc5b13 --- /dev/null +++ b/Documentation/LoginMechanism/Index.rst @@ -0,0 +1,22 @@ +.. include:: /Includes.rst.txt + +.. _login-mechanism: + +=============== +Login mechanism +=============== + +In order to properly use the felogin plugin and its advanced +capabilities (such as redirect options) it is important to understand +the mechanism of frontend user login in TYPO3 CMS. + + +.. toctree:: + :maxdepth: 5 + :titlesonly: + :glob: + + Display/Index + LoginProcess/Index + RedirectModes/Index + diff --git a/Documentation/LoginMechanism/LoginProcess/Index.rst b/Documentation/LoginMechanism/LoginProcess/Index.rst new file mode 100644 index 0000000..355b9d0 --- /dev/null +++ b/Documentation/LoginMechanism/LoginProcess/Index.rst @@ -0,0 +1,22 @@ +.. include:: /Includes.rst.txt + +.. _login-process: + +================= +The login process +================= + +After the form is submitted the TYPO3 CMS authentication services will +validate the login credentials. After this process felogin will handle +the rest. This means that the felogin plugin must be visible for the +user who has logged in. + +Felogin will then check any redirect options and generate the +appropriate content. + +.. caution:: + + - Do not use the login status of a frontend user as authorization, + but **always** rely on user groups. + - Only use different storage folders for frontend users if this is really + necessary due to organizational reasons. diff --git a/Documentation/LoginMechanism/RedirectModes/Index.rst b/Documentation/LoginMechanism/RedirectModes/Index.rst new file mode 100644 index 0000000..fcac243 --- /dev/null +++ b/Documentation/LoginMechanism/RedirectModes/Index.rst @@ -0,0 +1,103 @@ +.. include:: /Includes.rst.txt + +.. _redirect-modes: + +============== +Redirect Modes +============== + +The following redirect options are supported. + + +.. _defined-by-usergroup-record: + +Defined by Usergroup Record +=========================== + +Within a Website usergroup record, you can specify a page where +usergroup members will be redirected after login. + + +.. _defined-by-user-record: + +Defined by User Record +====================== + +This is identical to the redirection option for "defined by Usergroup +Record" but applies to a single website user instead of an entire user +group. + + +.. _after-login-ts-or-flexform: + +After Login (TS or Flexform) +============================ + +This redirect page is set either in TypoScript +(:typoscript:`plugin.tx_felogin_login.settings.redirectPageLogin`) or in the +FlexForm of the felogin plugin. + + +.. _after-logout-ts-or-flexform: + +After Logout (TS or Flexform) +============================= + +Defines the redirect page after a user has logged out. Again, it can +be set in TypoScript or in the felogin plugin's FlexForm. + + +.. _after-login-error-ts-of-flexform: + +After Login Error (TS of Flexform) +================================== + +Defines the redirect page after a login error occurs. Can be set in +TypoScript or in the felogin plugin's FlexForm. + + +.. _defined-by-get-post-vars: + +Defined by GET/POST Parameters +============================== + +Redirect the visitor based on the GET/POST parameters :code:`redirect_url`. +If the TypoScript configuration +:typoscript:`config.typolinkLinkAccessRestrictedPages` is set, the GET/POST +parameter :code:`redirect_url` is used. + +Example URL: + +.. code-block:: text + + https://example.org/index.php?id=12&redirect_url=https%3A%2F%2Fexample%2Eorg%2Fdestiny%2F + + +.. _defined-by-referrer: + +Defined by Referrer +=================== + +The referrer page is used for the redirect. This basically means that +the user is sent back to the page he originally came from. + + +.. _defined-by-domain-entries: + +Defined by Domain entries +========================= + +Same as :guilabel:`Defined by Referrer`, except that only the domains listed in +:typoscript:`plugin.tx_felogin_login.domains` are allowed. If someone is sent to the +login page coming from a domain which is not listed, the redirect will +not happen. + +By using the option :guilabel:`Use First Supported Mode from Selection` you can +define several fallback methods. + + +.. note:: + + It is only possible to use domains, which are known to TYPO3. This means, + that domains must be configured as :code:`base` in site settings for websites + in the current TYPO3 instance. diff --git a/Documentation/Sitemap.rst b/Documentation/Sitemap.rst new file mode 100644 index 0000000..09d3c6f --- /dev/null +++ b/Documentation/Sitemap.rst @@ -0,0 +1,9 @@ +:template: sitemap.html + +.. include:: /Includes.rst.txt + +======= +Sitemap +======= + +.. The sitemap.html template will insert here the page tree automatically. diff --git a/Documentation/UsersManual/Index.rst b/Documentation/UsersManual/Index.rst new file mode 100644 index 0000000..f299955 --- /dev/null +++ b/Documentation/UsersManual/Index.rst @@ -0,0 +1,58 @@ +.. include:: /Includes.rst.txt + +.. _users-manual: + +============ +Users manual +============ + +The felogin extension requires no special configuration. All options +are available in the plugin's FlexForm as shown in the :ref:`screenshots`. + + +.. _using-plugin: + +Using the plugin +================ + +The felogin plugin is available through the Content Wizard as :guilabel:`Login Form`: + + +.. figure:: ../Images/ContentElementWizard.png + :alt: The content element wizard + + The Login Form plugin in the content element wizard + + +.. _storage-folder: + +Choosing a user storage page for website users +============================================== + +In order for Website Users to be able to log in, the "Frontend login" plugin +must know where the records are stored. There are two possibilities +for setting this storage folder: + +The site's integrator may have set a default value for the +:confval:`User Storage Page ` or using the +:ref:`settings-editor`. If you use the default +folder to store frontend users in your project there is nothing to do here. + +If your project needs multiple storage folders for frontend users or +if there is no default storage folder set, see :ref:`Example: Override the +default storage page in the plugin's FlexForm `. + +.. _access-restrictions: + +Access restrictions on the felogin plugin +========================================= + +A very common issue is, that the felogin plugin is set to Access: +:guilabel:`Hide at login`. After the core has processed the login request, the +page will be rendered without the felogin plugin. If there are redirect options +active they will **not be executed**, simply because the felogin plugin is +hidden. + +Of course setting the felogin plugin to :guilabel:`Hide at login` and having +redirect options together doesn't really makes sense. + diff --git a/Documentation/guides.xml b/Documentation/guides.xml new file mode 100644 index 0000000..e00086e --- /dev/null +++ b/Documentation/guides.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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 2 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..db7e215 --- /dev/null +++ b/README.rst @@ -0,0 +1,11 @@ +=========================== +TYPO3 extension ``felogin`` +=========================== + +This extension provides a template-based plugin that allows website users to log +in to the TYPO3 frontend. + +:Repository: https://github.com/typo3/typo3 +:Issues: https://forge.typo3.org/ +:Read online: https://docs.typo3.org/c/typo3/cms-felogin/main/en-us/ +:Packagist: https://packagist.org/packages/typo3/cms-felogin diff --git a/Resources/Private/Email/Templates/PasswordRecovery.fluid.html b/Resources/Private/Email/Templates/PasswordRecovery.fluid.html new file mode 100644 index 0000000..0e0fae3 --- /dev/null +++ b/Resources/Private/Email/Templates/PasswordRecovery.fluid.html @@ -0,0 +1,16 @@ + + + + + + + + + {f:translate( + domain: 'felogin.messages', + key: 'forgot_validate_reset_password_html', + arguments: '{ 0: "{receiverName -> f:format.htmlspecialchars()}", 1: recoveryLink, 2: validUntil }' + ) -> f:format.html()} + + + diff --git a/Resources/Private/Email/Templates/PasswordRecovery.fluid.txt b/Resources/Private/Email/Templates/PasswordRecovery.fluid.txt new file mode 100644 index 0000000..933a6f1 --- /dev/null +++ b/Resources/Private/Email/Templates/PasswordRecovery.fluid.txt @@ -0,0 +1,9 @@ + + +{f:translate( + domain: 'felogin.messages', + key: 'forgot_validate_reset_password_plaintext', + arguments: {0: receiverName, 1: url, 2: validUntil} +) -> f:format.raw()} + + diff --git a/Resources/Private/Language/Database.xlf b/Resources/Private/Language/Database.xlf new file mode 100644 index 0000000..ba0e210 --- /dev/null +++ b/Resources/Private/Language/Database.xlf @@ -0,0 +1,167 @@ + + + +