. * * 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\Tools\UserSecurity\TwoFactor; use Espo\Core\Authentication\TwoFactor\Email\EmailLogin; use Espo\Core\Exceptions\Forbidden; use Espo\Core\Exceptions\NotFound; use Espo\Core\Mail\Exceptions\SendingError; use Espo\Core\Utils\Config; use Espo\Core\Authentication\TwoFactor\Email\Util; use Espo\ORM\EntityManager; use Espo\Entities\User; class EmailService { public function __construct( private Util $util, private User $user, private EntityManager $entityManager, private Config $config ) {} /** * @throws Forbidden * @throws NotFound * @throws SendingError */ public function sendCode(string $userId, string $emailAddress): void { if (!$this->user->isAdmin() && $userId !== $this->user->getId()) { throw new Forbidden(); } $this->checkAllowed(); /** @var ?User $user */ $user = $this->entityManager->getEntityById(User::ENTITY_TYPE, $userId); if (!$user) { throw new NotFound(); } $this->util->sendCode($user, $emailAddress); $this->util->storeEmailAddress($user, $emailAddress); } /** * @throws Forbidden */ private function checkAllowed(): void { if (!$this->config->get('auth2FA')) { throw new Forbidden("2FA is not enabled."); } if ($this->user->isPortal() && !$this->config->get('auth2FAInPortal')) { throw new Forbidden("2FA is not enabled in portals."); } $methodList = $this->config->get('auth2FAMethodList') ?? []; if (!in_array(EmailLogin::NAME, $methodList)) { throw new Forbidden("Email 2FA is not allowed."); } } }