-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEmailNotification.php
More file actions
150 lines (127 loc) · 5.96 KB
/
Copy pathEmailNotification.php
File metadata and controls
150 lines (127 loc) · 5.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
declare(strict_types=1);
/*
* This file is part of the "typo3_login_warning" TYPO3 CMS extension.
*
* (c) 2025-2026 Konrad Michalik <km@move-elevator.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace MoveElevator\Typo3LoginWarning\Notification;
use Exception;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\{LoggerAwareInterface, LoggerAwareTrait};
use Symfony\Component\Mailer\Exception\{TransportException, TransportExceptionInterface};
use Symfony\Component\Mime\Exception\RfcComplianceException;
use TYPO3\CMS\Core\Authentication\{AbstractUserAuthentication, BackendUserAuthentication};
use TYPO3\CMS\Core\Mail\{FluidEmail, MailerInterface};
use TYPO3\CMS\Core\Utility\GeneralUtility;
use function array_key_exists;
use function sprintf;
/**
* EmailNotification.
*
* @author Konrad Michalik <km@move-elevator.de>
* @license GPL-2.0-or-later
*/
class EmailNotification implements NotifierInterface, LoggerAwareInterface
{
use LoggerAwareTrait;
/**
* User record fields exposed to the (overridable) email templates. The full
* be_users row must never reach the template context as it contains sensitive
* data like the password hash and the MFA configuration.
*/
private const TEMPLATE_USER_FIELDS = ['uid', 'username', 'realName', 'email', 'admin', 'lang'];
public function __construct(
private readonly MailerInterface $mailer,
) {}
/**
* @param array<string, mixed> $configuration
* @param array<string, mixed> $additionalValues
*
* @throws TransportExceptionInterface
*/
public function notify(AbstractUserAuthentication $user, ServerRequestInterface $request, string $triggerClass, array $configuration = [], array $additionalValues = []): void
{
if (!$user instanceof BackendUserAuthentication) {
return;
}
$recipientsList = $this->buildRecipientsList($user, $configuration);
if ([] === $recipientsList) {
$this->logger?->info('No recipient configured for login notification email. Please set $GLOBALS[\'TYPO3_CONF_VARS\'][\'BE\'][\'warning_email_addr\'], configure the recipient via Typo3LoginWarning configuration, or use notificationReceiver setting with a valid user email.');
return;
}
$this->sendNotificationEmails($user, $request, $triggerClass, $recipientsList, $additionalValues);
}
/**
* @param array<string, mixed> $configuration
*
* @return array<int, string>
*/
private function buildRecipientsList(BackendUserAuthentication $user, array $configuration): array
{
$recipients = array_key_exists('recipient', $configuration) ? $configuration['recipient'] : '';
if ('' === $recipients) {
$recipients = $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'];
}
$notificationReceiver = $configuration['notificationReceiver'] ?? 'recipients';
$userEmail = trim($user->user['email'] ?? '');
$explodedRecipients = ('' !== $recipients && null !== $recipients) ? explode(',', $recipients) : [];
$recipientsList = match ($notificationReceiver) {
'user' => '' !== $userEmail ? [$userEmail] : [],
'both' => '' !== $userEmail ? [...$explodedRecipients, $userEmail] : $explodedRecipients,
default => $explodedRecipients,
};
return array_unique(array_filter(array_map(trim(...), $recipientsList), static fn (string $email): bool => '' !== $email));
}
/**
* @param array<int, string> $recipientsList
* @param array<string, mixed> $additionalValues
*/
private function sendNotificationEmails(BackendUserAuthentication $user, ServerRequestInterface $request, string $triggerClass, array $recipientsList, array $additionalValues): void
{
$userEmail = trim($user->user['email'] ?? '');
$templateUser = array_intersect_key($user->user ?? [], array_flip(self::TEMPLATE_USER_FIELDS));
foreach ($recipientsList as $recipient) {
$isUserNotification = '' !== $userEmail && $recipient === $userEmail;
$values = [
'user' => $templateUser,
'prefix' => $user->isAdmin() ? '[AdminLoginWarning]' : '[LoginWarning]',
'language' => $user->user['lang'] ?? 'default',
'headline' => 'TYPO3 Backend Login notification',
'isUserNotification' => $isUserNotification,
];
if ([] !== $additionalValues) {
$values = array_merge($values, $additionalValues);
}
$email = GeneralUtility::makeInstance(FluidEmail::class)
->to($recipient)
->setRequest($request)
->setTemplate(sprintf('LoginNotification/%s', basename(str_replace('\\', '/', $triggerClass))))
->assignMultiple($values);
try {
$this->mailer->send($email);
} catch (TransportException $e) {
$this->logger?->warning('Could not send notification email to "{recipient}" due to mailer settings error', [
'recipient' => $recipient,
'userId' => $user->user['uid'] ?? 0,
'exception' => $e,
]);
} catch (RfcComplianceException $e) {
$this->logger?->warning('Could not send notification email to "{recipient}" due to invalid email address', [
'recipient' => $recipient,
'userId' => $user->user['uid'] ?? 0,
'exception' => $e,
]);
} catch (Exception $e) {
$this->logger?->error('Could not send notification email to "{recipient}" due to a PHP exception', [
'recipient' => $recipient,
'userId' => $user->user['uid'] ?? 0,
'exception' => $e,
]);
}
}
}
}