diff --git a/appinfo/info.xml b/appinfo/info.xml index e225c6c803ee71c9e33a6c886f9706f5bff6ea43..5b8030fa6a437e747c1245080ebbfcd7626164b6 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -5,7 +5,7 @@ Email Recovery Email Recovery App - 6.0.0 + 6.0.1 agpl MURENA SAS EmailRecovery diff --git a/lib/Listeners/UserConfigChangedListener.php b/lib/Listeners/UserConfigChangedListener.php index 10d845d09a72af177a8c2fcad6dfe4d529eecfa7..446257b1fd697ea28a1de72a9e6a23b6d8bd36d5 100644 --- a/lib/Listeners/UserConfigChangedListener.php +++ b/lib/Listeners/UserConfigChangedListener.php @@ -4,19 +4,22 @@ declare(strict_types=1); namespace OCA\EmailRecovery\Listeners; +use OCA\EmailRecovery\Service\RecoveryEmailService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\ILogger; use OCP\User\Events\UserConfigChangedEvent; -use OCA\EmailRecovery\Service\RecoveryEmailService; +use OCP\IUserManager; class UserConfigChangedListener implements IEventListener { private $logger; private $recoveryEmailService; + private $userManager; - public function __construct(ILogger $logger, RecoveryEmailService $recoveryEmailService) { + public function __construct(ILogger $logger, RecoveryEmailService $recoveryEmailService, IUserManager $userManager) { $this->logger = $logger; $this->recoveryEmailService = $recoveryEmailService; + $this->userManager = $userManager; } public function handle(Event $event): void { @@ -35,6 +38,19 @@ class UserConfigChangedListener implements IEventListener { $user = $event->getUserId(); $newRecoveryEmail = $event->getValue(); $this->recoveryEmailService->updateRecoveryEmailAtLDAPServer($user, $newRecoveryEmail); + + try { + $userData = $this->userManager->get($user); + $userEmailAddress = $userData->getEMailAddress(); + + if (empty($newRecoveryEmail)) { + $this->recoveryEmailService->restrictEmail($userEmailAddress); + } else { + $this->recoveryEmailService->unrestrictEmail($userEmailAddress); + } + } catch (\Throwable $e) { + $this->logger->error('Error in managing restricted list: '.$e->getMessage()); + } } } } diff --git a/lib/Service/CurlService.php b/lib/Service/CurlService.php new file mode 100644 index 0000000000000000000000000000000000000000..894856855d4d1408ebab0204dae37ff7736a67da --- /dev/null +++ b/lib/Service/CurlService.php @@ -0,0 +1,142 @@ +request('GET', $url, $params, $headers, $userOptions); + } + + /** + * POST alis for request method + * + * @param $url + * @param array $params + * @param array $headers + * @param array $userOptions + * @return mixed + */ + public function post($url, $params = array(), $headers = array(), $userOptions = array()) { + return $this->request('POST', $url, $params, $headers, $userOptions); + } + + public function delete($url, $params = [], $headers = [], $userOptions = []) { + return $this->request('DELETE', $url, $params, $headers, $userOptions); + } + + public function put($url, $params = [], $headers = [], $userOptions = []) { + return $this->request('PUT', $url, $params, $headers, $userOptions); + } + + /** + * @return int + */ + + public function getLastStatusCode() : int { + return $this->lastStatusCode; + } + + private function buildPostData($params = [], $headers = []) { + $jsonContent = in_array('Content-Type: application/json', $headers); + if ($jsonContent) { + $params = json_encode($params); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new Exception('JSON encoding failed: ' . json_last_error_msg()); + } + return $params; + } + + $formContent = in_array('Content-Type: application/x-www-form-urlencoded', $headers); + if ($formContent) { + $params = http_build_query($params); + return $params; + } + + return $params; + } + + /** + * Curl run request + * + * @param $method + * @param string $url + * @param array $params + * @param array $headers + * @param array $userOptions + * @return mixed + * @throws Exception + */ + private function request($method, $url, $params = array(), $headers = array(), $userOptions = array()) { + $ch = curl_init(); + $method = strtoupper($method); + $options = array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => $headers + ); + foreach ($userOptions as $key => $value) { + $options[$key] = $value; + } + switch ($method) { + case 'GET': + if ($params) { + $url = $url . '?' . http_build_query($params); + } + break; + case 'POST': + $options[CURLOPT_POST] = true; + $options[CURLOPT_POSTFIELDS] = $this->buildPostData($params, $headers); + break; + case 'DELETE': + $options[CURLOPT_CUSTOMREQUEST] = "DELETE"; + if ($params) { + $url = $url . '?' . http_build_query($params); + } + break; + case 'PUT': + $options[CURLOPT_CUSTOMREQUEST] = "PUT"; + $options[CURLOPT_POSTFIELDS] = $this->buildPostData($params, $headers); + break; + default: + throw new Exception('Unsupported method.'); + break; + } + $options[CURLOPT_URL] = $url; + + curl_setopt_array($ch, $options); + + $response = curl_exec($ch); + + $this->lastStatusCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + + + if ($errno = curl_errno($ch)) { + $errorMessage = curl_strerror($errno); + throw new Exception("Curl error $errno - $errorMessage"); + } + + curl_close($ch); + + return $response; + } +} diff --git a/lib/Service/RecoveryEmailService.php b/lib/Service/RecoveryEmailService.php index 3ed2384ac4dbcfc8b5c7ae04b66f0511c85ded4c..1b01bd65472def1bd2bd0214cc8fcd12b2735e90 100644 --- a/lib/Service/RecoveryEmailService.php +++ b/lib/Service/RecoveryEmailService.php @@ -5,23 +5,23 @@ declare(strict_types=1); namespace OCA\EmailRecovery\Service; use Exception; -use OCP\ILogger; -use OCP\IConfig; -use OCP\IUserManager; +use OCA\EcloudAccounts\Service\LDAPConnectionService; +use OCA\EmailRecovery\Exception\BlacklistedEmailException; use OCA\EmailRecovery\Exception\InvalidRecoveryEmailException; -use OCA\EmailRecovery\Exception\SameRecoveryEmailAsEmailException; -use OCA\EmailRecovery\Exception\RecoveryEmailAlreadyFoundException; use OCA\EmailRecovery\Exception\MurenaDomainDisallowedException; -use OCA\EmailRecovery\Exception\BlacklistedEmailException; -use OCA\EcloudAccounts\Service\LDAPConnectionService; -use OCP\Mail\IEMailTemplate; -use OCP\Mail\IMailer; -use OCP\Util; +use OCA\EmailRecovery\Exception\RecoveryEmailAlreadyFoundException; +use OCA\EmailRecovery\Exception\SameRecoveryEmailAsEmailException; +use OCP\Defaults; +use OCP\IConfig; +use OCP\ILogger; +use OCP\IURLGenerator; use OCP\IUser; +use OCP\IUserManager; use OCP\L10N\IFactory; -use OCP\IURLGenerator; -use OCP\Defaults; +use OCP\Mail\IEMailTemplate; +use OCP\Mail\IMailer; use OCP\Security\VerificationToken\IVerificationToken; +use OCP\Util; class RecoveryEmailService { private ILogger $logger; @@ -34,9 +34,11 @@ class RecoveryEmailService { private IURLGenerator $urlGenerator; private Defaults $themingDefaults; private IVerificationToken $verificationToken; + private CurlService $curl; + private array $apiConfig; protected const TOKEN_LIFETIME = 60 * 30; // 30 minutes - public function __construct(string $appName, ILogger $logger, IConfig $config, LDAPConnectionService $LDAPConnectionService, IUserManager $userManager, IMailer $mailer, IFactory $l10nFactory, IURLGenerator $urlGenerator, Defaults $themingDefaults, IVerificationToken $verificationToken) { + public function __construct(string $appName, ILogger $logger, IConfig $config, LDAPConnectionService $LDAPConnectionService, IUserManager $userManager, IMailer $mailer, IFactory $l10nFactory, IURLGenerator $urlGenerator, Defaults $themingDefaults, IVerificationToken $verificationToken, CurlService $curlService) { $this->logger = $logger; $this->config = $config; $this->appName = $appName; @@ -47,6 +49,17 @@ class RecoveryEmailService { $this->urlGenerator = $urlGenerator; $this->themingDefaults = $themingDefaults; $this->verificationToken = $verificationToken; + $this->curl = $curlService; + $commonServiceURL = $this->config->getSystemValue('common_services_url', ''); + + if (!empty($commonServiceURL)) { + $commonServiceURL = rtrim($commonServiceURL, '/') . '/'; + } + $this->apiConfig = [ + 'commonServicesURL' => $commonServiceURL, + 'commonServicesToken' => $this->config->getSystemValue('common_services_token', ''), + 'commonApiVersion' => $this->config->getSystemValue('common_api_version', '') + ]; } public function setRecoveryEmail(string $username, string $value = '') : void { $this->config->setUserValue($username, $this->appName, 'recovery-email', $value); @@ -235,4 +248,51 @@ class RecoveryEmailService { // Check if the email domain is in the blacklisted domains array return in_array($emailDomain, $blacklistedDomains); } + + private function manageEmailRestriction(string $email, string $method, string $url) : void { + $params = []; + + $token = $this->apiConfig['commonServicesToken']; + $headers = [ + "Authorization: Bearer $token" + ]; + + if ($method === 'POST') { + $this->curl->post($url, $params, $headers); + } elseif ($method === 'DELETE') { + $this->curl->delete($url, $params, $headers); + } + + if ($this->curl->getLastStatusCode() !== 200) { + throw new Exception('Error ' . strtolower($method) . 'ing email ' . $email . ' in restricted list. Status Code: ' . $this->curl->getLastStatusCode()); + } + } + + public function restrictEmail(string $email) : void { + $commonServicesURL = $this->apiConfig['commonServicesURL']; + $commonApiVersion = $this->apiConfig['commonApiVersion']; + + if (!isset($commonServicesURL) || empty($commonServicesURL)) { + return; + } + + $endpoint = $commonApiVersion . '/emails/restricted/' . $email; + $url = $commonServicesURL . $endpoint; // POST /v2/emails/restricted/@email + + $this->manageEmailRestriction($email, 'POST', $url); + } + + public function unrestrictEmail(string $email) : void { + $commonServicesURL = $this->apiConfig['commonServicesURL']; + $commonApiVersion = $this->apiConfig['commonApiVersion']; + + if (!isset($commonServicesURL) || empty($commonServicesURL)) { + return; + } + + $endpoint = $commonApiVersion . '/emails/restricted/' . $email; + $url = $commonServicesURL . $endpoint; // DELETE /v2/emails/restricted/@email + + $this->manageEmailRestriction($email, 'DELETE', $url); + } }