diff options
-rw-r--r-- | apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php | 2 | ||||
-rw-r--r-- | apps/settings/lib/Mailer/NewUserMailHelper.php | 2 | ||||
-rw-r--r-- | apps/settings/tests/Mailer/NewUserMailHelperTest.php | 5 | ||||
-rw-r--r-- | config/config.sample.php | 5 | ||||
-rw-r--r-- | core/Command/Status.php | 27 | ||||
-rw-r--r-- | core/Controller/LoginController.php | 2 | ||||
-rw-r--r-- | core/Controller/LostController.php | 4 | ||||
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | lib/composer/composer/autoload_real.php | 27 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | lib/private/Console/Application.php | 3 | ||||
-rw-r--r-- | lib/private/Mail/Message.php | 38 | ||||
-rw-r--r-- | lib/public/Mail/Headers/AutoSubmitted.php | 75 | ||||
-rw-r--r-- | lib/public/Mail/IMessage.php | 10 | ||||
-rw-r--r-- | tests/lib/Mail/MessageTest.php | 107 |
15 files changed, 285 insertions, 24 deletions
diff --git a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php index 355d95057ff..32072688967 100644 --- a/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php +++ b/apps/dav/lib/CalDAV/Reminder/NotificationProvider/EmailProvider.php @@ -37,6 +37,7 @@ use OCP\IL10N; use OCP\IURLGenerator; use OCP\IUser; use OCP\L10N\IFactory as L10NFactory; +use OCP\Mail\Headers\AutoSubmitted; use OCP\Mail\IEMailTemplate; use OCP\Mail\IMailer; use Psr\Log\LoggerInterface; @@ -130,6 +131,7 @@ class EmailProvider extends AbstractProvider { } $message->setTo([$emailAddress]); $message->useTemplate($template); + $message->setAutoSubmitted(AutoSubmitted::VALUE_AUTO_GENERATED); try { $failed = $this->mailer->send($message); diff --git a/apps/settings/lib/Mailer/NewUserMailHelper.php b/apps/settings/lib/Mailer/NewUserMailHelper.php index 50502ed1d39..b91aea4391b 100644 --- a/apps/settings/lib/Mailer/NewUserMailHelper.php +++ b/apps/settings/lib/Mailer/NewUserMailHelper.php @@ -35,6 +35,7 @@ use OCP\IConfig; use OCP\IURLGenerator; use OCP\IUser; use OCP\L10N\IFactory; +use OCP\Mail\Headers\AutoSubmitted; use OCP\Mail\IEMailTemplate; use OCP\Mail\IMailer; use OCP\Security\ICrypto; @@ -181,6 +182,7 @@ class NewUserMailHelper { $message->setTo([$email => $user->getDisplayName()]); $message->setFrom([$this->fromAddress => $this->themingDefaults->getName()]); $message->useTemplate($emailTemplate); + $message->setAutoSubmitted(AutoSubmitted::VALUE_AUTO_GENERATED); $this->mailer->send($message); } } diff --git a/apps/settings/tests/Mailer/NewUserMailHelperTest.php b/apps/settings/tests/Mailer/NewUserMailHelperTest.php index 252dcfd8057..5c7d182d436 100644 --- a/apps/settings/tests/Mailer/NewUserMailHelperTest.php +++ b/apps/settings/tests/Mailer/NewUserMailHelperTest.php @@ -42,6 +42,7 @@ use OCP\IL10N; use OCP\IURLGenerator; use OCP\IUser; use OCP\L10N\IFactory; +use OCP\Mail\Headers\AutoSubmitted; use OCP\Mail\IEMailTemplate; use OCP\Mail\IMailer; use OCP\Security\ICrypto; @@ -867,6 +868,10 @@ EOF; ->expects($this->once()) ->method('useTemplate') ->with($emailTemplate); + $message + ->expects($this->once()) + ->method('setAutoSubmitted') + ->with(AutoSubmitted::VALUE_AUTO_GENERATED); $this->defaults ->expects($this->once()) ->method('getName') diff --git a/config/config.sample.php b/config/config.sample.php index 4597ce9a77d..0267ae51c91 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -1840,7 +1840,10 @@ $CONFIG = [ * restricted, or if external storage which do not support streaming are in * use. * - * The Web server user must have write access to this directory. + * The Web server user/PHP must have write access to this directory. + * Additionally you have to make sure that your PHP configuration considers this a valid + * tmp directory, by setting the TMP, TMPDIR, and TEMP variables to the required directories. + * On top of that you might be required to grant additional permissions in AppArmor or SELinux. */ 'tempdirectory' => '/tmp/nextcloudtemp', diff --git a/core/Command/Status.php b/core/Command/Status.php index 45ccb28f5c4..c59dac557a8 100644 --- a/core/Command/Status.php +++ b/core/Command/Status.php @@ -29,6 +29,7 @@ use OCP\Defaults; use OCP\IConfig; use OCP\Util; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Status extends Base { @@ -47,22 +48,40 @@ class Status extends Base { $this ->setDescription('show some status information') - ; + ->addOption( + 'exit-code', + 'e', + InputOption::VALUE_NONE, + 'exit with 0 if running in normal mode, 1 when in maintenance mode, 2 when `./occ upgrade` is needed. Does not write any output to STDOUT.' + ); } protected function execute(InputInterface $input, OutputInterface $output): int { + $maintenanceMode = $this->config->getSystemValueBool('maintenance', false); + $needUpgrade = Util::needUpgrade(); $values = [ 'installed' => $this->config->getSystemValueBool('installed', false), 'version' => implode('.', Util::getVersion()), 'versionstring' => OC_Util::getVersionString(), 'edition' => '', - 'maintenance' => $this->config->getSystemValueBool('maintenance', false), - 'needsDbUpgrade' => Util::needUpgrade(), + 'maintenance' => $maintenanceMode, + 'needsDbUpgrade' => $needUpgrade, 'productname' => $this->themingDefaults->getProductName(), 'extendedSupport' => Util::hasExtendedSupport() ]; - $this->writeArrayInOutputFormat($input, $output, $values); + if ($input->getOption('verbose') || !$input->getOption('exit-code')) { + $this->writeArrayInOutputFormat($input, $output, $values); + } + + if ($input->getOption('exit-code')) { + if ($maintenanceMode === true) { + return 1; + } + if ($needUpgrade === true) { + return 2; + } + } return 0; } } diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php index 4c4a12355d2..386987842c2 100644 --- a/core/Controller/LoginController.php +++ b/core/Controller/LoginController.php @@ -121,7 +121,7 @@ class LoginController extends Controller { $response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute( 'core.login.showLoginForm', - ['clear' => true] // this param the the code in login.js may be removed when the "Clear-Site-Data" is working in the browsers + ['clear' => true] // this param the code in login.js may be removed when the "Clear-Site-Data" is working in the browsers )); $this->session->set('clearingExecutionContexts', '1'); diff --git a/core/Controller/LostController.php b/core/Controller/LostController.php index fadfa242b93..e7960dbcef5 100644 --- a/core/Controller/LostController.php +++ b/core/Controller/LostController.php @@ -240,6 +240,10 @@ class LostController extends Controller { $this->eventDispatcher->dispatchTyped(new BeforePasswordResetEvent($user, $password)); \OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'pre_passwordReset', ['uid' => $userId, 'password' => $password]); + if (strlen($password) > 469) { + throw new HintException('Password too long', $this->l10n->t('Password is too long. Maximum allowed length is 469 characters.')); + } + if (!$user->setPassword($password)) { throw new Exception(); } diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 08a871e8466..5d9a90a3f02 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -479,6 +479,7 @@ return array( 'OCP\\Log\\IWriter' => $baseDir . '/lib/public/Log/IWriter.php', 'OCP\\Log\\RotationTrait' => $baseDir . '/lib/public/Log/RotationTrait.php', 'OCP\\Mail\\Events\\BeforeMessageSent' => $baseDir . '/lib/public/Mail/Events/BeforeMessageSent.php', + '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\\IMailer' => $baseDir . '/lib/public/Mail/IMailer.php', diff --git a/lib/composer/composer/autoload_real.php b/lib/composer/composer/autoload_real.php index 6b98041770d..6dbf91afee6 100644 --- a/lib/composer/composer/autoload_real.php +++ b/lib/composer/composer/autoload_real.php @@ -31,25 +31,18 @@ class ComposerAutoloaderInit749170dad3f5e7f9ca158f5a9f04f6a2 $loader->register(true); - $includeFiles = \Composer\Autoload\ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2::$files; - foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire749170dad3f5e7f9ca158f5a9f04f6a2($fileIdentifier, $file); + $filesToLoad = \Composer\Autoload\ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2::$files; + $requireFile = static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }; + foreach ($filesToLoad as $fileIdentifier => $file) { + ($requireFile)($fileIdentifier, $file); } return $loader; } } - -/** - * @param string $fileIdentifier - * @param string $file - * @return void - */ -function composerRequire749170dad3f5e7f9ca158f5a9f04f6a2($fileIdentifier, $file) -{ - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - - require $file; - } -} diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index eec226c9a6e..15bcc0f4843 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -512,6 +512,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Log\\IWriter' => __DIR__ . '/../../..' . '/lib/public/Log/IWriter.php', 'OCP\\Log\\RotationTrait' => __DIR__ . '/../../..' . '/lib/public/Log/RotationTrait.php', 'OCP\\Mail\\Events\\BeforeMessageSent' => __DIR__ . '/../../..' . '/lib/public/Mail/Events/BeforeMessageSent.php', + '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\\IMailer' => __DIR__ . '/../../..' . '/lib/public/Mail/IMailer.php', diff --git a/lib/private/Console/Application.php b/lib/private/Console/Application.php index fc48f57e499..2b48f9f5ada 100644 --- a/lib/private/Console/Application.php +++ b/lib/private/Console/Application.php @@ -181,7 +181,8 @@ class Application { InputInterface $input, ConsoleOutputInterface $output ) { if ($input->getArgument('command') !== '_completion' - && $input->getArgument('command') !== 'maintenance:mode') { + && $input->getArgument('command') !== 'maintenance:mode' + && $input->getArgument('command') !== 'status') { $errOutput = $output->getErrorOutput(); $errOutput->writeln( '<comment>Nextcloud is in maintenance mode, hence the database isn\'t accessible.' . PHP_EOL . diff --git a/lib/private/Mail/Message.php b/lib/private/Mail/Message.php index 8b94f44ddba..3313b39e2e2 100644 --- a/lib/private/Mail/Message.php +++ b/lib/private/Mail/Message.php @@ -31,6 +31,7 @@ declare(strict_types=1); */ namespace OC\Mail; +use OCP\Mail\Headers\AutoSubmitted; use OCP\Mail\IAttachment; use OCP\Mail\IEMailTemplate; use OCP\Mail\IMessage; @@ -301,4 +302,41 @@ class Message implements IMessage { } return $this; } + + /** + * Add the Auto-Submitted header to the email, preventing most automated + * responses to automated messages. + * + * @param AutoSubmitted::VALUE_* $value (one of AutoSubmitted::VALUE_NO, AutoSubmitted::VALUE_AUTO_GENERATED, AutoSubmitted::VALUE_AUTO_REPLIED) + * @return $this + */ + public function setAutoSubmitted(string $value): IMessage { + $headers = $this->swiftMessage->getHeaders(); + + if ($headers->has(AutoSubmitted::HEADER)) { + // if the header already exsists, remove it. + // the value can be modified with some implementations + // of the interface \Swift_Mime_Header, however the + // interface doesn't, and this makes the static-code + // analysis unhappy. + $headers->remove(AutoSubmitted::HEADER); + } + + $headers->addTextHeader(AutoSubmitted::HEADER, $value); + + return $this; + } + + /** + * Get the current value of the Auto-Submitted header. Defaults to "no" + * which is equivalent to the header not existing at all + * + * @return string + */ + public function getAutoSubmitted(): string { + $headers = $this->swiftMessage->getHeaders(); + + return $headers->has(AutoSubmitted::HEADER) ? + $headers->get(AutoSubmitted::HEADER)->toString() : AutoSubmitted::VALUE_NO; + } } diff --git a/lib/public/Mail/Headers/AutoSubmitted.php b/lib/public/Mail/Headers/AutoSubmitted.php new file mode 100644 index 00000000000..21df18dd918 --- /dev/null +++ b/lib/public/Mail/Headers/AutoSubmitted.php @@ -0,0 +1,75 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2022 Bennet Becker <dev@bennet.cc> + * + * @author Bennet Becker <dev@bennet.cc> + * + * @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 OCP\Mail\Headers; + +/** + * Keyword values for the Auto-Submitted email header, as per RFC 3834. + * + * The value "auto-notified" as per RFC 5436 is deliberately omitted as it is + * meant of notification of the sieve system. + * + * @link https://www.iana.org/assignments/auto-submitted-keywords/auto-submitted-keywords.xhtml + * + * @since 26.0.0 + */ +final class AutoSubmitted { + + /** + * Name of the Header as used in the final message later + * + * @var string + * @since 26.0.0 + */ + public const HEADER = 'Auto-Submitted'; + + /** + * Indicates that a message was NOT automatically generated, but was + * created by a human (or following human interaction). It is the equivalent + * to the absence of an Auto-Submitted header altogether. + * + * @var string + * @since 26.0.0 + */ + public const VALUE_NO = 'no'; + + /** + * Indicates that a message was generated by an automatic process, and is + * not a direct response to another message + * + * @var string + * @since 26.0.0 + */ + public const VALUE_AUTO_GENERATED = 'auto-generated'; + + /** + * Indicates that a message was automatically generated as a direct response + * to another message. + * + * @var string + * @since 26.0.0 + */ + public const VALUE_AUTO_REPLIED = 'auto-replied'; +} diff --git a/lib/public/Mail/IMessage.php b/lib/public/Mail/IMessage.php index 1549f61c1fe..994d32603e9 100644 --- a/lib/public/Mail/IMessage.php +++ b/lib/public/Mail/IMessage.php @@ -93,4 +93,14 @@ interface IMessage { * @since 13.0.0 */ public function useTemplate(IEMailTemplate $emailTemplate): IMessage; + + /** + * Add the Auto-Submitted header to the email, preventing most automated + * responses to automated messages. + * + * @param Headers\AutoSubmitted::VALUE_* $value (one of AutoSubmitted::VALUE_NO, AutoSubmitted::VALUE_AUTO_GENERATED, AutoSubmitted::VALUE_AUTO_REPLIED) + * @return IMessage + * @since 26.0.0 + */ + public function setAutoSubmitted(string $value): IMessage; } diff --git a/tests/lib/Mail/MessageTest.php b/tests/lib/Mail/MessageTest.php index bec70d1c78a..b97240d1336 100644 --- a/tests/lib/Mail/MessageTest.php +++ b/tests/lib/Mail/MessageTest.php @@ -9,6 +9,7 @@ namespace Test\Mail; use OC\Mail\Message; +use OCP\Mail\Headers\AutoSubmitted; use OCP\Mail\IEMailTemplate; use Swift_Message; use Test\TestCase; @@ -263,4 +264,110 @@ class MessageTest extends TestCase { $message->useTemplate($template); } + + public function testSetAutoSubmitted1() { + $swiftMimeSimpleHeaderSet = $this->getMockBuilder('\Swift_Mime_SimpleHeaderSet') + ->disableOriginalConstructor() + ->getMock(); + $swiftMessage = $this->getMockBuilder('\Swift_Message') + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->disallowMockingUnknownTypes() + ->getMock(); + + $swiftMessage->method('getHeaders')->willReturn($swiftMimeSimpleHeaderSet); + + $swiftMimeSimpleHeaderSet->expects($this->once()) + ->method('has') + ->with('Auto-Submitted'); + $swiftMimeSimpleHeaderSet->expects($this->never()) + ->method('remove'); + $swiftMimeSimpleHeaderSet->expects($this->once()) + ->method('addTextHeader') + ->with('Auto-Submitted', AutoSubmitted::VALUE_AUTO_GENERATED); + + $message = new Message($swiftMessage, false); + $message->setAutoSubmitted(AutoSubmitted::VALUE_AUTO_GENERATED); + } + + public function testSetAutoSubmitted2() { + $swiftMimeSimpleHeaderSet = $this->getMockBuilder('\Swift_Mime_SimpleHeaderSet') + ->disableOriginalConstructor() + ->getMock(); + $swiftMessage = $this->getMockBuilder('\Swift_Message') + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->disallowMockingUnknownTypes() + ->getMock(); + + $swiftMessage->method('getHeaders')->willReturn($swiftMimeSimpleHeaderSet); + + $swiftMimeSimpleHeaderSet->expects($this->once()) + ->method('has') + ->with('Auto-Submitted') + ->willReturn(true); + $swiftMimeSimpleHeaderSet->expects($this->once()) + ->method('remove') + ->with('Auto-Submitted'); + $swiftMimeSimpleHeaderSet->expects($this->once()) + ->method('addTextHeader') + ->with('Auto-Submitted', AutoSubmitted::VALUE_AUTO_GENERATED); + + $message = new Message($swiftMessage, false); + $message->setAutoSubmitted(AutoSubmitted::VALUE_AUTO_GENERATED); + } + + public function testGetAutoSubmitted1() { + $swiftMimeSimpleHeaderSet = $this->getMockBuilder('\Swift_Mime_SimpleHeaderSet') + ->disableOriginalConstructor() + ->getMock(); + $swiftMessage = $this->getMockBuilder('\Swift_Message') + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->disallowMockingUnknownTypes() + ->getMock(); + + $swiftMessage->method('getHeaders')->willReturn($swiftMimeSimpleHeaderSet); + + $swiftMimeSimpleHeaderSet->expects($this->once()) + ->method('has') + ->with('Auto-Submitted'); + $swiftMimeSimpleHeaderSet->expects($this->never()) + ->method('get'); + + $message = new Message($swiftMessage, false); + $this->assertSame("no", $message->getAutoSubmitted()); + } + public function testGetAutoSubmitted2() { + $swiftMimeHeader = $this->getMockBuilder('\Swift_Mime_Header') + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $swiftMimeSimpleHeaderSet = $this->getMockBuilder('\Swift_Mime_SimpleHeaderSet') + ->disableOriginalConstructor() + ->getMock(); + $swiftMessage = $this->getMockBuilder('\Swift_Message') + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->disallowMockingUnknownTypes() + ->getMock(); + + + $swiftMessage->method('getHeaders')->willReturn($swiftMimeSimpleHeaderSet); + $swiftMimeHeader->method('toString')->willReturn(AutoSubmitted::VALUE_AUTO_GENERATED); + + $swiftMimeSimpleHeaderSet->expects($this->once()) + ->method('has') + ->with('Auto-Submitted') + ->willReturn(true); + $swiftMimeSimpleHeaderSet->expects($this->once()) + ->method('get') + ->willReturn($swiftMimeHeader); + + $message = new Message($swiftMessage, false); + $this->assertSame(AutoSubmitted::VALUE_AUTO_GENERATED, $message->getAutoSubmitted()); + } } |