From 09d7c73449162289df0b46888a997940863efcde Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 18 Oct 2022 21:16:27 +0300 Subject: [PATCH] ref --- application/Espo/Controllers/User.php | 4 +- .../ExtGroup/UserGroup/SendAccessInfoType.php | 2 +- .../Password/Jobs/SendAccessInfo.php | 5 +- .../Password/RecoveryService.php} | 69 +++++++++++++------ .../Tools/UserSecurity/Password/Service.php | 5 +- 5 files changed, 55 insertions(+), 30 deletions(-) rename application/Espo/{Core => Tools/UserSecurity}/Password/Jobs/SendAccessInfo.php (98%) rename application/Espo/{Core/Password/Recovery.php => Tools/UserSecurity/Password/RecoveryService.php} (88%) diff --git a/application/Espo/Controllers/User.php b/application/Espo/Controllers/User.php index d5b33b2139..bd01f7b091 100644 --- a/application/Espo/Controllers/User.php +++ b/application/Espo/Controllers/User.php @@ -39,7 +39,7 @@ use Espo\Services\User as Service; use Espo\Core\Api\Request; use Espo\Core\Controllers\Record; use Espo\Core\Mail\Exceptions\SendingError; -use Espo\Core\Password\Recovery; +use Espo\Tools\UserSecurity\Password\RecoveryService; use Espo\Core\Select\SearchParams; use Espo\Core\Select\Where\Item as WhereItem; @@ -140,7 +140,7 @@ class User extends Record } $this->injectableFactory - ->create(Recovery::class) + ->create(RecoveryService::class) ->request($emailAddress, $userName, $url); return true; diff --git a/application/Espo/Core/Formula/Functions/ExtGroup/UserGroup/SendAccessInfoType.php b/application/Espo/Core/Formula/Functions/ExtGroup/UserGroup/SendAccessInfoType.php index ec81317669..919c4d9806 100644 --- a/application/Espo/Core/Formula/Functions/ExtGroup/UserGroup/SendAccessInfoType.php +++ b/application/Espo/Core/Formula/Functions/ExtGroup/UserGroup/SendAccessInfoType.php @@ -33,7 +33,7 @@ use Espo\Core\Formula\Functions\BaseFunction; use Espo\Core\Formula\ArgumentList; use Espo\Core\Job\JobSchedulerFactory; -use Espo\Core\Password\Jobs\SendAccessInfo as SendAccessInfoJob; +use Espo\Tools\UserSecurity\Password\Jobs\SendAccessInfo as SendAccessInfoJob; use Espo\Core\Job\Job\Data as JobData; use Espo\Entities\User; diff --git a/application/Espo/Core/Password/Jobs/SendAccessInfo.php b/application/Espo/Tools/UserSecurity/Password/Jobs/SendAccessInfo.php similarity index 98% rename from application/Espo/Core/Password/Jobs/SendAccessInfo.php rename to application/Espo/Tools/UserSecurity/Password/Jobs/SendAccessInfo.php index f5e5a927e5..06115a646d 100644 --- a/application/Espo/Core/Password/Jobs/SendAccessInfo.php +++ b/application/Espo/Tools/UserSecurity/Password/Jobs/SendAccessInfo.php @@ -27,17 +27,14 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -namespace Espo\Core\Password\Jobs; +namespace Espo\Tools\UserSecurity\Password\Jobs; use Espo\Core\Mail\Exceptions\SendingError; use Espo\Entities\User; - use Espo\Core\Job\Job; use Espo\Core\Job\Job\Data; use Espo\Core\Exceptions\Error; - use Espo\ORM\EntityManager; - use Espo\Tools\UserSecurity\Password\Service as PasswordService; class SendAccessInfo implements Job diff --git a/application/Espo/Core/Password/Recovery.php b/application/Espo/Tools/UserSecurity/Password/RecoveryService.php similarity index 88% rename from application/Espo/Core/Password/Recovery.php rename to application/Espo/Tools/UserSecurity/Password/RecoveryService.php index 4aec7162b5..6eb08827ad 100644 --- a/application/Espo/Core/Password/Recovery.php +++ b/application/Espo/Tools/UserSecurity/Password/RecoveryService.php @@ -27,12 +27,16 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -namespace Espo\Core\Password; +namespace Espo\Tools\UserSecurity\Password; use Espo\Core\Job\JobSchedulerFactory; +use Espo\Core\Mail\Exceptions\NoSmtp; +use Espo\Core\Mail\Exceptions\SendingError; +use Espo\Core\Mail\SmtpParams; use Espo\Core\Utils\Util; use Espo\Core\Utils\Json; +use Espo\Entities\Email; use Espo\Entities\User; use Espo\Entities\PasswordChangeRequest; use Espo\Entities\Portal; @@ -55,7 +59,7 @@ use Espo\Core\Utils\Log; use Espo\Core\Utils\TemplateFileManager; use Espo\Tools\UserSecurity\Password\Jobs\RemoveRecoveryRequest; -class Recovery +class RecoveryService { /** Milliseconds. */ private const REQUEST_DELAY = 3000; @@ -114,6 +118,7 @@ class Recovery } $userId = $request->get('userId'); + if (!$userId) { throw new Error(); } @@ -139,6 +144,7 @@ class Recovery * @throws Forbidden * @throws NotFound * @throws Error + * @throws SendingError */ public function request(string $emailAddress, string $userName, ?string $url): bool { @@ -242,10 +248,14 @@ class Recovery return true; } + /** + * @throws Error + */ private function createRequestNoSave(User $user, ?string $url = null): PasswordChangeRequest { $this->checkUser($user); + /** @var PasswordChangeRequest $entity */ $entity = $this->entityManager->getNewEntity(PasswordChangeRequest::ENTITY_TYPE); $entity->set([ @@ -337,7 +347,7 @@ class Recovery return $this->config->get('passwordRecoveryRequestDelay') ?? self::REQUEST_DELAY; } - protected function delay(?int $delay = null): void + private function delay(?int $delay = null): void { if ($delay === null) { $delay = $this->getDelay(); @@ -346,13 +356,18 @@ class Recovery usleep($delay * 1000); } - protected function send(string $requestId, string $emailAddress, User $user): void + /** + * @throws Error + * @throws SendingError + */ + private function send(string $requestId, string $emailAddress, User $user): void { if (!$emailAddress) { return; } - $email = $this->entityManager->getNewEntity('Email'); + /** @var Email $email */ + $email = $this->entityManager->getNewEntity(Email::ENTITY_TYPE); if (!$this->emailSender->hasSystemSmtp() && !$this->config->get('internalSmtpServer')) { throw new Error("Password recovery: SMTP credentials are not defined."); @@ -366,7 +381,7 @@ class Recovery $siteUrl = $this->config->getSiteUrl(); if ($user->isPortal()) { - /** @var Portal|null $portal */ + /** @var ?Portal $portal */ $portal = $this->entityManager ->getRDBRepository(Portal::ENTITY_TYPE) ->distinct() @@ -401,31 +416,45 @@ class Recovery $subject = $htmlizer->render($user, $subjectTpl, null, $data, true); $body = $htmlizer->render($user, $bodyTpl, null, $data, true); + $email + ->setSubject($subject) + ->setBody($body) + ->addToAddress($emailAddress); + $email->set([ - 'subject' => $subject, - 'body' => $body, - 'to' => $emailAddress, 'isSystem' => true, ]); if (!$this->emailSender->hasSystemSmtp()) { - $sender->withSmtpParams([ - 'server' => $this->config->get('internalSmtpServer'), - 'port' => $this->config->get('internalSmtpPort'), - 'auth' => $this->config->get('internalSmtpAuth'), - 'username' => $this->config->get('internalSmtpUsername'), - 'password' => $this->config->get('internalSmtpPassword'), - 'security' => $this->config->get('internalSmtpSecurity'), - 'fromAddress' => $this->config->get( - 'internalOutboundEmailFromAddress', + $server = $this->config->get('internalSmtpServer'); + $port = $this->config->get('internalSmtpPort'); + + if (!$server || $port === null) { + throw new NoSmtp(); + } + + $smtpParams = SmtpParams + ::create($server, $port) + ->withAuth($this->config->get('internalSmtpAuth')) + ->withUsername($this->config->get('internalSmtpUsername')) + ->withPassword($this->config->get('internalSmtpPassword')) + ->withSecurity($this->config->get('internalSmtpSecurity')) + ->withFromName( + $this->config->get('internalOutboundEmailFromAddress') ?? $this->config->get('outboundEmailFromAddress') - ), - ]); + ); + + $sender->withSmtpParams($smtpParams); } $sender->send($email); } + /** + * @throws Forbidden + * @throws Error + * @throws NotFound + */ private function fail(?string $msg = null, int $errorCode = 403): void { $noExposure = $this->config->get('passwordRecoveryNoExposure') ?? false; diff --git a/application/Espo/Tools/UserSecurity/Password/Service.php b/application/Espo/Tools/UserSecurity/Password/Service.php index 525210ce7f..6178df74e7 100644 --- a/application/Espo/Tools/UserSecurity/Password/Service.php +++ b/application/Espo/Tools/UserSecurity/Password/Service.php @@ -36,7 +36,6 @@ use Espo\Core\Exceptions\NotFound; use Espo\Core\FieldValidation\FieldValidationManager; use Espo\Core\Mail\EmailSender; use Espo\Core\Mail\Exceptions\SendingError; -use Espo\Core\Password\Recovery; use Espo\Core\Record\ServiceContainer; use Espo\Core\Utils\Config; use Espo\Core\Utils\PasswordHash; @@ -53,7 +52,7 @@ class Service private Sender $sender; private PasswordHash $passwordHash; private EntityManager $entityManager; - private Recovery $recovery; + private RecoveryService $recovery; private FieldValidationManager $fieldValidationManager; private Checker $checker; @@ -66,7 +65,7 @@ class Service Sender $sender, PasswordHash $passwordHash, EntityManager $entityManager, - Recovery $recovery, + RecoveryService $recovery, FieldValidationManager $fieldValidationManager, Checker $checker ) {