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:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2022-07-01 16:10:21 +0300
committerChristoph Wurst <christoph@winzerhof-wurst.at>2022-07-01 17:09:14 +0300
commit78704879b437a93cc3028418cfd65cbee886ee81 (patch)
tree4b1016d6d4122d5a78ef48b56721973d37c6ede8
parentff28c48255c1247228c777b52a786667f5b4c0b3 (diff)
Add support for XOAUTH2
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
-rw-r--r--appinfo/info.xml2
-rw-r--r--lib/Command/CreateAccount.php5
-rw-r--r--lib/Db/MailAccount.php3
-rw-r--r--lib/IMAP/IMAPClientFactory.php12
-rw-r--r--lib/Migration/Version1140Date20220701103556.php59
-rw-r--r--tests/Unit/Command/CreateAccountTest.php13
6 files changed, 87 insertions, 7 deletions
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 8ada4faff..fbd1a3c66 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -12,7 +12,7 @@
- **🙈 We’re not reinventing the wheel!** Based on the great [Horde](https://horde.org) libraries.
- **📬 Want to host your own mail server?** We do not have to reimplement this as you could set up [Mail-in-a-Box](https://mailinabox.email)!
]]></description>
- <version>1.14.0-alpha.3</version>
+ <version>1.14.0-alpha.4</version>
<licence>agpl</licence>
<author>Greta Doçi</author>
<author homepage="https://github.com/nextcloud/groupware">Nextcloud Groupware Team</author>
diff --git a/lib/Command/CreateAccount.php b/lib/Command/CreateAccount.php
index a1b95a283..fd8a428a3 100644
--- a/lib/Command/CreateAccount.php
+++ b/lib/Command/CreateAccount.php
@@ -36,6 +36,7 @@ class CreateAccount extends Command {
public const ARGUMENT_USER_ID = 'user-id';
public const ARGUMENT_NAME = 'name';
public const ARGUMENT_EMAIL = 'email';
+ public const ARGUMENT_AUTH_METHOD = 'auth-method';
public const ARGUMENT_IMAP_HOST = 'imap-host';
public const ARGUMENT_IMAP_PORT = 'imap-port';
public const ARGUMENT_IMAP_SSL_MODE = 'imap-ssl-mode';
@@ -87,12 +88,15 @@ class CreateAccount extends Command {
$this->addArgument(self::ARGUMENT_SMTP_SSL_MODE, InputArgument::REQUIRED);
$this->addArgument(self::ARGUMENT_SMTP_USER, InputArgument::REQUIRED);
$this->addArgument(self::ARGUMENT_SMTP_PASSWORD, InputArgument::REQUIRED);
+
+ $this->addArgument(self::ARGUMENT_AUTH_METHOD, InputArgument::OPTIONAL, 'password or xoauth2', 'password');
}
protected function execute(InputInterface $input, OutputInterface $output): int {
$userId = $input->getArgument(self::ARGUMENT_USER_ID);
$name = $input->getArgument(self::ARGUMENT_NAME);
$email = $input->getArgument(self::ARGUMENT_EMAIL);
+ $authMethod = $input->getArgument(self::ARGUMENT_AUTH_METHOD);
$imapHost = $input->getArgument(self::ARGUMENT_IMAP_HOST);
$imapPort = $input->getArgument(self::ARGUMENT_IMAP_PORT);
@@ -115,6 +119,7 @@ class CreateAccount extends Command {
$account->setUserId($userId);
$account->setName($name);
$account->setEmail($email);
+ $account->setAuthMethod($authMethod);
$account->setInboundHost($imapHost);
$account->setInboundPort((int) $imapPort);
diff --git a/lib/Db/MailAccount.php b/lib/Db/MailAccount.php
index 7703165b8..b24ca0729 100644
--- a/lib/Db/MailAccount.php
+++ b/lib/Db/MailAccount.php
@@ -91,6 +91,8 @@ use OCP\AppFramework\Db\Entity;
* @method void setSievePassword(?string $sievePassword)
* @method bool|null isSignatureAboveQuote()
* @method void setSignatureAboveQuote(bool $signatureAboveQuote)
+ * @method string getAuthMethod()
+ * @method void setAuthMethod(string $method)
*/
class MailAccount extends Entity {
protected $userId;
@@ -112,6 +114,7 @@ class MailAccount extends Entity {
protected $order;
protected $showSubscribedOnly;
protected $personalNamespace;
+ protected $authMethod;
/** @var int|null */
protected $draftsMailboxId;
diff --git a/lib/IMAP/IMAPClientFactory.php b/lib/IMAP/IMAPClientFactory.php
index 236e2a329..b7bf596f0 100644
--- a/lib/IMAP/IMAPClientFactory.php
+++ b/lib/IMAP/IMAPClientFactory.php
@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace OCA\Mail\IMAP;
+use Horde_Imap_Client_Password_Xoauth2;
use Horde_Imap_Client_Socket;
use OCA\Mail\Account;
use OCA\Mail\Cache\Cache;
@@ -66,8 +67,7 @@ class IMAPClientFactory {
public function getClient(Account $account, bool $useCache = true): Horde_Imap_Client_Socket {
$host = $account->getMailAccount()->getInboundHost();
$user = $account->getMailAccount()->getInboundUser();
- $password = $account->getMailAccount()->getInboundPassword();
- $password = $this->crypto->decrypt($password);
+ $decryptedPassword = $this->crypto->decrypt($account->getMailAccount()->getInboundPassword());
$port = $account->getMailAccount()->getInboundPort();
$sslMode = $account->getMailAccount()->getInboundSslMode();
if ($sslMode === 'none') {
@@ -76,7 +76,7 @@ class IMAPClientFactory {
$params = [
'username' => $user,
- 'password' => $password,
+ 'password' => $decryptedPassword,
'hostspec' => $host,
'port' => $port,
'secure' => $sslMode,
@@ -88,6 +88,12 @@ class IMAPClientFactory {
],
],
];
+ if ($account->getMailAccount()->getAuthMethod() === 'xoauth2') {
+ $params['xoauth2_token'] = new Horde_Imap_Client_Password_Xoauth2(
+ $account->getEmail(),
+ $decryptedPassword,
+ );
+ }
if ($useCache && $this->cacheFactory->isAvailable()) {
$params['cache'] = [
'backend' => new Cache([
diff --git a/lib/Migration/Version1140Date20220701103556.php b/lib/Migration/Version1140Date20220701103556.php
new file mode 100644
index 000000000..6d21fea34
--- /dev/null
+++ b/lib/Migration/Version1140Date20220701103556.php
@@ -0,0 +1,59 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @author 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\Migration;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\DB\Types;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+class Version1140Date20220701103556 extends SimpleMigrationStep {
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ $accountsTable = $schema->getTable('mail_accounts');
+ if (!$accountsTable->hasColumn('auth_method')) {
+ $accountsTable->addColumn(
+ 'auth_method',
+ Types::STRING,
+ [
+ 'notnull' => true,
+ 'default' => 'password',
+ ],
+ );
+ }
+
+ return $schema;
+ }
+}
diff --git a/tests/Unit/Command/CreateAccountTest.php b/tests/Unit/Command/CreateAccountTest.php
index a86fe7f0c..1102ee6c2 100644
--- a/tests/Unit/Command/CreateAccountTest.php
+++ b/tests/Unit/Command/CreateAccountTest.php
@@ -1,5 +1,7 @@
<?php
+declare(strict_types=1);
+
/**
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
*
@@ -46,6 +48,7 @@ class CreateAccountTest extends TestCase {
'smtp-ssl-mode',
'smtp-user',
'smtp-password',
+ 'auth-method',
];
protected function setUp(): void {
@@ -72,8 +75,12 @@ class CreateAccountTest extends TestCase {
$actual = $this->command->getDefinition()->getArguments();
foreach ($actual as $actArg) {
- $this->assertTrue($actArg->isRequired());
- $this->assertTrue(in_array($actArg->getName(), $this->args));
+ if ($actArg->getName() === 'auth-method') {
+ self::assertFalse($actArg->isRequired());
+ } else {
+ self::assertTrue($actArg->isRequired());
+ }
+ self::assertTrue(in_array($actArg->getName(), $this->args));
}
}
@@ -98,7 +105,7 @@ class CreateAccountTest extends TestCase {
$input = $this->createMock(InputInterface::class);
$input->method('getArgument')
->willReturnCallback(function ($arg) use ($data) {
- return $data[$arg];
+ return $data[$arg] ?? null;
});
$output = $this->createMock(OutputInterface::class);
$output->expects($this->once())