1<?php 2 3declare(strict_types=1); 4 5/* 6 * This file is part of the TYPO3 CMS project. 7 * 8 * It is free software; you can redistribute it and/or modify it under 9 * the terms of the GNU General Public License, either version 2 10 * of the License, or any later version. 11 * 12 * For the full copyright and license information, please read the 13 * LICENSE.txt file that was distributed with this source code. 14 * 15 * The TYPO3 project - inspiring people to share! 16 */ 17 18namespace TYPO3\CMS\Backend\Security; 19 20use Psr\Http\Message\ServerRequestInterface; 21use Psr\Log\LoggerAwareInterface; 22use Psr\Log\LoggerAwareTrait; 23use Symfony\Component\Mailer\Exception\TransportException; 24use Symfony\Component\Mime\Exception\RfcComplianceException; 25use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication; 26use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; 27use TYPO3\CMS\Core\Http\ServerRequestFactory; 28use TYPO3\CMS\Core\Mail\FluidEmail; 29use TYPO3\CMS\Core\Mail\Mailer; 30use TYPO3\CMS\Core\Utility\GeneralUtility; 31 32/** 33 * Sends out an email if a backend user has just been logged in. 34 * 35 * Relevant settings: 36 * $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_mode'] 37 * $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'] 38 * $BE_USER->uc['emailMeAtLogin'] 39 * 40 * @internal this is not part of TYPO3 API as this is an internal hook 41 */ 42class EmailLoginNotification implements LoggerAwareInterface 43{ 44 use LoggerAwareTrait; 45 46 /** 47 * @var int 48 */ 49 private $warningMode; 50 51 /** 52 * @var string 53 */ 54 private $warningEmailRecipient; 55 56 /** 57 * @var ServerRequestInterface 58 */ 59 private $request; 60 61 public function __construct() 62 { 63 $this->warningMode = (int)($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_mode'] ?? 0); 64 $this->warningEmailRecipient = $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'] ?? ''; 65 } 66 67 /** 68 * Sends an email notification to warning_email_address and/or the logged-in user's email address. 69 * 70 * @param array $parameters array data 71 * @param BackendUserAuthentication $currentUser the currently just-logged in user 72 */ 73 public function emailAtLogin(array $parameters, BackendUserAuthentication $currentUser): void 74 { 75 $user = $parameters['user']; 76 $genericLoginWarning = $this->warningMode > 0 && !empty($this->warningEmailRecipient); 77 $userLoginNotification = ($currentUser->uc['emailMeAtLogin'] ?? null) && GeneralUtility::validEmail($user['email']); 78 if (!$genericLoginWarning && !$userLoginNotification) { 79 return; 80 } 81 $this->request = $parameters['request'] ?? $GLOBALS['TYPO3_REQUEST'] ?? ServerRequestFactory::fromGlobals(); 82 83 if ($genericLoginWarning) { 84 $prefix = $currentUser->isAdmin() ? '[AdminLoginWarning]' : '[LoginWarning]'; 85 if ($this->warningMode & 1) { 86 // First bit: Send warning email on any login 87 $this->sendEmail($this->warningEmailRecipient, $currentUser, $prefix); 88 } elseif ($currentUser->isAdmin() && $this->warningMode & 2) { 89 // Second bit: Only send warning email when an admin logs in 90 $this->sendEmail($this->warningEmailRecipient, $currentUser, $prefix); 91 } 92 } 93 // Trigger an email to the current BE user, if this has been enabled in the user configuration 94 if ($userLoginNotification) { 95 $this->sendEmail($user['email'], $currentUser); 96 } 97 } 98 99 /** 100 * Sends an email. 101 * 102 * @param string $recipient 103 * @param AbstractUserAuthentication $user 104 * @param string|null $subjectPrefix 105 */ 106 protected function sendEmail(string $recipient, AbstractUserAuthentication $user, ?string $subjectPrefix = null): void 107 { 108 $headline = 'TYPO3 Backend Login notification'; 109 $recipients = explode(',', $recipient); 110 $email = GeneralUtility::makeInstance(FluidEmail::class) 111 ->to(...$recipients) 112 ->setRequest($this->request) 113 ->setTemplate('Security/LoginNotification') 114 ->assignMultiple([ 115 'user' => $user->user, 116 'prefix' => $subjectPrefix, 117 'language' => ($user->user['lang'] ?? '') ?: 'default', 118 'headline' => $headline, 119 ]); 120 try { 121 GeneralUtility::makeInstance(Mailer::class)->send($email); 122 } catch (TransportException $e) { 123 $this->logger->warning('Could not send notification email to "{recipient}" due to mailer settings error', [ 124 'recipient' => $recipient, 125 'userId' => $user->user['uid'] ?? 0, 126 'recipientList' => $recipients, 127 'exception' => $e, 128 ]); 129 } catch (RfcComplianceException $e) { 130 $this->logger->warning('Could not send notification email to "{recipient}" due to invalid email address', [ 131 'recipient' => $recipient, 132 'userId' => $user->user['uid'] ?? 0, 133 'recipientList' => $recipients, 134 'exception' => $e, 135 ]); 136 } 137 } 138} 139