From 3347b7fba8e5d6a4a73e7cad5eeb9628238e5dcf Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Mon, 8 Jul 2024 18:43:32 +0300 Subject: [PATCH] email from address check --- .../RecordHooks/Email/CheckFromAddress.php | 94 +++++++++++++++++++ .../Resources/metadata/recordDefs/Email.json | 2 + application/Espo/Tools/Email/SendService.php | 1 + 3 files changed, 97 insertions(+) create mode 100644 application/Espo/Classes/RecordHooks/Email/CheckFromAddress.php diff --git a/application/Espo/Classes/RecordHooks/Email/CheckFromAddress.php b/application/Espo/Classes/RecordHooks/Email/CheckFromAddress.php new file mode 100644 index 0000000000..361fac81f1 --- /dev/null +++ b/application/Espo/Classes/RecordHooks/Email/CheckFromAddress.php @@ -0,0 +1,94 @@ +. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +namespace Espo\Classes\RecordHooks\Email; + +use Espo\Core\Acl; +use Espo\Core\Exceptions\BadRequest; +use Espo\Core\Exceptions\Forbidden; +use Espo\Core\Mail\Account\SendingAccountProvider; +use Espo\Core\Record\Hook\SaveHook; +use Espo\Core\Utils\Config; +use Espo\Entities\Email; +use Espo\Entities\User; +use Espo\ORM\Entity; + +/** + * @implements SaveHook + */ +class CheckFromAddress implements SaveHook +{ + public function __construct( + private User $user, + private SendingAccountProvider $sendingAccountProvider, + private Config $config, + private Acl $acl, + ) {} + + public function process(Entity $entity): void + { + if ($this->user->isAdmin()) { + return; + } + + if (!$entity->getFromAddress()) { + throw new BadRequest("No 'from' address"); + } + + if ($this->acl->checkScope('Import')) { + return; + } + + $fromAddress = strtolower($entity->getFromAddress()); + + foreach ($this->user->getEmailAddressGroup()->getAddressList() as $address) { + if ($fromAddress === strtolower($address)) { + return; + } + } + + if ($this->sendingAccountProvider->getShared($this->user, $fromAddress)) { + return; + } + + $system = $this->sendingAccountProvider->getSystem(); + + if ( + $system && + $this->config->get('outboundEmailIsShared') && + $system->getEmailAddress() + ) { + if ($fromAddress === strtolower($system->getEmailAddress())) { + return; + } + } + + throw new Forbidden("Not allowed 'from' address."); + } +} diff --git a/application/Espo/Resources/metadata/recordDefs/Email.json b/application/Espo/Resources/metadata/recordDefs/Email.json index e31b3eaa92..dcb7e4b514 100644 --- a/application/Espo/Resources/metadata/recordDefs/Email.json +++ b/application/Espo/Resources/metadata/recordDefs/Email.json @@ -40,9 +40,11 @@ "Espo\\Classes\\RecordHooks\\Email\\MarkAsRead" ], "beforeCreateHookClassNameList": [ + "Espo\\Classes\\RecordHooks\\Email\\CheckFromAddress", "Espo\\Classes\\RecordHooks\\Email\\BeforeCreate" ], "beforeUpdateHookClassNameList": [ + "Espo\\Classes\\RecordHooks\\Email\\CheckFromAddress", "Espo\\Classes\\RecordHooks\\Email\\MarkAsReadBeforeUpdate", "Espo\\Classes\\RecordHooks\\Email\\BeforeUpdate" ], diff --git a/application/Espo/Tools/Email/SendService.php b/application/Espo/Tools/Email/SendService.php index 3a09915b01..985bf84552 100644 --- a/application/Espo/Tools/Email/SendService.php +++ b/application/Espo/Tools/Email/SendService.php @@ -138,6 +138,7 @@ class SendService $userAddressList = []; if ($user) { + // @todo Use getEmailAddressGroup. /** @var Collection $emailAddressCollection */ $emailAddressCollection = $this->entityManager ->getRDBRepositoryByClass(User::class)