‪TYPO3CMS  10.4
FrontendLoginController.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Symfony\Component\Mime\Address;
37 
45 {
51  public ‪$prefixId = 'tx_felogin_pi1';
52 
58  public ‪$extKey = 'felogin';
59 
65  protected ‪$userIsLoggedIn;
66 
72  protected ‪$template;
73 
79  protected ‪$redirectUrl = '';
80 
86  protected ‪$noRedirect = false;
87 
93  protected ‪$logintype;
94 
100  public ‪$referer;
101 
105  protected ‪$urlValidator;
106 
116  public function ‪main($content, ‪$conf)
117  {
118  trigger_error(
119  'The pibase felogin plugin is deprecated since TYPO3 10.4 and will be removed in version 11.0',
120  E_USER_DEPRECATED
121  );
122  $this->urlValidator = GeneralUtility::makeInstance(
123  RedirectUrlValidator::class,
124  GeneralUtility::makeInstance(SiteFinder::class)
125  );
126 
127  // Loading TypoScript array into object variable:
128  $this->conf = ‪$conf;
129  // Loading default pivars
130  $this->‪pi_setPiVarDefaults();
131  // Loading language-labels
132  $this->‪pi_loadLL('EXT:felogin/Resources/Private/Language/locallang.xlf');
133  // Init FlexForm configuration for plugin:
134  $this->‪pi_initPIflexForm();
136  // GPvars:
137  $this->logintype = GeneralUtility::_GP('logintype');
138 
139  if ($this->urlValidator->isValid((string)GeneralUtility::_GP('referer'))) {
140  $this->referer = GeneralUtility::_GP('referer');
141  } else {
142  $this->referer = '';
143  }
144  $this->noRedirect = $this->piVars['noredirect'] || $this->conf['redirectDisable'];
145  // If config.typolinkLinkAccessRestrictedPages is set, the var is return_url
146  $this->redirectUrl = GeneralUtility::_GP('return_url') ?: (string)GeneralUtility::_GP('redirect_url');
147  $this->redirectUrl = $this->urlValidator->isValid($this->redirectUrl) ? $this->redirectUrl : '';
148  // Get Template
149  $templateFile = $this->conf['templateFile'] ?: 'EXT:felogin/Resources/Private/Templates/FrontendLogin.html';
150  ‪$template = GeneralUtility::getFileAbsFileName($templateFile);
151  if (‪$template !== '' && file_exists(‪$template)) {
152  $this->template = file_get_contents(‪$template);
153  }
154  // Is user logged in?
155  $this->userIsLoggedIn = GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('frontend.user', 'isLoggedIn');
156  // Redirect
157  if ($this->conf['redirectMode'] && !$this->conf['redirectDisable'] && !$this->noRedirect) {
159  if (!empty(‪$redirectUrl)) {
160  $this->redirectUrl = $this->conf['redirectFirstMethod'] ? array_shift(‪$redirectUrl) : array_pop(‪$redirectUrl);
161  } else {
162  $this->redirectUrl = '';
163  }
164  }
165  // What to display
166  $content = '';
167  if ($this->piVars['forgot'] && $this->conf['showForgotPasswordLink']) {
168  $content .= $this->‪showForgot();
169  } elseif ($this->piVars['forgothash']) {
170  $content .= $this->‪changePassword();
171  } else {
172  if ($this->userIsLoggedIn && !$this->logintype) {
173  $content .= $this->‪showLogout();
174  } else {
175  $content .= $this->‪showLogin();
176  }
177  }
178  // Process the redirect
179  if (
180  $this->redirectUrl
181  && !$this->noRedirect
182  && (
183  ($this->logintype === ‪LoginType::LOGIN && $this->userIsLoggedIn)
184  || $this->logintype === ‪LoginType::LOGOUT
185  )
186  ) {
187  if (!$this->frontendController->fe_user->isCookieSet() && $this->userIsLoggedIn) {
188  $content .= $this->cObj->stdWrap($this->‪pi_getLL('cookie_warning'), $this->conf['cookieWarning_stdWrap.']);
189  } else {
190  // Add hook for extra processing before redirect
191  $_params = [
192  'loginType' => ‪$this->logintype,
193  'redirectUrl' => &‪$this->redirectUrl
194  ];
195  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['beforeRedirect'] ?? [] as $_funcRef) {
196  if ($_funcRef) {
197  trigger_error(
198  sprintf(
199  'Hook "%s" got called by "%s" which is deprecated since TYPO3 10.4 and will be removed in version 11.0',
200  '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'felogin\'][\'beforeRedirect\']',
201  $_funcRef
202  ),
203  E_USER_DEPRECATED
204  );
205  $ref = $this; // introduced for phpstan to not lose type information when passing $this into callUserFunction
206  GeneralUtility::callUserFunction($_funcRef, $_params, $ref);
207  }
208  }
209  ‪HttpUtility::redirect($this->redirectUrl);
210  }
211  }
212  // Adds hook for processing of extra item markers / special
213  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['postProcContent'] ?? [] as $_funcRef) {
214  trigger_error(
215  sprintf(
216  'Hook "%s" got called by "%s" which is deprecated since TYPO3 10.4 and will be removed in version 11.0',
217  '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'felogin\'][\'postProcContent\']',
218  $_funcRef
219  ),
220  E_USER_DEPRECATED
221  );
222  $_params = [
223  'content' => $content
224  ];
225  $ref = $this; // introduced for phpstan to not lose type information when passing $this into callUserFunction
226  $content = GeneralUtility::callUserFunction($_funcRef, $_params, $ref);
227  }
228  return $this->conf['wrapContentInBaseClass'] ? $this->‪pi_wrapInBaseClass($content) : $content;
229  }
230 
236  protected function ‪showForgot()
237  {
238  $markerArray = [];
239  $subpart = $this->templateService->getSubpart($this->template, '###TEMPLATE_FORGOT###');
240  $subpartArray = ($linkpartArray = []);
241  $postData = GeneralUtility::_POST($this->prefixId);
242  if ($postData['forgot_email']) {
243  // Get hashes for compare
244  $postedHash = $postData['forgot_hash'];
245  $hashData = $this->frontendController->fe_user->getKey('ses', 'forgot_hash');
246  if ($postedHash === $hashData['forgot_hash']) {
247  $userTable = $this->frontendController->fe_user->user_table;
248  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($userTable);
249  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
250  $row = $queryBuilder
251  ->select('*')
252  ->from($userTable)
253  ->where(
254  $queryBuilder->expr()->orX(
255  $queryBuilder->expr()->eq(
256  'email',
257  $queryBuilder->createNamedParameter($this->piVars['forgot_email'], \PDO::PARAM_STR)
258  ),
259  $queryBuilder->expr()->eq(
260  'username',
261  $queryBuilder->createNamedParameter($this->piVars['forgot_email'], \PDO::PARAM_STR)
262  )
263  ),
264  $queryBuilder->expr()->in(
265  'pid',
266  $queryBuilder->createNamedParameter(
267  ‪GeneralUtility::intExplode(',', $this->getStorageFolders()),
268  Connection::PARAM_INT_ARRAY
269  )
270  )
271  )
272  ->execute()
273  ->fetch();
274 
275  $error = null;
276  if ($row) {
277  // Generate an email with the hashed link
278  $error = $this->‪generateAndSendHash($row);
279  } elseif ($this->conf['exposeNonexistentUserInForgotPasswordDialog']) {
280  $error = $this->‪pi_getLL('forgot_reset_message_error');
281  }
282  // Generate message
283  if ($error) {
284  $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap($error, $this->conf['forgotErrorMessage_stdWrap.']);
285  } else {
286  $markerArray['###STATUS_MESSAGE###'] = $this->cObj->stdWrap(
287  $this->‪pi_getLL('forgot_reset_message_emailSent'),
288  $this->conf['forgotResetMessageEmailSentMessage_stdWrap.']
289  );
290  }
291  $subpartArray['###FORGOT_FORM###'] = '';
292  } else {
293  // Wrong email
294  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
295  $markerArray['###BACKLINK_LOGIN###'] = '';
296  }
297  } else {
298  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText('forgot_reset_message', $this->conf['forgotMessage_stdWrap.']);
299  $markerArray['###BACKLINK_LOGIN###'] = '';
300  }
301  $markerArray['###BACKLINK_LOGIN###'] = $this->‪getPageLink(htmlspecialchars($this->‪pi_getLL('forgot_header_backToLogin')), []);
302  $markerArray['###STATUS_HEADER###'] = $this->‪getDisplayText('forgot_header', $this->conf['forgotHeader_stdWrap.']);
303  $markerArray['###LEGEND###'] = htmlspecialchars($this->‪pi_getLL('legend', $this->‪pi_getLL('reset_password')));
304  $markerArray['###ACTION_URI###'] = $this->‪getPageLink('', [$this->prefixId . '[forgot]' => 1], true);
305  $markerArray['###EMAIL_LABEL###'] = htmlspecialchars($this->‪pi_getLL('your_email'));
306  $markerArray['###FORGOT_PASSWORD_ENTEREMAIL###'] = htmlspecialchars($this->‪pi_getLL('forgot_password_enterEmail'));
307  $markerArray['###FORGOT_EMAIL###'] = $this->prefixId . '[forgot_email]';
308  $markerArray['###SEND_PASSWORD###'] = htmlspecialchars($this->‪pi_getLL('reset_password'));
309  $markerArray['###DATA_LABEL###'] = htmlspecialchars($this->‪pi_getLL('enter_your_data'));
310  $markerArray = array_merge($markerArray, $this->‪getUserFieldMarkers());
311  // Generate hash
312  $hash = md5($this->‪generatePassword(3));
313  $markerArray['###FORGOTHASH###'] = $hash;
314  // Set hash in feuser session
315  $this->frontendController->fe_user->setKey('ses', 'forgot_hash', ['forgot_hash' => $hash]);
316  return $this->templateService->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
317  }
318 
325  protected function ‪changePassword()
326  {
327  $markerArray = [];
328  $subpartArray = ($linkpartArray = []);
329  $done = false;
330  $minLength = (int)$this->conf['newPasswordMinLength'] ?: 6;
331  $subpart = $this->templateService->getSubpart($this->template, '###TEMPLATE_CHANGEPASSWORD###');
332  $markerArray['###STATUS_HEADER###'] = $this->‪getDisplayText('change_password_header', $this->conf['changePasswordHeader_stdWrap.']);
333  $markerArray['###STATUS_MESSAGE###'] = sprintf($this->‪getDisplayText(
334  'change_password_message',
335  $this->conf['changePasswordMessage_stdWrap.']
336  ), $minLength);
337 
338  $markerArray['###BACKLINK_LOGIN###'] = '';
339  $uid = $this->piVars['user'];
340  $piHash = $this->piVars['forgothash'];
341  $hash = explode('|', rawurldecode($piHash));
342  if ((int)$uid === 0) {
343  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText(
344  'change_password_notvalid_message',
345  $this->conf['changePasswordNotValidMessage_stdWrap.']
346  );
347  $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
348  } else {
349  $user = $this->‪pi_getRecord('fe_users', (int)$uid);
350  $userHash = $user['felogin_forgotHash'];
351  $compareHash = explode('|', $userHash);
352  if (!$compareHash || !$compareHash[1] || $compareHash[0] < time() || !hash_equals($compareHash[0], $hash[0])) {
353  $hashEquals = false;
354  } elseif (strlen($compareHash[1]) === 40) {
355  $hashEquals = hash_equals($compareHash[1], GeneralUtility::hmac((string)$hash[1]));
356  } else {
357  // backward-compatibility for previous MD5 hashes
358  $hashEquals = hash_equals($compareHash[1], md5($hash[1]));
359  }
360  if (!$hashEquals) {
361  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText(
362  'change_password_notvalid_message',
363  $this->conf['changePasswordNotValidMessage_stdWrap.']
364  );
365  $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
366  } else {
367  // All is fine, continue with new password
368  $postData = GeneralUtility::_POST($this->prefixId);
369  if (isset($postData['changepasswordsubmit'])) {
370  if (strlen($postData['password1']) < $minLength) {
371  $markerArray['###STATUS_MESSAGE###'] = sprintf(
372  $this->‪getDisplayText(
373  'change_password_tooshort_message',
374  $this->conf['changePasswordTooShortMessage_stdWrap.']
375  ),
376  $minLength
377  );
378  } elseif ($postData['password1'] != $postData['password2']) {
379  $markerArray['###STATUS_MESSAGE###'] = sprintf(
380  $this->‪getDisplayText(
381  'change_password_notequal_message',
382  $this->conf['changePasswordNotEqualMessage_stdWrap.']
383  ),
384  $minLength
385  );
386  } else {
387  // Hash password using configured salted passwords hash mechanism for FE
388  $hashInstance = GeneralUtility::makeInstance(PasswordHashFactory::class)->getDefaultHashInstance('FE');
389  $newPass = $hashInstance->getHashedPassword($postData['password1']);
390 
391  // Call a hook for further password processing
392  $hookPasswordValid = true;
393  if (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed']) {
394  $_params = [
395  'user' => $user,
396  'newPassword' => $newPass,
397  'newPasswordUnencrypted' => $postData['password1'],
398  'passwordValid' => true,
399  'passwordInvalidMessage' => '',
400  ];
401  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['password_changed'] as $_funcRef) {
402  trigger_error(
403  sprintf(
404  'Hook "%s" got called by "%s" which is deprecated since TYPO3 10.4 and will be removed in version 11.0',
405  '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'felogin\'][\'password_changed\']',
406  $_funcRef
407  ),
408  E_USER_DEPRECATED
409  );
410  if ($_funcRef) {
411  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
412  }
413  }
414  $newPass = $_params['newPassword'];
415  $hookPasswordValid = $_params['passwordValid'];
416 
417  if (!$hookPasswordValid) {
418  $markerArray['###STATUS_MESSAGE###'] = $_params['passwordInvalidMessage'];
419  }
420  }
421 
422  // Change Password only if Hook returns valid
423  if ($hookPasswordValid) {
424  // Save new password and clear DB-hash
425  $userTable = $this->frontendController->fe_user->user_table;
426  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($userTable);
427  $queryBuilder->getRestrictions()->removeAll();
428  $queryBuilder->update($userTable)
429  ->set('password', $newPass)
430  ->set('felogin_forgotHash', '')
431  ->set('tstamp', (int)‪$GLOBALS['EXEC_TIME'])
432  ->where(
433  $queryBuilder->expr()->eq(
434  'uid',
435  $queryBuilder->createNamedParameter($user['uid'], \PDO::PARAM_INT)
436  )
437  )
438  ->execute();
439  $this->‪invalidateUserSessions((int)$user['uid']);
440 
441  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText(
442  'change_password_done_message',
443  $this->conf['changePasswordDoneMessage_stdWrap.']
444  );
445  $done = true;
446  $subpartArray['###CHANGEPASSWORD_FORM###'] = '';
447  $markerArray['###BACKLINK_LOGIN###'] = $this->‪getPageLink(
448  htmlspecialchars($this->‪pi_getLL('forgot_header_backToLogin')),
449  [$this->prefixId . '[redirectReferrer]' => 'off']
450  );
451  }
452  }
453  }
454  if (!$done) {
455  // Change password form
456  $markerArray['###ACTION_URI###'] = $this->‪getPageLink('', [
457  $this->prefixId . '[user]' => $user['uid'],
458  $this->prefixId . '[forgothash]' => $piHash
459  ], true);
460  $markerArray['###LEGEND###'] = htmlspecialchars($this->‪pi_getLL('change_password'));
461  $markerArray['###NEWPASSWORD1_LABEL###'] = htmlspecialchars($this->‪pi_getLL('newpassword_label1'));
462  $markerArray['###NEWPASSWORD2_LABEL###'] = htmlspecialchars($this->‪pi_getLL('newpassword_label2'));
463  $markerArray['###NEWPASSWORD1###'] = $this->prefixId . '[password1]';
464  $markerArray['###NEWPASSWORD2###'] = $this->prefixId . '[password2]';
465  $markerArray['###STORAGE_PID###'] = $this->‪shallEnforceLoginSigning() ? $this->‪getSignedStorageFolders() : $this->‪getStorageFolders();
466  $markerArray['###SEND_PASSWORD###'] = htmlspecialchars($this->‪pi_getLL('change_password'));
467  $markerArray['###FORGOTHASH###'] = $piHash;
468  }
469  }
470  }
471  return $this->templateService->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
472  }
473 
480  protected function ‪generateAndSendHash($user)
481  {
482  $hours = (int)$this->conf['forgotLinkHashValidTime'] > 0 ? (int)$this->conf['forgotLinkHashValidTime'] : 24;
483  $validEnd = time() + 3600 * $hours;
484  $validEndString = date($this->conf['dateFormat'], $validEnd);
485  $hash = md5(GeneralUtility::makeInstance(Random::class)->generateRandomBytes(64));
486  $randHash = $validEnd . '|' . $hash;
487  $randHashDB = $validEnd . '|' . GeneralUtility::hmac($hash);
488 
489  // Write hash to DB
490  $userTable = $this->frontendController->fe_user->user_table;
491  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($userTable);
492  $queryBuilder->getRestrictions()->removeAll();
493  $queryBuilder->update($userTable)
494  ->set('felogin_forgotHash', $randHashDB)
495  ->where(
496  $queryBuilder->expr()->eq(
497  'uid',
498  $queryBuilder->createNamedParameter($user['uid'], \PDO::PARAM_INT)
499  )
500  )
501  ->execute();
502 
503  // Send hashlink to user
504  $this->conf['linkPrefix'] = -1;
505  $isAbsRefPrefix = !empty($this->frontendController->absRefPrefix);
506  $isBaseURL = !empty($this->frontendController->baseUrl);
507  $isFeloginBaseURL = !empty($this->conf['feloginBaseURL']);
508  $link = $this->‪pi_getPageLink((int)$this->frontendController->id, '', [
509  $this->prefixId . '[user]' => $user['uid'],
510  $this->prefixId . '[forgothash]' => $randHash
511  ]);
512  // Prefix link if necessary
513  if ($isFeloginBaseURL) {
514  // First priority, use specific base URL
515  // "absRefPrefix" must be removed first, otherwise URL will be prepended twice
516  if ($isAbsRefPrefix) {
517  $link = substr($link, strlen($this->frontendController->absRefPrefix));
518  }
519  $link = $this->conf['feloginBaseURL'] . $link;
520  } elseif ($isAbsRefPrefix) {
521  // Second priority
522  // absRefPrefix must not necessarily contain a hostname and URL scheme, so add it if needed
523  $link = GeneralUtility::locationHeaderUrl($link);
524  } elseif ($isBaseURL) {
525  // Third priority
526  // Add the global base URL to the link
527  $link = $this->frontendController->baseUrlWrap($link);
528  } else {
529  // No prefix is set, return the error
530  return $this->‪pi_getLL('change_password_nolinkprefix_message');
531  }
532  $msg = sprintf($this->‪pi_getLL('forgot_validate_reset_password'), $user['username'], $link, $validEndString);
533  // Add hook for extra processing of mail message
534  $params = [
535  'message' => &$msg,
536  'user' => &$user
537  ];
538  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['forgotPasswordMail'] ?? [] as $reference) {
539  trigger_error(
540  sprintf(
541  'Hook "%s" got called by "%s" which is deprecated since TYPO3 10.4 and will be removed in version 11.0',
542  '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'felogin\'][\'forgotPasswordMail\']',
543  $reference
544  ),
545  E_USER_DEPRECATED
546  );
547  if ($reference) {
548  GeneralUtility::callUserFunction($reference, $params, $this);
549  }
550  }
551  if ($user['email']) {
552  $this->‪sendMail($msg, $user['email'], '', $this->conf['email_from'] ?? '', $this->conf['email_fromName'] ?? '', $this->conf['replyTo'] ?? '');
553  }
554 
555  return '';
556  }
557 
563  protected function ‪showLogout()
564  {
565  $markerArray = [];
566  $subpart = $this->templateService->getSubpart($this->template, '###TEMPLATE_LOGOUT###');
567  $subpartArray = ($linkpartArray = []);
568  $markerArray['###STATUS_HEADER###'] = $this->‪getDisplayText('status_header', $this->conf['logoutHeader_stdWrap.']);
569  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText('status_message', $this->conf['logoutMessage_stdWrap.']);
570  $this->cObj->stdWrap($this->‪flexFormValue('message', 's_status'), $this->conf['logoutMessage_stdWrap.']);
571  $markerArray['###LEGEND###'] = htmlspecialchars($this->‪pi_getLL('logout'));
572  $markerArray['###ACTION_URI###'] = $this->‪getPageLink('', [], true);
573  $markerArray['###LOGOUT_LABEL###'] = htmlspecialchars($this->‪pi_getLL('logout'));
574  $markerArray['###NAME###'] = htmlspecialchars($this->frontendController->fe_user->user['name']);
575  $markerArray['###STORAGE_PID###'] = $this->‪shallEnforceLoginSigning() ? $this->‪getSignedStorageFolders() : $this->‪getStorageFolders();
576  $markerArray['###USERNAME###'] = htmlspecialchars($this->frontendController->fe_user->user['username']);
577  $markerArray['###USERNAME_LABEL###'] = htmlspecialchars($this->‪pi_getLL('username'));
578  $markerArray['###NOREDIRECT###'] = $this->noRedirect ? '1' : '0';
579  $markerArray['###PREFIXID###'] = ‪$this->prefixId;
580  $markerArray = array_merge($markerArray, $this->‪getUserFieldMarkers());
581  if ($this->redirectUrl) {
582  // Use redirectUrl for action tag because of possible access restricted pages
583  $markerArray['###ACTION_URI###'] = htmlspecialchars($this->redirectUrl);
584  $this->redirectUrl = '';
585  }
586  return $this->templateService->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
587  }
588 
594  protected function ‪showLogin()
595  {
596  $subpart = $this->templateService->getSubpart($this->template, '###TEMPLATE_LOGIN###');
597  $subpartArray = ($linkpartArray = ($markerArray = []));
598  $gpRedirectUrl = '';
599  $markerArray['###LEGEND###'] = htmlspecialchars($this->‪pi_getLL('oLabel_header_welcome'));
600  if ($this->logintype === ‪LoginType::LOGIN) {
601  if ($this->userIsLoggedIn) {
602  // login success
603  $markerArray['###STATUS_HEADER###'] = $this->‪getDisplayText('success_header', $this->conf['successHeader_stdWrap.']);
604  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText('success_message', $this->conf['successMessage_stdWrap.']);
605  $markerArray = array_merge($markerArray, $this->‪getUserFieldMarkers());
606  $subpartArray['###LOGIN_FORM###'] = '';
607  // Hook for general actions after after login has been confirmed (by Thomas Danzl <thomas@danzl.org>)
608  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_confirmed'] ?? [] as $_funcRef) {
609  $_params = [];
610  trigger_error(
611  sprintf(
612  'Hook "%s" got called by "%s" which is deprecated since TYPO3 10.4 and will be removed in version 11.0',
613  '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'felogin\'][\'login_confirmed\']',
614  $_funcRef
615  ),
616  E_USER_DEPRECATED
617  );
618  if ($_funcRef) {
619  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
620  }
621  }
622  // show logout form directly
623  if ($this->conf['showLogoutFormAfterLogin']) {
624  $this->redirectUrl = '';
625  return $this->‪showLogout();
626  }
627  } else {
628  // Hook for general actions on login error
629  $params = [];
630  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['login_error'] ?? [] as $funcRef) {
631  trigger_error(
632  sprintf(
633  'Hook "%s" got called by "%s" which is deprecated since TYPO3 10.4 and will be removed in version 11.0',
634  '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'felogin\'][\'login_error\']',
635  $funcRef
636  ),
637  E_USER_DEPRECATED
638  );
639  if ($funcRef) {
640  GeneralUtility::callUserFunction($funcRef, $params, $this);
641  }
642  }
643  // login error
644  $markerArray['###STATUS_HEADER###'] = $this->‪getDisplayText('error_header', $this->conf['errorHeader_stdWrap.']);
645  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText('error_message', $this->conf['errorMessage_stdWrap.']);
646  $gpRedirectUrl = GeneralUtility::_GP('redirect_url');
647  }
648  } else {
649  if ($this->logintype === ‪LoginType::LOGOUT) {
650  // login form after logout
651  $markerArray['###STATUS_HEADER###'] = $this->‪getDisplayText('logout_header', $this->conf['logoutHeader_stdWrap.']);
652  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText('logout_message', $this->conf['logoutMessage_stdWrap.']);
653  } else {
654  // login form
655  $markerArray['###STATUS_HEADER###'] = $this->‪getDisplayText('welcome_header', $this->conf['welcomeHeader_stdWrap.']);
656  $markerArray['###STATUS_MESSAGE###'] = $this->‪getDisplayText('welcome_message', $this->conf['welcomeMessage_stdWrap.']);
657  }
658  }
659 
660  // This hook allows to call User JS functions.
661  // The methods should also set the required JS functions to get included
662  $onSubmit = '';
663  $extraHidden = '';
664  $onSubmitAr = [];
665  $extraHiddenAr = [];
666  // Check for referer redirect method. if present, save referer in form field
667  if (GeneralUtility::inList($this->conf['redirectMode'], 'referer') || GeneralUtility::inList($this->conf['redirectMode'], 'refererDomains')) {
668  ‪$referer = $this->referer ?: GeneralUtility::getIndpEnv('HTTP_REFERER');
669  if (‪$referer) {
670  $extraHiddenAr[] = '<input type="hidden" name="referer" value="' . htmlspecialchars(‪$referer) . '" />';
671  if ($this->piVars['redirectReferrer'] === 'off') {
672  $extraHiddenAr[] = '<input type="hidden" name="' . $this->prefixId . '[redirectReferrer]" value="off" />';
673  }
674  }
675  }
676  $_params = [];
677  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['loginFormOnSubmitFuncs'] ?? [] as $funcRef) {
678  trigger_error(
679  sprintf(
680  'Hook "%s" got called by "%s" which is deprecated since TYPO3 10.4 and will be removed in version 11.0',
681  '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'felogin\'][\'loginFormOnSubmitFuncs\']',
682  $funcRef
683  ),
684  E_USER_DEPRECATED
685  );
686  [$onSub, $hid] = GeneralUtility::callUserFunction($funcRef, $_params, $this);
687  $onSubmitAr[] = $onSub;
688  $extraHiddenAr[] = $hid;
689  }
690  if (!empty($onSubmitAr)) {
691  $onSubmit = implode('; ', $onSubmitAr) . '; return true;';
692  }
693  if (!empty($extraHiddenAr)) {
694  $extraHidden = implode(LF, $extraHiddenAr);
695  }
696  if (!$gpRedirectUrl && $this->redirectUrl) {
697  $gpRedirectUrl = ‪$this->redirectUrl;
698  }
699  // Login form
700  $markerArray['###ACTION_URI###'] = $this->‪getPageLink('', [], true);
701  // Used by kb_md5fepw extension...
702  $markerArray['###EXTRA_HIDDEN###'] = $extraHidden;
703  $markerArray['###LEGEND###'] = htmlspecialchars($this->‪pi_getLL('login'));
704  $markerArray['###LOGIN_LABEL###'] = htmlspecialchars($this->‪pi_getLL('login'));
705  // Used by kb_md5fepw extension...
706  $markerArray['###ON_SUBMIT###'] = $onSubmit;
707  $markerArray['###PASSWORD_LABEL###'] = htmlspecialchars($this->‪pi_getLL('password'));
708  $markerArray['###STORAGE_PID###'] = $this->‪shallEnforceLoginSigning() ? $this->‪getSignedStorageFolders() : $this->‪getStorageFolders();
709  $markerArray['###USERNAME_LABEL###'] = htmlspecialchars($this->‪pi_getLL('username'));
710  $markerArray['###REDIRECT_URL###'] = htmlspecialchars($gpRedirectUrl);
711  $markerArray['###NOREDIRECT###'] = $this->noRedirect ? '1' : '0';
712  $markerArray['###PREFIXID###'] = ‪$this->prefixId;
713  $markerArray = array_merge($markerArray, $this->‪getUserFieldMarkers());
714  if ($this->conf['showForgotPasswordLink']) {
715  $linkpartArray['###FORGOT_PASSWORD_LINK###'] = explode('|', $this->‪getPageLink('|', [$this->prefixId . '[forgot]' => 1]));
716  $markerArray['###FORGOT_PASSWORD###'] = htmlspecialchars($this->‪pi_getLL('forgot_header'));
717  } else {
718  $subpartArray['###FORGOTP_VALID###'] = '';
719  }
720  // The permanent login checkbox should only be shown if permalogin is not deactivated (-1),
721  // not forced to be always active (2) and lifetime is greater than 0
722  $permalogin = (int)‪$GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'];
723  if (
724  $this->conf['showPermaLogin']
725  && ($permalogin === 0 || $permalogin === 1)
726  && ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['lifetime'] > 0
727  ) {
728  $markerArray['###PERMALOGIN###'] = htmlspecialchars($this->‪pi_getLL('permalogin'));
729  if ($permalogin === 1) {
730  $markerArray['###PERMALOGIN_HIDDENFIELD_ATTRIBUTES###'] = 'disabled="disabled"';
731  $markerArray['###PERMALOGIN_CHECKBOX_ATTRIBUTES###'] = 'checked="checked"';
732  } else {
733  $markerArray['###PERMALOGIN_HIDDENFIELD_ATTRIBUTES###'] = '';
734  $markerArray['###PERMALOGIN_CHECKBOX_ATTRIBUTES###'] = '';
735  }
736  } else {
737  $subpartArray['###PERMALOGIN_VALID###'] = '';
738  }
739  return $this->templateService->substituteMarkerArrayCached($subpart, $markerArray, $subpartArray, $linkpartArray);
740  }
741 
747  protected function ‪processRedirect()
748  {
749  $redirect_url = [];
750  if ($this->conf['redirectMode']) {
751  $redirectMethods = ‪GeneralUtility::trimExplode(',', $this->conf['redirectMode'], true);
752  foreach ($redirectMethods as $redirMethod) {
753  if ($this->userIsLoggedIn && $this->logintype === ‪LoginType::LOGIN) {
754  // Logintype is needed because the login-page wouldn't be accessible anymore after a login (would always redirect)
755  switch ($redirMethod) {
756  case 'groupLogin':
757  // taken from dkd_redirect_at_login written by Ingmar Schlecht; database-field changed
758  $groupData = $this->frontendController->fe_user->groupData;
759  if (!empty($groupData['uid'])) {
760 
761  // take the first group with a redirect page
762  $userGroupTable = $this->frontendController->fe_user->usergroup_table;
763  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($userGroupTable);
764  $queryBuilder->getRestrictions()->removeAll();
765  $row = $queryBuilder
766  ->select('felogin_redirectPid')
767  ->from($userGroupTable)
768  ->where(
769  $queryBuilder->expr()->neq(
770  'felogin_redirectPid',
771  $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
772  ),
773  $queryBuilder->expr()->in(
774  'uid',
775  $queryBuilder->createNamedParameter(
776  $groupData['uid'],
777  Connection::PARAM_INT_ARRAY
778  )
779  )
780  )
781  ->execute()
782  ->fetch();
783 
784  if ($row) {
785  $redirect_url[] = $this->‪pi_getPageLink($row['felogin_redirectPid']);
786  }
787  }
788  break;
789  case 'userLogin':
790 
791  $userTable = $this->frontendController->fe_user->user_table;
792  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($userTable);
793  $queryBuilder->getRestrictions()->removeAll();
794  $row = $queryBuilder
795  ->select('felogin_redirectPid')
796  ->from($userTable)
797  ->where(
798  $queryBuilder->expr()->neq(
799  'felogin_redirectPid',
800  $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
801  ),
802  $queryBuilder->expr()->eq(
803  $this->frontendController->fe_user->userid_column,
804  $queryBuilder->createNamedParameter(
805  $this->frontendController->fe_user->user['uid'],
806  \PDO::PARAM_INT
807  )
808  )
809  )
810  ->execute()
811  ->fetch();
812 
813  if ($row) {
814  $redirect_url[] = $this->‪pi_getPageLink($row['felogin_redirectPid']);
815  }
816 
817  break;
818  case 'login':
819  if ($this->conf['redirectPageLogin']) {
820  $redirect_url[] = $this->‪pi_getPageLink((int)$this->conf['redirectPageLogin']);
821  }
822  break;
823  case 'getpost':
824  $redirect_url[] = ‪$this->redirectUrl;
825  break;
826  case 'referer':
827  // Avoid redirect when logging in after changing password
828  if ($this->piVars['redirectReferrer'] !== 'off') {
829  // Avoid forced logout, when trying to login immediately after a logout
830  $redirect_url[] = preg_replace('/[&?]logintype=[a-z]+/', '', $this->referer);
831  }
832  break;
833  case 'refererDomains':
834  // Auto redirect.
835  // Feature to redirect to the page where the user came from (HTTP_REFERER).
836  // Allowed domains to redirect to, can be configured with plugin.tx_felogin_pi1.domains
837  // Thanks to plan2.net / Martin Kutschker for implementing this feature.
838  // also avoid redirect when logging in after changing password
839  if (isset($this->conf['domains']) && $this->conf['domains']
840  && (!isset($this->piVars['redirectReferrer']) || $this->piVars['redirectReferrer'] !== 'off')
841  ) {
842  $url = ‪$this->referer;
843  // Is referring url allowed to redirect?
844  $match = [];
845  if (preg_match('#^http://([[:alnum:]._-]+)/#', $url, $match)) {
846  $redirect_domain = $match[1];
847  $found = false;
848  foreach (‪GeneralUtility::trimExplode(',', $this->conf['domains'], true) as $d) {
849  if (preg_match('/(?:^|\\.)' . $d . '$/', $redirect_domain)) {
850  $found = true;
851  break;
852  }
853  }
854  if (!$found) {
855  $url = '';
856  }
857  }
858  // Avoid forced logout, when trying to login immediately after a logout
859  if ($url) {
860  $redirect_url[] = preg_replace('/[&?]logintype=[a-z]+/', '', $url);
861  }
862  }
863  break;
864  }
865  } elseif ($this->logintype === ‪LoginType::LOGIN) {
866  // after login-error
867  switch ($redirMethod) {
868  case 'loginError':
869  if ($this->conf['redirectPageLoginError']) {
870  $redirect_url[] = $this->‪pi_getPageLink((int)$this->conf['redirectPageLoginError']);
871  }
872  break;
873  }
874  } elseif ($this->logintype == '' && $redirMethod === 'login' && $this->conf['redirectPageLogin']) {
875  // If login and page not accessible
876  $this->cObj->typoLink('', [
877  'parameter' => $this->conf['redirectPageLogin'],
878  'linkAccessRestrictedPages' => true
879  ]);
880  $redirect_url[] = $this->cObj->lastTypoLinkUrl;
881  } elseif ($this->logintype == '' && $redirMethod === 'logout' && $this->conf['redirectPageLogout'] && $this->userIsLoggedIn) {
882  // If logout and page not accessible
883  $redirect_url[] = $this->‪pi_getPageLink((int)$this->conf['redirectPageLogout']);
884  } elseif ($this->logintype === ‪LoginType::LOGOUT) {
885  // after logout
886  // Hook for general actions after after logout has been confirmed
887  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['felogin']['logout_confirmed'] ?? [] as $_funcRef) {
888  trigger_error(
889  sprintf(
890  'Hook "%s" got called by "%s" which is deprecated since TYPO3 10.4 and will be removed in version 11.0',
891  '$GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'felogin\'][\'logout_confirmed\']',
892  $_funcRef
893  ),
894  E_USER_DEPRECATED
895  );
896  $_params = [];
897  if ($_funcRef) {
898  $ref = $this; // introduced for phpstan to not lose type information when passing $this into callUserFunction
899  GeneralUtility::callUserFunction($_funcRef, $_params, $ref);
900  }
901  }
902  switch ($redirMethod) {
903  case 'logout':
904  if ($this->conf['redirectPageLogout']) {
905  $redirect_url[] = $this->‪pi_getPageLink((int)$this->conf['redirectPageLogout']);
906  }
907  break;
908  }
909  } else {
910  // not logged in
911  // Placeholder for maybe future options
912  switch ($redirMethod) {
913  case 'getpost':
914  // Preserve the get/post value
915  $redirect_url[] = ‪$this->redirectUrl;
916  break;
917  }
918  }
919  }
920  }
921  // Remove empty values, but keep "0" as value (that's why "strlen" is used as second parameter)
922  if (!empty($redirect_url)) {
923  return array_filter($redirect_url, static function (string $value) {
924  return $value !== '';
925  });
926  }
927  return [];
928  }
929 
933  protected function ‪mergeflexFormValuesIntoConf()
934  {
935  $flex = [];
936  if ($this->‪flexFormValue('showForgotPassword', 'sDEF')) {
937  $flex['showForgotPasswordLink'] = $this->‪flexFormValue('showForgotPassword', 'sDEF');
938  }
939  if ($this->‪flexFormValue('showPermaLogin', 'sDEF')) {
940  $flex['showPermaLogin'] = $this->‪flexFormValue('showPermaLogin', 'sDEF');
941  }
942  if ($this->‪flexFormValue('showLogoutFormAfterLogin', 'sDEF')) {
943  $flex['showLogoutFormAfterLogin'] = $this->‪flexFormValue('showLogoutFormAfterLogin', 'sDEF');
944  }
945  if ($this->‪flexFormValue('pages', 'sDEF')) {
946  $flex['pages'] = $this->‪flexFormValue('pages', 'sDEF');
947  }
948  if ($this->‪flexFormValue('recursive', 'sDEF')) {
949  $flex['recursive'] = $this->‪flexFormValue('recursive', 'sDEF');
950  }
951  if ($this->‪flexFormValue('redirectMode', 's_redirect')) {
952  $flex['redirectMode'] = $this->‪flexFormValue('redirectMode', 's_redirect');
953  }
954  if ($this->‪flexFormValue('redirectFirstMethod', 's_redirect')) {
955  $flex['redirectFirstMethod'] = $this->‪flexFormValue('redirectFirstMethod', 's_redirect');
956  }
957  if ($this->‪flexFormValue('redirectDisable', 's_redirect')) {
958  $flex['redirectDisable'] = $this->‪flexFormValue('redirectDisable', 's_redirect');
959  }
960  if ($this->‪flexFormValue('redirectPageLogin', 's_redirect')) {
961  $flex['redirectPageLogin'] = $this->‪flexFormValue('redirectPageLogin', 's_redirect');
962  }
963  if ($this->‪flexFormValue('redirectPageLoginError', 's_redirect')) {
964  $flex['redirectPageLoginError'] = $this->‪flexFormValue('redirectPageLoginError', 's_redirect');
965  }
966  if ($this->‪flexFormValue('redirectPageLogout', 's_redirect')) {
967  $flex['redirectPageLogout'] = $this->‪flexFormValue('redirectPageLogout', 's_redirect');
968  }
969  $pid = $flex['pages'] ? $this->‪pi_getPidList($flex['pages'], (int)$flex['recursive']) : 0;
970  if ($pid > 0) {
971  $flex['storagePid'] = $pid;
972  }
973  $this->conf = array_merge($this->conf, $flex);
974  }
975 
983  protected function ‪flexFormValue($var, $sheet)
984  {
985  return $this->‪pi_getFFvalue($this->cObj->data['pi_flexform'], 'settings.' . $var, $sheet);
986  }
987 
996  protected function ‪getPageLink($label, ‪$piVars, $returnUrl = false)
997  {
998  $additionalParams = is_array(‪$piVars) && !empty(‪$piVars) ? ‪$piVars : [];
999  // Should GETvars be preserved?
1000  if ($this->conf['preserveGETvars']) {
1001  $additionalParams = array_merge_recursive($additionalParams, $this->‪getPreserveGetVars());
1002  }
1003  $this->conf['linkConfig.']['parameter'] = $this->frontendController->id;
1004  if (!empty($additionalParams)) {
1005  $this->conf['linkConfig.']['additionalParams'] = ‪HttpUtility::buildQueryString($additionalParams, '&');
1006  }
1007  if ($returnUrl) {
1008  return htmlspecialchars($this->cObj->typoLink_URL($this->conf['linkConfig.']));
1009  }
1010  return $this->cObj->typoLink($label, $this->conf['linkConfig.']);
1011  }
1021  protected function ‪getPreserveGetVars()
1022  {
1023  $getVars = GeneralUtility::_GET();
1024  unset(
1025  $getVars['id'],
1026  $getVars['no_cache'],
1027  $getVars['logintype'],
1028  $getVars['redirect_url'],
1029  $getVars['cHash'],
1030  $getVars[$this->prefixId]
1031  );
1032  if ($this->conf['preserveGETvars'] === 'all') {
1033  $preserveQueryParts = $getVars;
1034  } else {
1035  $preserveQueryStringProperties = ‪GeneralUtility::trimExplode(',', $this->conf['preserveGETvars']);
1036  $preserveQueryParts = [];
1037  parse_str(implode('=1&', $preserveQueryStringProperties) . '=1', $preserveQueryParts);
1038  $preserveQueryParts = ‪ArrayUtility::intersectRecursive($getVars, $preserveQueryParts);
1039  }
1040  return $preserveQueryParts;
1041  }
1042 
1048  protected function ‪generatePassword($len)
1049  {
1050  $pass = '';
1051  while ($len--) {
1052  $char = random_int(0, 35);
1053  if ($char < 10) {
1054  $pass .= '' . $char;
1055  } else {
1056  $pass .= chr($char - 10 + 97);
1057  }
1058  }
1059  return $pass;
1060  }
1061 
1069  protected function ‪getDisplayText($label, $stdWrapArray = [])
1070  {
1071  $text = $this->‪flexFormValue($label, 's_messages') ? $this->cObj->stdWrap($this->‪flexFormValue($label, 's_messages'), $stdWrapArray) : $this->cObj->stdWrap($this->‪pi_getLL($label), $stdWrapArray);
1072  $replace = $this->‪getUserFieldMarkers();
1073  return strtr($text, $replace);
1074  }
1075 
1081  protected function ‪getUserFieldMarkers()
1082  {
1083  $marker = [];
1084  // replace markers with fe_user data
1085  if ($this->frontendController->fe_user->user) {
1086  // All fields of fe_user will be replaced, scheme is ###FEUSER_FIELDNAME###
1087  foreach ($this->frontendController->fe_user->user as $field => $value) {
1088  ‪$conf = $this->conf['userfields.'][$field . '.'] ?? [];
1089  ‪$conf = array_replace_recursive(['htmlSpecialChars' => '1'], ‪$conf);
1090  $marker['###FEUSER_' . strtoupper($field) . '###'] = $this->cObj->stdWrap($value, ‪$conf);
1091  }
1092  // Add ###USER### for compatibility
1093  $marker['###USER###'] = $marker['###FEUSER_USERNAME###'];
1094  }
1095  return $marker;
1096  }
1097 
1103  protected function ‪invalidateUserSessions(int $userId)
1104  {
1105  $sessionManager = GeneralUtility::makeInstance(SessionManager::class);
1106  $sessionBackend = $sessionManager->getSessionBackend('FE');
1107  $sessionManager->invalidateAllSessionsByUserId($sessionBackend, $userId, $this->frontendController->fe_user);
1108  }
1109 
1121  protected function ‪sendMail(string $message, string $recipients, string $cc, string $senderAddress, string $senderName = '', string $replyTo = ''): bool
1122  {
1123  if (trim($message) === '') {
1124  return false;
1125  }
1126 
1127  $mail = GeneralUtility::makeInstance(MailMessage::class);
1128  $senderName = trim($senderName);
1129  $senderAddress = trim($senderAddress);
1130  if ($senderAddress !== '') {
1131  $mail->from(new Address($senderAddress, $senderName));
1132  }
1133  $parsedReplyTo = ‪MailUtility::parseAddresses($replyTo);
1134  if (!empty($parsedReplyTo)) {
1135  $mail->replyTo(...$parsedReplyTo);
1136  }
1137  // First line is subject
1138  $messageParts = explode(LF, trim($message), 2);
1139  $subject = trim($messageParts[0]);
1140  $plainMessage = trim($messageParts[1]);
1141  $parsedRecipients = ‪MailUtility::parseAddresses($recipients);
1142  if (!empty($parsedRecipients)) {
1143  $mail->to(...$parsedRecipients)
1144  ->subject($subject)
1145  ->text($plainMessage);
1146  $mail->send();
1147  }
1148  $parsedCc = ‪MailUtility::parseAddresses($cc);
1149  if (!empty($parsedCc)) {
1150  $from = $mail->getFrom();
1152  $mail = GeneralUtility::makeInstance(MailMessage::class);
1153  if (!empty($parsedReplyTo)) {
1154  $mail->replyTo($parsedReplyTo);
1155  }
1156  $mail->from($from)
1157  ->to(...$parsedCc)
1158  ->subject($subject)
1159  ->text($plainMessage);
1160  $mail->send();
1161  }
1162  return true;
1163  }
1164 
1165  protected function ‪getStorageFolders(): string
1166  {
1167  if ((bool)(‪$GLOBALS['TYPO3_CONF_VARS']['FE']['checkFeUserPid'] ?? false) === false) {
1168  $storagePidList = '0';
1169  } elseif ($this->conf['storagePid']) {
1170  if ((int)$this->conf['recursive']) {
1171  $storagePidList = $this->‪pi_getPidList($this->conf['storagePid'], (int)$this->conf['recursive']);
1172  } else {
1173  $storagePidList = $this->conf['storagePid'];
1174  }
1175  } else {
1176  throw new \RuntimeException('No storage folder (option storagePid) for frontend users given.', 1450904202);
1177  }
1178 
1179  return $storagePidList;
1180  }
1181 
1182  protected function ‪getSignedStorageFolders(): string
1183  {
1184  $pidList = $this->‪getStorageFolders();
1185  return sprintf(
1186  '%s@%s',
1187  $pidList,
1188  GeneralUtility::hmac($pidList, FrontendUserAuthentication::class)
1189  );
1190  }
1191 
1192  protected function ‪shallEnforceLoginSigning(): bool
1193  {
1194  return GeneralUtility::makeInstance(Features::class)
1195  ->isFeatureEnabled('security.frontend.enforceLoginSigning');
1196  }
1197 }
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\main
‪string main($content, $conf)
Definition: FrontendLoginController.php:107
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\flexFormValue
‪string flexFormValue($var, $sheet)
Definition: FrontendLoginController.php:974
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$template
‪string $template
Definition: FrontendLoginController.php:68
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory
Definition: PasswordHashFactory.php:27
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\sendMail
‪bool sendMail(string $message, string $recipients, string $cc, string $senderAddress, string $senderName='', string $replyTo='')
Definition: FrontendLoginController.php:1112
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\mergeflexFormValuesIntoConf
‪mergeflexFormValuesIntoConf()
Definition: FrontendLoginController.php:924
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\showLogin
‪string showLogin()
Definition: FrontendLoginController.php:585
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\generatePassword
‪string generatePassword($len)
Definition: FrontendLoginController.php:1039
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\showForgot
‪string showForgot()
Definition: FrontendLoginController.php:227
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$extKey
‪string $extKey
Definition: FrontendLoginController.php:56
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\shallEnforceLoginSigning
‪shallEnforceLoginSigning()
Definition: FrontendLoginController.php:1183
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_getPidList
‪string pi_getPidList($pid_list, $recursive=0)
Definition: AbstractPlugin.php:1139
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController
Definition: FrontendLoginController.php:45
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_getLL
‪string pi_getLL($key, $alternativeLabel='')
Definition: AbstractPlugin.php:904
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$redirectUrl
‪string $redirectUrl
Definition: FrontendLoginController.php:74
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_initPIflexForm
‪pi_initPIflexForm($field='pi_flexform')
Definition: AbstractPlugin.php:1316
‪TYPO3\CMS\Core\Mail\MailMessage
Definition: MailMessage.php:28
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin
Definition: AbstractPlugin.php:42
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Core\Session\SessionManager
Definition: SessionManager.php:39
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\getUserFieldMarkers
‪array getUserFieldMarkers()
Definition: FrontendLoginController.php:1072
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\$conf
‪array $conf
Definition: AbstractPlugin.php:174
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\generateAndSendHash
‪string generateAndSendHash($user)
Definition: FrontendLoginController.php:471
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$logintype
‪string $logintype
Definition: FrontendLoginController.php:86
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\getSignedStorageFolders
‪getSignedStorageFolders()
Definition: FrontendLoginController.php:1173
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\processRedirect
‪array processRedirect()
Definition: FrontendLoginController.php:738
‪TYPO3\CMS\Core\Authentication\LoginType
Definition: LoginType.php:26
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$userIsLoggedIn
‪bool $userIsLoggedIn
Definition: FrontendLoginController.php:62
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\$piVars
‪array $piVars
Definition: AbstractPlugin.php:73
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_wrapInBaseClass
‪string pi_wrapInBaseClass($str)
Definition: AbstractPlugin.php:796
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_getPageLink
‪string pi_getPageLink($id, $target='', $urlParameters=[])
Definition: AbstractPlugin.php:313
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_setPiVarDefaults
‪pi_setPiVarDefaults()
Definition: AbstractPlugin.php:262
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$urlValidator
‪RedirectUrlValidator $urlValidator
Definition: FrontendLoginController.php:96
‪TYPO3\CMS\Core\Utility\MailUtility\parseAddresses
‪static array parseAddresses($rawAddresses)
Definition: MailUtility.php:171
‪TYPO3\CMS\Core\Utility\HttpUtility\buildQueryString
‪static string buildQueryString(array $parameters, string $prependCharacter='', bool $skipEmptyParameters=false)
Definition: HttpUtility.php:163
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$referer
‪string $referer
Definition: FrontendLoginController.php:92
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_getFFvalue
‪string null pi_getFFvalue($T3FlexForm_array, $fieldName, $sheet='sDEF', $lang='lDEF', $value='vDEF')
Definition: AbstractPlugin.php:1337
‪TYPO3\CMS\Core\Configuration\Features
Definition: Features.php:56
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\invalidateUserSessions
‪invalidateUserSessions(int $userId)
Definition: FrontendLoginController.php:1094
‪TYPO3\CMS\Core\Utility\ArrayUtility\intersectRecursive
‪static array intersectRecursive(array $source, array $mask=[])
Definition: ArrayUtility.php:569
‪TYPO3\CMS\Core\Utility\MailUtility
Definition: MailUtility.php:24
‪TYPO3\CMS\Core\Authentication\LoginType\LOGOUT
‪const LOGOUT
Definition: LoginType.php:35
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\showLogout
‪string showLogout()
Definition: FrontendLoginController.php:554
‪TYPO3\CMS\Core\Authentication\LoginType\LOGIN
‪const LOGIN
Definition: LoginType.php:30
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\getPageLink
‪string getPageLink($label, $piVars, $returnUrl=false)
Definition: FrontendLoginController.php:987
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:36
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\getDisplayText
‪string getDisplayText($label, $stdWrapArray=[])
Definition: FrontendLoginController.php:1060
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\getPreserveGetVars
‪array getPreserveGetVars()
Definition: FrontendLoginController.php:1012
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\getStorageFolders
‪getStorageFolders()
Definition: FrontendLoginController.php:1156
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_loadLL
‪pi_loadLL($languageFilePath='')
Definition: AbstractPlugin.php:948
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$noRedirect
‪bool $noRedirect
Definition: FrontendLoginController.php:80
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:988
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\$prefixId
‪string $prefixId
Definition: FrontendLoginController.php:50
‪TYPO3\CMS\Core\Utility\HttpUtility
Definition: HttpUtility.php:24
‪TYPO3\CMS\Core\Crypto\Random
Definition: Random.php:24
‪TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
Definition: FrontendUserAuthentication.php:30
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\FrontendLogin\Validation\RedirectUrlValidator
Definition: RedirectUrlValidator.php:32
‪TYPO3\CMS\Frontend\Plugin\AbstractPlugin\pi_getRecord
‪array pi_getRecord($table, $uid, $checkPage=false)
Definition: AbstractPlugin.php:1127
‪TYPO3\CMS\Felogin\Controller
Definition: FrontendLoginController.php:16
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Felogin\Controller\FrontendLoginController\changePassword
‪string changePassword()
Definition: FrontendLoginController.php:316
‪TYPO3\CMS\Core\Utility\HttpUtility\redirect
‪static redirect($url, $httpStatus=self::HTTP_STATUS_303)
Definition: HttpUtility.php:106
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:31