Skip to content

Commit b63a609

Browse files
committed
dkim
1 parent d4600df commit b63a609

File tree

9 files changed

+132
-66
lines changed

9 files changed

+132
-66
lines changed

.dkim/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Ignore everything in this directory
2+
*
3+
# Except this file
4+
!.gitignore
5+
!readme.md
6+
!public.key

.dkim/public.key

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAva7UBSxlTA1kGKoDjjSp
3+
5dwwLOKmWJJTkMfu3Vlbwd4HxStIr9OQE+EAINdLjOn3qeUZf6Lrh9ZGs1dcCSjg
4+
KN37m1r0zDsWBN8XYI7pqo13SmY8TYYcr4mVpgo951Lmk2JccVO5kpocwxASmRKd
5+
MzOkifhtegxzAYt04IFtQLOK7vyh0DzncWZaxxfb5HtMPRdgTshEiYVHcd+8AXPv
6+
cE4PuidW95vO3hQ+Y/JmSDSnGbo9ys/AVOGaWK/1YUVIWtlCPTjSxOWkMNRrSJbp
7+
RmYgm+5SbHARXFWsbAvYf/Wui/W1NNL3vOK8lphbCVx9GctHwzIqJR4tztriJS1U
8+
rQIDAQAB
9+
-----END PUBLIC KEY-----

.dkim/readme.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Dkim Key pair
2+
3+
In order to sign our emails a private key must be created and stored on the server.
4+
This private key must never be added to the git-history! Ask a product owner in case you need access to the key store.
5+
6+
The corresponding public key must be added to the DNS Dkim entry (Cloudflare).
7+
8+
Note: The private key must be kept valid during deployments.

config/services.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,12 @@ services:
465465
tags:
466466
- { name: monolog.processor }
467467

468+
# ======== Mails ========
469+
470+
App\System\Mail\MailerAdapter:
471+
class: App\System\Mail\MailerAdapter
472+
public: true
473+
468474
# ======== Scratch ========
469475
App\Project\Scratch\ScratchProgramUpdater:
470476
class: App\Project\Scratch\ScratchProgramUpdater

deploy.php

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
'.env.prod.local',
4444
'.env.dev.local',
4545
'google_cloud_key.json',
46+
'.dkim/private.key',
4647
]);
4748

4849
// Symfony writable dirs

src/Admin/Tools/SendMailToUser/SendMailToUserController.php

+9-21
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,20 @@
33
namespace App\Admin\Tools\SendMailToUser;
44

55
use App\DB\Entity\User\User;
6+
use App\System\Mail\MailerAdapter;
67
use App\User\UserManager;
78
use Psr\Log\LoggerInterface;
89
use Sonata\AdminBundle\Controller\CRUDController;
9-
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
1010
use Symfony\Component\HttpFoundation\Request;
1111
use Symfony\Component\HttpFoundation\Response;
12-
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
13-
use Symfony\Component\Mailer\MailerInterface;
14-
use Symfony\Component\Mime\Address;
1512

1613
class SendMailToUserController extends CRUDController
1714
{
18-
protected MailerInterface $mailer;
15+
protected MailerAdapter $mailer;
1916
protected UserManager $user_manager;
2017
protected LoggerInterface $logger;
2118

22-
public function __construct(MailerInterface $mailer, UserManager $user_manager, LoggerInterface $logger)
19+
public function __construct(MailerAdapter $mailer, UserManager $user_manager, LoggerInterface $logger)
2320
{
2421
$this->user_manager = $user_manager;
2522
$this->mailer = $mailer;
@@ -48,22 +45,13 @@ public function sendAction(Request $request): Response
4845
return new Response('Empty message!');
4946
}
5047
$htmlText = str_replace(PHP_EOL, '<br>', $messageText);
51-
5248
$mailTo = $user->getEmail();
53-
try {
54-
$email = (new TemplatedEmail())
55-
->from(new Address('share@catrob.at'))
56-
->to($mailTo)
57-
->subject($subject)
58-
->htmlTemplate('Admin/Tools/Email/simple_message.html.twig')
59-
->context([
60-
['message' => $htmlText],
61-
])
62-
;
63-
$this->mailer->send($email);
64-
} catch (TransportExceptionInterface $e) {
65-
$this->logger->error("Can't send email to {$mailTo}; Reason ".$e->getMessage());
66-
}
49+
$this->mailer->send(
50+
$mailTo,
51+
$subject,
52+
'Admin/Tools/Email/simple_message.html.twig',
53+
['message' => $htmlText]
54+
);
6755

6856
return new Response('OK - message sent');
6957
}

src/System/Mail/MailerAdapter.php

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace App\System\Mail;
4+
5+
use Psr\Log\LoggerInterface;
6+
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
7+
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
8+
use Symfony\Component\Mailer\MailerInterface;
9+
use Symfony\Component\Mime\Address;
10+
use Symfony\Component\Mime\Crypto\DkimSigner;
11+
use Symfony\Component\Mime\Exception\InvalidArgumentException;
12+
use Symfony\Component\Mime\Message;
13+
14+
class MailerAdapter
15+
{
16+
protected MailerInterface $mailer;
17+
protected LoggerInterface $logger;
18+
19+
public function __construct(MailerInterface $mailer, LoggerInterface $logger)
20+
{
21+
$this->mailer = $mailer;
22+
$this->logger = $logger;
23+
}
24+
25+
public function send(string $to, string $subject, string $template, array $context = []): void
26+
{
27+
$email = $this->buildEmail($to, $subject, $template, $context);
28+
$signedEmail = $this->signEmail($email);
29+
$this->sendEmail($signedEmail, $to);
30+
}
31+
32+
protected function buildEmail(string $to, string $subject, string $template, array $context): Message
33+
{
34+
return (new TemplatedEmail())
35+
->from(new Address('share@catrob.at'))
36+
->to($to)
37+
->subject($subject)
38+
->htmlTemplate($template)
39+
->context($context)
40+
;
41+
}
42+
43+
protected function signEmail(Message $email): Message
44+
{
45+
try {
46+
$signer = new DkimSigner('.dkim/dkim.id_rsa', 'catrob.at', 'sf');
47+
48+
return $signer->sign($email);
49+
} catch (InvalidArgumentException $e) {
50+
if ('prod' === $_ENV['APP_ENV']) {
51+
$this->logger->error('Private dkim key is missing: '.$e->getMessage());
52+
}
53+
54+
return $email;
55+
}
56+
}
57+
58+
protected function sendEmail(Message $email, string $to): void
59+
{
60+
try {
61+
$this->mailer->send($email);
62+
} catch (TransportExceptionInterface $e) {
63+
$this->logger->error("Can't send email to {$to}; Reason ".$e->getMessage());
64+
}
65+
}
66+
}

src/User/EventListener/UserPostPersistNotifier.php

+18-27
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,26 @@
33
namespace App\User\EventListener;
44

55
use App\DB\Entity\User\User;
6+
use App\System\Mail\MailerAdapter;
67
use App\User\Achievements\AchievementManager;
78
use Doctrine\Persistence\Event\LifecycleEventArgs;
89
use Exception;
910
use Psr\Log\LoggerInterface;
10-
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
11-
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
12-
use Symfony\Component\Mailer\MailerInterface;
13-
use Symfony\Component\Mime\Address;
1411
use Symfony\Contracts\Translation\TranslatorInterface;
1512
use SymfonyCasts\Bundle\VerifyEmail\VerifyEmailHelperInterface;
1613

