mirror of
https://github.com/nextcloud/server.git
synced 2026-02-03 20:41:22 -05:00
feat(ocp): add email address validator
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
This commit is contained in:
parent
e0a21e5927
commit
336c6d2957
11 changed files with 190 additions and 43 deletions
|
|
@ -371,6 +371,12 @@
|
|||
</UndefinedMethod>
|
||||
</file>
|
||||
<file src="apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php">
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
</DeprecatedMethod>
|
||||
<LessSpecificReturnStatement>
|
||||
<code><![CDATA[$emailAddresses]]></code>
|
||||
</LessSpecificReturnStatement>
|
||||
|
|
@ -452,6 +458,9 @@
|
|||
</DeprecatedMethod>
|
||||
</file>
|
||||
<file src="apps/dav/lib/CalDAV/Schedule/IMipPlugin.php">
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
</DeprecatedMethod>
|
||||
<RedundantCast>
|
||||
<code><![CDATA[(string)$iTipMessage->recipientName]]></code>
|
||||
</RedundantCast>
|
||||
|
|
@ -864,6 +873,11 @@
|
|||
<code><![CDATA[getUserFolder]]></code>
|
||||
</DeprecatedMethod>
|
||||
</file>
|
||||
<file src="apps/dav/lib/Listener/CalendarContactInteractionListener.php">
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
</DeprecatedMethod>
|
||||
</file>
|
||||
<file src="apps/dav/lib/Migration/BuildCalendarSearchIndex.php">
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[getAppValue]]></code>
|
||||
|
|
@ -1572,6 +1586,7 @@
|
|||
</DeprecatedClass>
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[getAppValue]]></code>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
</DeprecatedMethod>
|
||||
<RedundantCast>
|
||||
<code><![CDATA[(int)$code]]></code>
|
||||
|
|
@ -2079,6 +2094,7 @@
|
|||
<code><![CDATA[getAppValue]]></code>
|
||||
<code><![CDATA[getAppValue]]></code>
|
||||
<code><![CDATA[setAppValue]]></code>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
</DeprecatedMethod>
|
||||
</file>
|
||||
<file src="apps/settings/lib/Controller/WebAuthnController.php">
|
||||
|
|
@ -2201,6 +2217,10 @@
|
|||
</DeprecatedMethod>
|
||||
</file>
|
||||
<file src="apps/sharebymail/lib/ShareByMailProvider.php">
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
</DeprecatedMethod>
|
||||
<InvalidArgument>
|
||||
<code><![CDATA[$share->getId()]]></code>
|
||||
<code><![CDATA[(int)$data['id']]]></code>
|
||||
|
|
@ -3053,6 +3073,11 @@
|
|||
<code><![CDATA[listen]]></code>
|
||||
</DeprecatedMethod>
|
||||
</file>
|
||||
<file src="core/Command/User/Add.php">
|
||||
<DeprecatedMethod>
|
||||
<code><![CDATA[validateMailAddress]]></code>
|
||||
</DeprecatedMethod>
|
||||
</file>
|
||||
<file src="core/Command/User/AuthTokens/Add.php">
|
||||
<DeprecatedClass>
|
||||
<code><![CDATA[IToken::DO_NOT_REMEMBER]]></code>
|
||||
|
|
|
|||
|
|
@ -655,6 +655,7 @@ return array(
|
|||
'OCP\\Mail\\Headers\\AutoSubmitted' => $baseDir . '/lib/public/Mail/Headers/AutoSubmitted.php',
|
||||
'OCP\\Mail\\IAttachment' => $baseDir . '/lib/public/Mail/IAttachment.php',
|
||||
'OCP\\Mail\\IEMailTemplate' => $baseDir . '/lib/public/Mail/IEMailTemplate.php',
|
||||
'OCP\\Mail\\IEmailValidator' => $baseDir . '/lib/public/Mail/IEmailValidator.php',
|
||||
'OCP\\Mail\\IMailer' => $baseDir . '/lib/public/Mail/IMailer.php',
|
||||
'OCP\\Mail\\IMessage' => $baseDir . '/lib/public/Mail/IMessage.php',
|
||||
'OCP\\Mail\\Provider\\Address' => $baseDir . '/lib/public/Mail/Provider/Address.php',
|
||||
|
|
@ -1820,6 +1821,7 @@ return array(
|
|||
'OC\\Log\\Systemdlog' => $baseDir . '/lib/private/Log/Systemdlog.php',
|
||||
'OC\\Mail\\Attachment' => $baseDir . '/lib/private/Mail/Attachment.php',
|
||||
'OC\\Mail\\EMailTemplate' => $baseDir . '/lib/private/Mail/EMailTemplate.php',
|
||||
'OC\\Mail\\EmailValidator' => $baseDir . '/lib/private/Mail/EmailValidator.php',
|
||||
'OC\\Mail\\Mailer' => $baseDir . '/lib/private/Mail/Mailer.php',
|
||||
'OC\\Mail\\Message' => $baseDir . '/lib/private/Mail/Message.php',
|
||||
'OC\\Mail\\Provider\\Manager' => $baseDir . '/lib/private/Mail/Provider/Manager.php',
|
||||
|
|
|
|||
|
|
@ -696,6 +696,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OCP\\Mail\\Headers\\AutoSubmitted' => __DIR__ . '/../../..' . '/lib/public/Mail/Headers/AutoSubmitted.php',
|
||||
'OCP\\Mail\\IAttachment' => __DIR__ . '/../../..' . '/lib/public/Mail/IAttachment.php',
|
||||
'OCP\\Mail\\IEMailTemplate' => __DIR__ . '/../../..' . '/lib/public/Mail/IEMailTemplate.php',
|
||||
'OCP\\Mail\\IEmailValidator' => __DIR__ . '/../../..' . '/lib/public/Mail/IEmailValidator.php',
|
||||
'OCP\\Mail\\IMailer' => __DIR__ . '/../../..' . '/lib/public/Mail/IMailer.php',
|
||||
'OCP\\Mail\\IMessage' => __DIR__ . '/../../..' . '/lib/public/Mail/IMessage.php',
|
||||
'OCP\\Mail\\Provider\\Address' => __DIR__ . '/../../..' . '/lib/public/Mail/Provider/Address.php',
|
||||
|
|
@ -1861,6 +1862,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OC\\Log\\Systemdlog' => __DIR__ . '/../../..' . '/lib/private/Log/Systemdlog.php',
|
||||
'OC\\Mail\\Attachment' => __DIR__ . '/../../..' . '/lib/private/Mail/Attachment.php',
|
||||
'OC\\Mail\\EMailTemplate' => __DIR__ . '/../../..' . '/lib/private/Mail/EMailTemplate.php',
|
||||
'OC\\Mail\\EmailValidator' => __DIR__ . '/../../..' . '/lib/private/Mail/EmailValidator.php',
|
||||
'OC\\Mail\\Mailer' => __DIR__ . '/../../..' . '/lib/private/Mail/Mailer.php',
|
||||
'OC\\Mail\\Message' => __DIR__ . '/../../..' . '/lib/private/Mail/Message.php',
|
||||
'OC\\Mail\\Provider\\Manager' => __DIR__ . '/../../..' . '/lib/private/Mail/Provider/Manager.php',
|
||||
|
|
|
|||
37
lib/private/Mail/EmailValidator.php
Normal file
37
lib/private/Mail/EmailValidator.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OC\Mail;
|
||||
|
||||
use Egulias\EmailValidator\EmailValidator as EquliasEmailValidator;
|
||||
use Egulias\EmailValidator\Validation\NoRFCWarningsValidation;
|
||||
use Egulias\EmailValidator\Validation\RFCValidation;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\Mail\IEmailValidator;
|
||||
|
||||
class EmailValidator implements IEmailValidator {
|
||||
public function __construct(
|
||||
private IAppConfig $appConfig,
|
||||
) {
|
||||
}
|
||||
|
||||
public function isValid(string $email): bool {
|
||||
if ($email === '') {
|
||||
// Shortcut: empty addresses are never valid
|
||||
return false;
|
||||
}
|
||||
|
||||
$strictMailCheck = $this->appConfig->getValueString('core', 'enforce_strict_email_check', 'yes') === 'yes';
|
||||
|
||||
$validator = new EquliasEmailValidator();
|
||||
$validation = $strictMailCheck ? new NoRFCWarningsValidation() : new RFCValidation();
|
||||
|
||||
return $validator->isValid($email, $validation);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,9 +8,6 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace OC\Mail;
|
||||
|
||||
use Egulias\EmailValidator\EmailValidator;
|
||||
use Egulias\EmailValidator\Validation\NoRFCWarningsValidation;
|
||||
use Egulias\EmailValidator\Validation\RFCValidation;
|
||||
use OCP\Defaults;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\IBinaryFinder;
|
||||
|
|
@ -21,6 +18,7 @@ use OCP\L10N\IFactory;
|
|||
use OCP\Mail\Events\BeforeMessageSent;
|
||||
use OCP\Mail\IAttachment;
|
||||
use OCP\Mail\IEMailTemplate;
|
||||
use OCP\Mail\IEmailValidator;
|
||||
use OCP\Mail\IMailer;
|
||||
use OCP\Mail\IMessage;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -69,6 +67,7 @@ class Mailer implements IMailer {
|
|||
private IL10N $l10n,
|
||||
private IEventDispatcher $dispatcher,
|
||||
private IFactory $l10nFactory,
|
||||
private IEmailValidator $emailValidator,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -234,18 +233,10 @@ class Mailer implements IMailer {
|
|||
/**
|
||||
* @param string $email Email address to be validated
|
||||
* @return bool True if the mail address is valid, false otherwise
|
||||
* @deprecated 26.0.0 use IEmailValidator.isValid instead
|
||||
*/
|
||||
public function validateMailAddress(string $email): bool {
|
||||
if ($email === '') {
|
||||
// Shortcut: empty addresses are never valid
|
||||
return false;
|
||||
}
|
||||
|
||||
$strictMailCheck = $this->config->getAppValue('core', 'enforce_strict_email_check', 'yes') === 'yes';
|
||||
$validator = new EmailValidator();
|
||||
$validation = $strictMailCheck ? new NoRFCWarningsValidation() : new RFCValidation();
|
||||
|
||||
return $validator->isValid($email, $validation);
|
||||
return $this->emailValidator->isValid($email);
|
||||
}
|
||||
|
||||
protected function getInstance(): MailerInterface {
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ use OC\Lock\NoopLockingProvider;
|
|||
use OC\Lockdown\LockdownManager;
|
||||
use OC\Log\LogFactory;
|
||||
use OC\Log\PsrLoggerAdapter;
|
||||
use OC\Mail\EmailValidator;
|
||||
use OC\Mail\Mailer;
|
||||
use OC\Memcache\ArrayCache;
|
||||
use OC\Memcache\Factory;
|
||||
|
|
@ -195,6 +196,7 @@ use OCP\LDAP\ILDAPProviderFactory;
|
|||
use OCP\Lock\ILockingProvider;
|
||||
use OCP\Lockdown\ILockdownManager;
|
||||
use OCP\Log\ILogFactory;
|
||||
use OCP\Mail\IEmailValidator;
|
||||
use OCP\Mail\IMailer;
|
||||
use OCP\OCM\ICapabilityAwareOCMProvider;
|
||||
use OCP\OCM\IOCMDiscoveryService;
|
||||
|
|
@ -916,6 +918,9 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
);
|
||||
});
|
||||
|
||||
/** @since 32.0.0 */
|
||||
$this->registerAlias(IEmailValidator::class, EmailValidator::class);
|
||||
|
||||
$this->registerService(IMailer::class, function (Server $c) {
|
||||
return new Mailer(
|
||||
$c->get(\OCP\IConfig::class),
|
||||
|
|
@ -924,7 +929,8 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
$c->get(IURLGenerator::class),
|
||||
$c->getL10N('lib'),
|
||||
$c->get(IEventDispatcher::class),
|
||||
$c->get(IFactory::class)
|
||||
$c->get(IFactory::class),
|
||||
$c->get(IEmailValidator::class),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
24
lib/public/Mail/IEmailValidator.php
Normal file
24
lib/public/Mail/IEmailValidator.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCP\Mail;
|
||||
|
||||
/**
|
||||
* Validator for email addresses
|
||||
*
|
||||
* @since 32.0.0
|
||||
*/
|
||||
interface IEmailValidator {
|
||||
/**
|
||||
* @param string $email Email address to be validated
|
||||
* @return bool True if the mail address is valid, false otherwise
|
||||
* @since 32.0.0
|
||||
*/
|
||||
public function isValid(string $email): bool;
|
||||
}
|
||||
|
|
@ -80,6 +80,7 @@ interface IMailer {
|
|||
* @param string $email Email address to be validated
|
||||
* @return bool True if the mail address is valid, false otherwise
|
||||
* @since 8.1.0
|
||||
* @deprecated 26.0.0 use IEmailValidator.isValid instead
|
||||
*/
|
||||
public function validateMailAddress(string $email): bool;
|
||||
}
|
||||
|
|
|
|||
53
tests/lib/Mail/EmailValidatorTest.php
Normal file
53
tests/lib/Mail/EmailValidatorTest.php
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Test\Mail;
|
||||
|
||||
use OC\Mail\EmailValidator;
|
||||
use OCP\IAppConfig;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Test\TestCase;
|
||||
|
||||
class EmailValidatorTest extends TestCase {
|
||||
private IAppConfig&MockObject $appConfig;
|
||||
private EmailValidator $emailValidator;
|
||||
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->appConfig = $this->createMock(IAppConfig::class);
|
||||
$this->emailValidator = new EmailValidator($this->appConfig);
|
||||
}
|
||||
|
||||
public static function mailAddressProvider(): array {
|
||||
return [
|
||||
['lukas@nextcloud.com', true, false],
|
||||
['lukas@localhost', true, false],
|
||||
['lukas@192.168.1.1', true, false],
|
||||
['lukas@éxämplè.com', true, false],
|
||||
['asdf', false, false],
|
||||
['', false, false],
|
||||
['lukas@nextcloud.org@nextcloud.com', false, false],
|
||||
['test@localhost', true, false],
|
||||
['test@localhost', false, true],
|
||||
];
|
||||
}
|
||||
|
||||
#[DataProvider('mailAddressProvider')]
|
||||
public function testIsValid($email, $expected, $strict): void {
|
||||
$this->appConfig
|
||||
->expects($this->atMost(1))
|
||||
->method('getValueString')
|
||||
->with('core', 'enforce_strict_email_check', 'yes')
|
||||
->willReturn($strict ? 'yes' : 'no');
|
||||
$this->assertSame($expected, $this->emailValidator->isValid($email));
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ use OCP\IL10N;
|
|||
use OCP\IURLGenerator;
|
||||
use OCP\L10N\IFactory;
|
||||
use OCP\Mail\Events\BeforeMessageSent;
|
||||
use OCP\Mail\IEmailValidator;
|
||||
use OCP\Server;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -61,7 +62,8 @@ class MailerTest extends TestCase {
|
|||
$this->urlGenerator,
|
||||
$this->l10n,
|
||||
$this->dispatcher,
|
||||
$this->createMock(IFactory::class)
|
||||
$this->createMock(IFactory::class),
|
||||
$this->createMock(IEmailValidator::class),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -181,7 +183,8 @@ class MailerTest extends TestCase {
|
|||
$this->urlGenerator,
|
||||
$this->l10n,
|
||||
$this->dispatcher,
|
||||
$this->createMock(IFactory::class)
|
||||
$this->createMock(IFactory::class),
|
||||
$this->createMock(IEmailValidator::class),
|
||||
]
|
||||
)
|
||||
->getMock();
|
||||
|
|
@ -226,33 +229,6 @@ class MailerTest extends TestCase {
|
|||
$this->mailer->send($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function mailAddressProvider(): array {
|
||||
return [
|
||||
['lukas@owncloud.com', true, false],
|
||||
['lukas@localhost', true, false],
|
||||
['lukas@192.168.1.1', true, false],
|
||||
['lukas@éxämplè.com', true, false],
|
||||
['asdf', false, false],
|
||||
['', false, false],
|
||||
['lukas@owncloud.org@owncloud.com', false, false],
|
||||
['test@localhost', true, false],
|
||||
['test@localhost', false, true],
|
||||
];
|
||||
}
|
||||
|
||||
#[\PHPUnit\Framework\Attributes\DataProvider('mailAddressProvider')]
|
||||
public function testValidateMailAddress($email, $expected, $strict): void {
|
||||
$this->config
|
||||
->expects($this->atMost(1))
|
||||
->method('getAppValue')
|
||||
->with('core', 'enforce_strict_email_check')
|
||||
->willReturn($strict ? 'yes' : 'no');
|
||||
$this->assertSame($expected, $this->mailer->validateMailAddress($email));
|
||||
}
|
||||
|
||||
public function testCreateEMailTemplate(): void {
|
||||
$this->config->method('getSystemValueString')
|
||||
->with('mail_template_class', '')
|
||||
|
|
|
|||
30
tests/lib/Traits/EmailValidatorTrait.php
Normal file
30
tests/lib/Traits/EmailValidatorTrait.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Test\Traits;
|
||||
|
||||
use OC\Mail\EmailValidator;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\Mail\IEmailValidator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
trait EmailValidatorTrait {
|
||||
protected function getEmailValidatorWithStrictEmailCheck(): IEmailValidator {
|
||||
if (!($this instanceof TestCase)) {
|
||||
throw new \RuntimeException('This trait can only be used in a test case');
|
||||
}
|
||||
|
||||
$appConfig = $this->createMock(IAppConfig::class);
|
||||
$appConfig->method('getValueString')
|
||||
->with('core', 'enforce_strict_email_check', 'yes')
|
||||
->willReturn('yes');
|
||||
|
||||
return new EmailValidator($appConfig);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue