Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/mail.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Larch <anna@nextcloud.com>2021-04-15 14:27:03 +0300
committerChristoph Wurst <christoph@winzerhof-wurst.at>2021-05-28 10:17:14 +0300
commit537a766a12b74a3118e8993a5370ae250b96645d (patch)
tree4f32a74cde113fea1b2097690c62528504df8c3b /lib/Service
parent8c8d71e37ad87a3303c0dbe09ab39098893c50c1 (diff)
Add option to use multiple configs for mail provisioning
Signed-off-by: Anna Larch <anna@nextcloud.com> Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib/Service')
-rw-r--r--lib/Service/Provisioning/Config.php187
-rw-r--r--lib/Service/Provisioning/ConfigMapper.php62
-rw-r--r--lib/Service/Provisioning/Manager.php167
3 files changed, 99 insertions, 317 deletions
diff --git a/lib/Service/Provisioning/Config.php b/lib/Service/Provisioning/Config.php
deleted file mode 100644
index 74b8cda8d..000000000
--- a/lib/Service/Provisioning/Config.php
+++ /dev/null
@@ -1,187 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * Mail
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License, version 3,
- * along with this program. If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-namespace OCA\Mail\Service\Provisioning;
-
-use JsonSerializable;
-use OCP\IUser;
-
-class Config implements JsonSerializable {
- private const VERSION = 1;
-
- /** @var mixed[] */
- private $data;
-
- /**
- * @param array $data
- */
- public function __construct(array $data) {
- $this->data = $data;
- }
-
- /**
- * @param IUser $user
- * @return string
- */
- public function buildEmail(IUser $user) {
- return $this->buildUserEmail($this->data['email'], $user);
- }
-
- /**
- * @return string
- */
- public function getImapHost() {
- return $this->data['imapHost'];
- }
-
- /**
- * @return int
- */
- public function getImapPort(): int {
- return (int) $this->data['imapPort'];
- }
-
- /**
- * @return string
- */
- public function buildImapUser(IUser $user) {
- if (isset($this->data['imapUser'])) {
- return $this->buildUserEmail($this->data['imapUser'], $user);
- }
- return $this->buildEmail($user);
- }
-
- /**
- * @return string
- */
- public function getImapSslMode() {
- return $this->data['imapSslMode'];
- }
-
- /**
- * @return string
- */
- public function getSmtpHost() {
- return $this->data['smtpHost'];
- }
-
- /**
- * @return int
- */
- public function getSmtpPort(): int {
- return (int) $this->data['smtpPort'];
- }
-
- /**
- * @param IUser $user
- * @return string
- */
- public function buildSmtpUser(IUser $user) {
- if (isset($this->data['smtpUser'])) {
- return $this->buildUserEmail($this->data['smtpUser'], $user);
- }
- return $this->buildEmail($user);
- }
-
- /**
- * @return string
- */
- public function getSmtpSslMode() {
- return $this->data['smtpSslMode'];
- }
-
- /**
- * @return boolean
- */
- public function getSieveEnabled(): bool {
- return (bool)$this->data['sieveEnabled'];
- }
-
- /**
- * @return string
- */
- public function getSieveHost() {
- return $this->data['sieveHost'];
- }
-
- /**
- * @return int
- */
- public function getSievePort(): int {
- return (int)$this->data['sievePort'];
- }
-
- /**
- * @param IUser $user
- * @return string
- */
- public function buildSieveUser(IUser $user) {
- if (isset($this->data['sieveUser'])) {
- return $this->buildUserEmail($this->data['sieveUser'], $user);
- }
- return $this->buildEmail($user);
- }
-
- /**
- * @return string
- */
- public function getSieveSslMode() {
- return $this->data['sieveSslMode'];
- }
-
- /**
- * Replace %USERID% and %EMAIL% to allow special configurations
- *
- * @param string $original
- * @param IUser $user
- * @return string
- */
- private function buildUserEmail(string $original, IUser $user) {
- if ($user->getUID() !== null) {
- $original = str_replace('%USERID%', $user->getUID(), $original);
- }
- if ($user->getEMailAddress() !== null) {
- $original = str_replace('%EMAIL%', $user->getEMailAddress(), $original);
- }
- return $original;
- }
-
- public function setActive(bool $state): self {
- $this->data['active'] = $state;
- return $this;
- }
-
- public function isActive(): bool {
- return (bool) ($this->data['active'] ?? true);
- }
-
- public function jsonSerialize() {
- return array_merge(
- [
- 'active' => false,
- 'version' => self::VERSION,
- ],
- $this->data
- );
- }
-}
diff --git a/lib/Service/Provisioning/ConfigMapper.php b/lib/Service/Provisioning/ConfigMapper.php
deleted file mode 100644
index 2f9b2de31..000000000
--- a/lib/Service/Provisioning/ConfigMapper.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace OCA\Mail\Service\Provisioning;
-
-use OCA\Mail\AppInfo\Application;
-use OCP\IConfig;
-
-class ConfigMapper {
- private const CONFIG_KEY = 'provisioning_settings';
-
- /** @var IConfig */
- private $config;
-
- public function __construct(IConfig $config) {
- $this->config = $config;
- }
-
- public function load(): ?Config {
- $raw = $this->config->getAppValue(
- Application::APP_ID,
- self::CONFIG_KEY
- );
- if ($raw === '') {
- // Not config set yet
- return null;
- }
- return new Config(json_decode($raw, true));
- }
-
- public function save(Config $config): Config {
- $this->config->setAppValue(
- Application::APP_ID,
- self::CONFIG_KEY,
- json_encode($config)
- );
-
- return $config;
- }
-}
diff --git a/lib/Service/Provisioning/Manager.php b/lib/Service/Provisioning/Manager.php
index 742c87f13..8cc9c2e06 100644
--- a/lib/Service/Provisioning/Manager.php
+++ b/lib/Service/Provisioning/Manager.php
@@ -23,9 +23,14 @@ declare(strict_types=1);
namespace OCA\Mail\Service\Provisioning;
+use Horde_Mail_Rfc822_Address;
use OCA\Mail\Db\MailAccount;
use OCA\Mail\Db\MailAccountMapper;
+use OCA\Mail\Db\Provisioning;
+use OCA\Mail\Db\ProvisioningMapper;
+use OCA\Mail\Exception\ValidationException;
use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Security\ICrypto;
@@ -36,8 +41,8 @@ class Manager {
/** @var IUserManager */
private $userManager;
- /** @var ConfigMapper */
- private $configMapper;
+ /** @var ProvisioningMapper */
+ private $provisioningMapper;
/** @var MailAccountMapper */
private $mailAccountMapper;
@@ -49,85 +54,106 @@ class Manager {
private $logger;
public function __construct(IUserManager $userManager,
- ConfigMapper $configMapper,
+ ProvisioningMapper $provisioningMapper,
MailAccountMapper $mailAccountMapper,
ICrypto $crypto,
LoggerInterface $logger) {
$this->userManager = $userManager;
- $this->configMapper = $configMapper;
+ $this->provisioningMapper = $provisioningMapper;
$this->mailAccountMapper = $mailAccountMapper;
$this->crypto = $crypto;
$this->logger = $logger;
}
- public function getConfig(): ?Config {
- return $this->configMapper->load();
+ public function getConfigById(int $provisioningId): ?Provisioning {
+ return $this->provisioningMapper->get($provisioningId);
}
- public function provision(Config $config): int {
+ public function getConfigs(): array {
+ return $this->provisioningMapper->getAll();
+ }
+
+ public function provision(): int {
$cnt = 0;
- $this->userManager->callForAllUsers(function (IUser $user) use ($config, &$cnt) {
- $this->provisionSingleUser($config, $user);
- $cnt++;
+ $configs = $this->getConfigs();
+ $this->userManager->callForAllUsers(function (IUser $user) use ($configs, &$cnt) {
+ if ($this->provisionSingleUser($configs, $user) === true) {
+ $cnt++;
+ }
});
return $cnt;
}
- public function provisionSingleUser(Config $config, IUser $user): void {
+ /**
+ * @param Provisioning[] $provisionings
+ */
+ public function provisionSingleUser(array $provisionings, IUser $user): bool {
+ $provisioning = $this->findMatchingConfig($provisionings, $user);
+
+ if ($provisioning === null) {
+ return false;
+ }
+
try {
+ // TODO: match by UID only, catch multiple objects returned below and delete all those accounts
$existing = $this->mailAccountMapper->findProvisionedAccount($user);
$this->mailAccountMapper->update(
- $this->updateAccount($user, $existing, $config)
+ $this->updateAccount($user, $existing, $provisioning)
);
+ return true;
} catch (DoesNotExistException $e) {
// Fine, then we create a new one
$new = new MailAccount();
$new->setUserId($user->getUID());
- $new->setProvisioned(true);
$this->mailAccountMapper->insert(
- $this->updateAccount($user, $new, $config)
+ $this->updateAccount($user, $new, $provisioning)
);
+ return true;
+ } catch (MultipleObjectsReturnedException $e) {
+ // This is unlikely to happen but not impossible.
+ // Let's wipe any existing accounts and start fresh
+ $this->mailAccountMapper->deleteProvisionedAccountsByUid($user->getUID());
+
+ $new = new MailAccount();
+ $new->setUserId($user->getUID());
+
+ $this->mailAccountMapper->insert(
+ $this->updateAccount($user, $new, $provisioning)
+ );
+ return true;
}
+ return false;
}
- public function newProvisioning(string $email,
- string $imapUser,
- string $imapHost,
- int $imapPort,
- string $imapSslMode,
- string $smtpUser,
- string $smtpHost,
- int $smtpPort,
- string $smtpSslMode,
- bool $sieveEnabled,
- string $sieveUser,
- string $sieveHost,
- int $sievePort,
- string $sieveSslMode): void {
- $config = $this->configMapper->save(new Config([
- 'active' => true,
- 'email' => $email,
- 'imapUser' => $imapUser,
- 'imapHost' => $imapHost,
- 'imapPort' => $imapPort,
- 'imapSslMode' => $imapSslMode,
- 'smtpUser' => $smtpUser,
- 'smtpHost' => $smtpHost,
- 'smtpPort' => $smtpPort,
- 'smtpSslMode' => $smtpSslMode,
- 'sieveEnabled' => $sieveEnabled,
- 'sieveUser' => $sieveUser,
- 'sieveHost' => $sieveHost,
- 'sievePort' => $sievePort,
- 'sieveSslMode' => $sieveSslMode,
- ]));
-
- $this->provision($config);
+ public function newProvisioning(array $data): void {
+ try {
+ $provisioning = $this->provisioningMapper->validate(
+ $data
+ );
+ } catch (ValidationException $e) {
+ throw $e;
+ }
+ $this->provisioningMapper->insert($provisioning);
}
- private function updateAccount(IUser $user, MailAccount $account, Config $config): MailAccount {
+ public function updateProvisioning(array $data): void {
+ try {
+ $provisioning = $this->provisioningMapper->validate(
+ $data
+ );
+ } catch (ValidationException $e) {
+ throw $e;
+ }
+
+ $this->provisioningMapper->update($provisioning);
+ }
+
+ private function updateAccount(IUser $user, MailAccount $account, Provisioning $config): MailAccount {
+ // Set the ID to make sure it reflects when the account switches from one config to another
+ $account->setProvisioningId($config->getId());
+
$account->setEmail($config->buildEmail($user));
$account->setName($user->getDisplayName());
$account->setInboundUser($config->buildImapUser($user));
@@ -155,26 +181,9 @@ class Manager {
return $account;
}
- public function deprovision(): void {
- $this->mailAccountMapper->deleteProvisionedAccounts();
-
- $config = $this->configMapper->load();
- if ($config !== null) {
- $config->setActive(false);
- $this->configMapper->save($config);
- }
- }
-
- public function importConfig(array $data): Config {
- if (!isset($data['imapUser'])) {
- $data['imapUser'] = $data['email'];
- }
- if (!isset($data['smtpUser'])) {
- $data['smtpUser'] = $data['email'];
- }
- $data['active'] = true;
-
- return $this->configMapper->save(new Config($data));
+ public function deprovision(Provisioning $provisioning): void {
+ $this->mailAccountMapper->deleteProvisionedAccounts($provisioning->getId());
+ $this->provisioningMapper->delete($provisioning);
}
public function updatePassword(IUser $user, string $password): void {
@@ -198,4 +207,26 @@ class Manager {
// Nothing to update
}
}
+
+ /**
+ * @param Provisioning[] $provisionings
+ */
+ private function findMatchingConfig(array $provisionings, IUser $user): ?Provisioning {
+ foreach ($provisionings as $provisioning) {
+ if ($provisioning->getProvisioningDomain() === Provisioning::WILDCARD) {
+ return $provisioning;
+ }
+
+ $email = $user->getEMailAddress();
+ if ($email === null) {
+ continue;
+ }
+ $rfc822Address = new Horde_Mail_Rfc822_Address($email);
+ if ($rfc822Address->matchDomain($provisioning->getProvisioningDomain())) {
+ return $provisioning;
+ }
+ }
+
+ return null;
+ }
}