diff --git a/application/Espo/Core/Authentication/TwoFactor/Exceptions/NotConfigured.php b/application/Espo/Core/Authentication/TwoFactor/Exceptions/NotConfigured.php new file mode 100644 index 0000000000..f1f803a99b --- /dev/null +++ b/application/Espo/Core/Authentication/TwoFactor/Exceptions/NotConfigured.php @@ -0,0 +1,35 @@ +config->get('smsProvider')) { + throw new NotConfigured("No SMS provider. Need to configure an SMS provider."); + } + return (object) [ 'phoneNumberList' => $user->getPhoneNumberGroup()->getNumberList(), ]; diff --git a/application/Espo/Core/Authentication/TwoFactor/UserSetup.php b/application/Espo/Core/Authentication/TwoFactor/UserSetup.php index d796110012..656910fd7c 100644 --- a/application/Espo/Core/Authentication/TwoFactor/UserSetup.php +++ b/application/Espo/Core/Authentication/TwoFactor/UserSetup.php @@ -29,6 +29,7 @@ namespace Espo\Core\Authentication\TwoFactor; +use Espo\Core\Authentication\TwoFactor\Exceptions\NotConfigured; use Espo\Core\Exceptions\BadRequest; use Espo\Entities\User; @@ -41,6 +42,8 @@ interface UserSetup { /** * Get data needed for configuration for a user. Data will be passed to the front-end. + * + * @throws NotConfigured */ public function getData(User $user): stdClass; diff --git a/application/Espo/Core/Sms/SenderFactory.php b/application/Espo/Core/Sms/SenderFactory.php index 6af489068d..f2efbccc12 100644 --- a/application/Espo/Core/Sms/SenderFactory.php +++ b/application/Espo/Core/Sms/SenderFactory.php @@ -59,7 +59,7 @@ class SenderFactory implements Factory $className = $this->metadata->get(['app', 'smsProviders', $provider, 'senderClassName']); if (!$className) { - throw new RuntimeException("No `senderClassName` for '{$provider}' provider."); + throw new RuntimeException("No `senderClassName` for '$provider' provider."); } return $this->injectableFactory->create($className); diff --git a/application/Espo/Core/Sms/SmsSender.php b/application/Espo/Core/Sms/SmsSender.php index 22a74a9241..39ede1d578 100644 --- a/application/Espo/Core/Sms/SmsSender.php +++ b/application/Espo/Core/Sms/SmsSender.php @@ -29,17 +29,31 @@ namespace Espo\Core\Sms; +use Espo\Core\InjectableFactory; use Espo\Entities\Sms as SmsEntity; - use Espo\Core\Utils\Config; class SmsSender { + private ?Sender $sender; + public function __construct( - private Sender $sender, + private InjectableFactory $injectableFactory, private Config $config ) {} + private function getSender(): Sender + { + if ($this->sender === null) { + // Sender factory can throw an exception (if no 'smsProvider' in config). + // Better it be thrown when sending rather than when instantiating + // constructor dependencies. + $this->sender = $this->injectableFactory->createResolved(Sender::class); + } + + return $this->sender; + } + public function send(SmsEntity $sms): void { $systemFromNumber = $this->config->get('outboundSmsFromNumber'); @@ -48,7 +62,7 @@ class SmsSender $sms->setFromNumber($systemFromNumber); } - $this->sender->send($sms); + $this->getSender()->send($sms); $sms->setAsSent(); } diff --git a/application/Espo/Tools/UserSecurity/Service.php b/application/Espo/Tools/UserSecurity/Service.php index 2a97facfca..6e93501bc7 100644 --- a/application/Espo/Tools/UserSecurity/Service.php +++ b/application/Espo/Tools/UserSecurity/Service.php @@ -29,6 +29,7 @@ namespace Espo\Tools\UserSecurity; +use Espo\Core\Authentication\TwoFactor\Exceptions\NotConfigured; use Espo\Core\Exceptions\Forbidden; use Espo\Core\Exceptions\NotFound; use Espo\Core\Exceptions\BadRequest; @@ -147,9 +148,14 @@ class Service throw new BadRequest(); } - $clientData = $this->twoFactorUserSetupFactory - ->create($auth2FAMethod) - ->getData($user); + try { + $clientData = $this->twoFactorUserSetupFactory + ->create($auth2FAMethod) + ->getData($user); + } + catch (NotConfigured $e) { + throw new Forbidden($e->getMessage()); + } if ($isReset) { $userData = $this->getUserDataRepository()->getByUserId($id);