1714
class UserPostPersistNotifier
1815
{
1916
protected AchievementManager $achievement_manager;
2017
protected VerifyEmailHelperInterface $verify_email_helper;
21-
protected MailerInterface $mailer;
18+
protected MailerAdapter $mailer;
2219
protected LoggerInterface $logger;
2320
protected TranslatorInterface $translator;
2421

2522
public function __construct(AchievementManager $achievement_manager,
2623
VerifyEmailHelperInterface $verify_email_helper,
27-
MailerInterface $mailer, LoggerInterface $logger,
24+
MailerAdapter $mailer,
25+
LoggerInterface $logger,
2826
TranslatorInterface $translator)
2927
{
3028
$this->translator = $translator;
@@ -50,27 +48,20 @@ protected function addVerifiedDeveloperAchievement(User $user): void
5048

5149
protected function sendVerifyEmail(User $user): void
5250
{
53-
try {
54-
$signatureComponents = $this->verify_email_helper->generateSignature(
55-
'registration_confirmation_route',
56-
$user->getId(),
57-
$user->getEmail()
58-
);
51+
$signatureComponents = $this->verify_email_helper->generateSignature(
52+
'registration_confirmation_route',
53+
$user->getId(),
54+
$user->getEmail()
55+
);
5956

60-
$email = (new TemplatedEmail())
61-
->from(new Address('share@catrob.at'))
62-
->to($user->getEmail())
63-
->subject($this->translator->trans('user.verification.email', [], 'catroweb'))
64-
->htmlTemplate('security/registration/confirmation_email.html.twig')
65-
->context([
66-
'signedUrl' => $signatureComponents->getSignedUrl(),
67-
'user' => $user,
68-
])
69-
;
70-
71-
$this->mailer->send($email);
72-
} catch (TransportExceptionInterface $e) {
73-
$this->logger->critical("Can't send verification email to \"".$user->getEmail().'" '.$e->getMessage());
74-
}
57+
$this->mailer->send(
58+
$user->getEmail(),
59+
$this->translator->trans('user.verification.email', [], 'catroweb'),
60+
'security/registration/confirmation_email.html.twig',
61+
[
62+
'signedUrl' => $signatureComponents->getSignedUrl(),
63+
'user' => $user,
64+
]
65+
);
7566
}
7667
}

src/User/ResetPassword/PasswordResetRequestedSubscriber.php

+9-18
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,25 @@
33
namespace App\User\ResetPassword;
44

55
use App\Api\Services\Base\TranslatorAwareTrait;
6+
use App\System\Mail\MailerAdapter;
67
use App\User\UserManager;
78
use Psr\Log\LoggerInterface;
8-
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
99
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
10-
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
11-
use Symfony\Component\Mailer\MailerInterface;
12-
use Symfony\Component\Mime\Address;
1310
use Symfony\Contracts\Translation\TranslatorInterface;
1411
use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
1512
use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
1613

1714
class PasswordResetRequestedSubscriber implements EventSubscriberInterface
1815
{
1916
use TranslatorAwareTrait;
20-
protected MailerInterface $mailer;
17+
protected MailerAdapter $mailer;
2118
protected UserManager $user_manager;
2219
protected LoggerInterface $logger;
2320
protected ResetPasswordHelperInterface $reset_password_helper;
2421

2522
public function __construct(
2623
UserManager $user_manager,
27-
MailerInterface $mailer,
24+
MailerAdapter $mailer,
2825
LoggerInterface $logger,
2926
ResetPasswordHelperInterface $reset_password_helper,
3027
TranslatorInterface $translator)
@@ -56,18 +53,12 @@ protected function sendPasswordResetEmail(string $email, string $locale): void
5653
}
5754
$mailTo = $user->getEmail();
5855
try {
59-
$email = (new TemplatedEmail())
60-
->from(new Address('share@catrob.at'))
61-
->to($user->getEmail())
62-
->subject($this->__('passwordRecovery.subject', [], $locale))
63-
->htmlTemplate('security/reset_password/email.html.twig')
64-
->context([
65-
'resetToken' => $this->reset_password_helper->generateResetToken($user),
66-
])
67-
;
68-
$this->mailer->send($email);
69-
} catch (TransportExceptionInterface $e) {
70-
$this->logger->error("Can't send email to {$mailTo}; Reason ".$e->getMessage());
56+
$this->mailer->send(
57+
$user->getEmail(),
58+
$this->__('passwordRecovery.subject', [], $locale),
59+
'security/reset_password/email.html.twig',
60+
['resetToken' => $this->reset_password_helper->generateResetToken($user)]
61+
);
7162
} catch (ResetPasswordExceptionInterface $e) {
7263
$this->logger->error("Can't create reset token for {$mailTo}; Reason ".$e->getMessage());
7364
}

0 commit comments

Comments
 (0)