summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/Application.php14
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/Authentication/Listeners/RemoteWipeEmailListener.php171
-rw-r--r--tests/lib/Authentication/Listeners/RemoteWipeEmailListenerTest.php241
5 files changed, 423 insertions, 5 deletions
diff --git a/core/Application.php b/core/Application.php
index 97ebae774dd..9655a8e1a47 100644
--- a/core/Application.php
+++ b/core/Application.php
@@ -31,6 +31,7 @@ namespace OC\Core;
use OC\Authentication\Events\RemoteWipeFinished;
use OC\Authentication\Events\RemoteWipeStarted;
use OC\Authentication\Listeners\RemoteWipeActivityListener;
+use OC\Authentication\Listeners\RemoteWipeEmailListener;
use OC\Authentication\Listeners\RemoteWipeNotificationsListener;
use OC\Authentication\Notifications\Notifier as AuthenticationNotifier;
use OC\Core\Notification\RemoveLinkSharesNotifier;
@@ -64,19 +65,19 @@ class Application extends App {
$eventDispatcher = $server->query(IEventDispatcher::class);
$notificationManager = $server->getNotificationManager();
- $notificationManager->registerNotifier(function() use ($server) {
+ $notificationManager->registerNotifier(function () use ($server) {
return new RemoveLinkSharesNotifier(
$server->getL10NFactory()
);
- }, function() {
+ }, function () {
return [
'id' => 'core',
'name' => 'core',
];
});
- $notificationManager->registerNotifier(function() use ($server) {
+ $notificationManager->registerNotifier(function () use ($server) {
return $server->query(AuthenticationNotifier::class);
- }, function() {
+ }, function () {
return [
'id' => 'auth',
'name' => 'authentication notifier',
@@ -84,7 +85,7 @@ class Application extends App {
});
$eventDispatcher->addListener(IDBConnection::CHECK_MISSING_INDEXES_EVENT,
- function(GenericEvent $event) use ($container) {
+ function (GenericEvent $event) use ($container) {
/** @var MissingIndexInformation $subject */
$subject = $event->getSubject();
@@ -165,7 +166,10 @@ class Application extends App {
$eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeActivityListener::class);
$eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeNotificationsListener::class);
+ $eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeEmailListener::class);
$eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeActivityListener::class);
$eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeNotificationsListener::class);
+ $eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeEmailListener::class);
}
+
}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 80c03a6e63a..f608ce0b77c 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -522,6 +522,7 @@ return array(
'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => $baseDir . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php',
'OC\\Authentication\\Exceptions\\WipeTokenException' => $baseDir . '/lib/private/Authentication/Exceptions/WipeTokenException.php',
'OC\\Authentication\\Listeners\\RemoteWipeActivityListener' => $baseDir . '/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php',
+ 'OC\\Authentication\\Listeners\\RemoteWipeEmailListener' => $baseDir . '/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php',
'OC\\Authentication\\Listeners\\RemoteWipeNotificationsListener' => $baseDir . '/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php',
'OC\\Authentication\\LoginCredentials\\Credentials' => $baseDir . '/lib/private/Authentication/LoginCredentials/Credentials.php',
'OC\\Authentication\\LoginCredentials\\Store' => $baseDir . '/lib/private/Authentication/LoginCredentials/Store.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 0eaa457464c..fc4fc585e60 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -556,6 +556,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Authentication\\Exceptions\\UserAlreadyLoggedInException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/UserAlreadyLoggedInException.php',
'OC\\Authentication\\Exceptions\\WipeTokenException' => __DIR__ . '/../../..' . '/lib/private/Authentication/Exceptions/WipeTokenException.php',
'OC\\Authentication\\Listeners\\RemoteWipeActivityListener' => __DIR__ . '/../../..' . '/lib/private/Authentication/Listeners/RemoteWipeActivityListener.php',
+ 'OC\\Authentication\\Listeners\\RemoteWipeEmailListener' => __DIR__ . '/../../..' . '/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php',
'OC\\Authentication\\Listeners\\RemoteWipeNotificationsListener' => __DIR__ . '/../../..' . '/lib/private/Authentication/Listeners/RemoteWipeNotificationsListener.php',
'OC\\Authentication\\LoginCredentials\\Credentials' => __DIR__ . '/../../..' . '/lib/private/Authentication/LoginCredentials/Credentials.php',
'OC\\Authentication\\LoginCredentials\\Store' => __DIR__ . '/../../..' . '/lib/private/Authentication/LoginCredentials/Store.php',
diff --git a/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php b/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php
new file mode 100644
index 00000000000..be431747389
--- /dev/null
+++ b/lib/private/Authentication/Listeners/RemoteWipeEmailListener.php
@@ -0,0 +1,171 @@
+<?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 OC\Authentication\Listeners;
+
+use Exception;
+use OC\Authentication\Events\RemoteWipeFinished;
+use OC\Authentication\Events\RemoteWipeStarted;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IL10N;
+use OCP\ILogger;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\L10N\IFactory as IL10nFactory;
+use OCP\Mail\IMailer;
+use OCP\Mail\IMessage;
+use function substr;
+
+class RemoteWipeEmailListener implements IEventListener {
+
+ /** @var IMailer */
+ private $mailer;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var IL10N */
+ private $l10n;
+
+ /** @var ILogger */
+ private $logger;
+
+ public function __construct(IMailer $mailer,
+ IUserManager $userManager,
+ IL10nFactory $l10nFactory,
+ ILogger $logger) {
+ $this->mailer = $mailer;
+ $this->userManager = $userManager;
+ $this->l10n = $l10nFactory->get('core');
+ $this->logger = $logger;
+ }
+
+ /**
+ * @param Event $event
+ */
+ public function handle(Event $event): void {
+ if ($event instanceof RemoteWipeStarted) {
+ $uid = $event->getToken()->getUID();
+ $user = $this->userManager->get($uid);
+ if ($user === null) {
+ $this->logger->warning("not sending a wipe started email because user <$uid> does not exist (anymore)");
+ return;
+ }
+ if ($user->getEMailAddress() === null) {
+ $this->logger->info("not sending a wipe started email because user <$uid> has no email set");
+ return;
+ }
+
+ try {
+ $this->mailer->send(
+ $this->getWipingStartedMessage($event, $user)
+ );
+ } catch (Exception $e) {
+ $this->logger->logException($e, [
+ 'message' => "Could not send remote wipe started email to <$uid>",
+ 'level' => ILogger::ERROR,
+ ]);
+ }
+ } else if ($event instanceof RemoteWipeFinished) {
+ $uid = $event->getToken()->getUID();
+ $user = $this->userManager->get($uid);
+ if ($user === null) {
+ $this->logger->warning("not sending a wipe finished email because user <$uid> does not exist (anymore)");
+ return;
+ }
+ if ($user->getEMailAddress() === null) {
+ $this->logger->info("not sending a wipe finished email because user <$uid> has no email set");
+ return;
+ }
+
+ try {
+ $this->mailer->send(
+ $this->getWipingFinishedMessage($event, $user)
+ );
+ } catch (Exception $e) {
+ $this->logger->logException($e, [
+ 'message' => "Could not send remote wipe finished email to <$uid>",
+ 'level' => ILogger::ERROR,
+ ]);
+ }
+ }
+ }
+
+ private function getWipingStartedMessage(RemoteWipeStarted $event, IUser $user): IMessage {
+ $message = $this->mailer->createMessage();
+ $emailTemplate = $this->mailer->createEMailTemplate('auth.RemoteWipeStarted');
+ $plainHeading = $this->l10n->t('Wiping of device %s has started', [$event->getToken()->getName()]);
+ $htmlHeading = $this->l10n->t('Wiping of device »%s« has started', [$event->getToken()->getName()]);
+ $emailTemplate->setSubject(
+ $this->l10n->t(
+ '»%s« started remote wipe',
+ [
+ substr($event->getToken()->getName(), 0, 15)
+ ]
+ )
+ );
+ $emailTemplate->addHeader();
+ $emailTemplate->addHeading(
+ $htmlHeading,
+ $plainHeading
+ );
+ $emailTemplate->addBodyText(
+ $this->l10n->t('Device or application »%s« has started the remote wipe process. You will receive another email once the process has finished', [$event->getToken()->getName()])
+ );
+ $emailTemplate->addFooter();
+ $message->setTo([$user->getEMailAddress()]);
+ $message->useTemplate($emailTemplate);
+
+ return $message;
+ }
+
+ private function getWipingFinishedMessage(RemoteWipeFinished $event, IUser $user): IMessage {
+ $message = $this->mailer->createMessage();
+ $emailTemplate = $this->mailer->createEMailTemplate('auth.RemoteWipeFinished');
+ $plainHeading = $this->l10n->t('Wiping of device %s has finished', [$event->getToken()->getName()]);
+ $htmlHeading = $this->l10n->t('Wiping of device »%s« has finished', [$event->getToken()->getName()]);
+ $emailTemplate->setSubject(
+ $this->l10n->t(
+ '»%s« finished remote wipe',
+ [
+ substr($event->getToken()->getName(), 0, 15)
+ ]
+ )
+ );
+ $emailTemplate->addHeader();
+ $emailTemplate->addHeading(
+ $htmlHeading,
+ $plainHeading
+ );
+ $emailTemplate->addBodyText(
+ $this->l10n->t('Device or application »%s« has finished the remote wipe process.', [$event->getToken()->getName()])
+ );
+ $emailTemplate->addFooter();
+ $message->setTo([$user->getEMailAddress()]);
+ $message->useTemplate($emailTemplate);
+
+ return $message;
+ }
+
+}
diff --git a/tests/lib/Authentication/Listeners/RemoteWipeEmailListenerTest.php b/tests/lib/Authentication/Listeners/RemoteWipeEmailListenerTest.php
new file mode 100644
index 00000000000..ea7740057ba
--- /dev/null
+++ b/tests/lib/Authentication/Listeners/RemoteWipeEmailListenerTest.php
@@ -0,0 +1,241 @@
+<?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 lib\Authentication\Listeners;
+
+use Exception;
+use OC\Authentication\Events\RemoteWipeFinished;
+use OC\Authentication\Events\RemoteWipeStarted;
+use OC\Authentication\Listeners\RemoteWipeEmailListener;
+use OC\Authentication\Token\IToken;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\IL10N;
+use OCP\ILogger;
+use OCP\IUser;
+use OCP\IUserManager;
+use OCP\L10N\IFactory;
+use OCP\Mail\IMailer;
+use OCP\Mail\IMessage;
+use PHPUnit\Framework\MockObject\MockObject;
+use Test\TestCase;
+
+class RemoteWipeEmailListenerTest extends TestCase {
+
+ /** @var IMailer|MockObject */
+ private $mailer;
+
+ /** @var IUserManager|MockObject */
+ private $userManager;
+
+ /** @var IFactory|MockObject */
+ private $l10nFactory;
+
+ /** @var IL10N|MockObject */
+ private $l10n;
+
+ /** @var ILogger|MockObject */
+ private $logger;
+
+ /** @var IEventListener */
+ private $listener;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->mailer = $this->createMock(IMailer::class);
+ $this->userManager = $this->createMock(IUserManager::class);
+ $this->l10nFactory = $this->createMock(IFactory::class);
+ $this->l10n = $this->createMock(IL10N::class);
+ $this->logger = $this->createMock(ILogger::class);
+
+ $this->l10nFactory->method('get')->with('core')->willReturn($this->l10n);
+ $this->l10n->method('t')->willReturnArgument(0);
+
+ $this->listener = new RemoteWipeEmailListener(
+ $this->mailer,
+ $this->userManager,
+ $this->l10nFactory,
+ $this->logger
+ );
+ }
+
+
+ public function testHandleUnrelated() {
+ $event = new Event();
+ $this->mailer->expects($this->never())->method('send');
+
+ $this->listener->handle($event);
+ }
+
+ public function testHandleRemoteWipeStartedInvalidUser() {
+ /** @var IToken|MockObject $token */
+ $token = $this->createMock(IToken::class);
+ $event = new RemoteWipeStarted($token);
+ $token->method('getUID')->willReturn('nope');
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('nope')
+ ->willReturn(null);
+ $this->mailer->expects($this->never())->method('send');
+
+ $this->listener->handle($event);
+ }
+
+ public function testHandleRemoteWipeStartedNoEmailSet() {
+ /** @var IToken|MockObject $token */
+ $token = $this->createMock(IToken::class);
+ $event = new RemoteWipeStarted($token);
+ $token->method('getUID')->willReturn('nope');
+ $user = $this->createMock(IUser::class);
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('nope')
+ ->willReturn($user);
+ $user->method('getEMailAddress')->willReturn(null);
+ $this->mailer->expects($this->never())->method('send');
+
+ $this->listener->handle($event);
+ }
+
+ public function testHandleRemoteWipeStartedTransmissionError() {
+ /** @var IToken|MockObject $token */
+ $token = $this->createMock(IToken::class);
+ $event = new RemoteWipeStarted($token);
+ $token->method('getUID')->willReturn('nope');
+ $user = $this->createMock(IUser::class);
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('nope')
+ ->willReturn($user);
+ $user->method('getEMailAddress')->willReturn('user@domain.org');
+ $this->mailer->expects($this->once())
+ ->method('send')
+ ->willThrowException(new Exception());
+ $this->logger->expects($this->once())
+ ->method('logException');
+
+ $this->listener->handle($event);
+ }
+
+ public function testHandleRemoteWipeStarted() {
+ /** @var IToken|MockObject $token */
+ $token = $this->createMock(IToken::class);
+ $event = new RemoteWipeStarted($token);
+ $token->method('getUID')->willReturn('nope');
+ $user = $this->createMock(IUser::class);
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('nope')
+ ->willReturn($user);
+ $user->method('getEMailAddress')->willReturn('user@domain.org');
+ $message = $this->createMock(IMessage::class);
+ $this->mailer->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($message);
+ $message->expects($this->once())
+ ->method('setTo')
+ ->with($this->equalTo(['user@domain.org']));
+ $this->mailer->expects($this->once())
+ ->method('send')
+ ->with($message);
+
+ $this->listener->handle($event);
+ }
+
+ public function testHandleRemoteWipeFinishedInvalidUser() {
+ /** @var IToken|MockObject $token */
+ $token = $this->createMock(IToken::class);
+ $event = new RemoteWipeFinished($token);
+ $token->method('getUID')->willReturn('nope');
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('nope')
+ ->willReturn(null);
+ $this->mailer->expects($this->never())->method('send');
+
+ $this->listener->handle($event);
+ }
+
+ public function testHandleRemoteWipeFinishedNoEmailSet() {
+ /** @var IToken|MockObject $token */
+ $token = $this->createMock(IToken::class);
+ $event = new RemoteWipeFinished($token);
+ $token->method('getUID')->willReturn('nope');
+ $user = $this->createMock(IUser::class);
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('nope')
+ ->willReturn($user);
+ $user->method('getEMailAddress')->willReturn(null);
+ $this->mailer->expects($this->never())->method('send');
+
+ $this->listener->handle($event);
+ }
+
+ public function testHandleRemoteWipeFinishedTransmissionError() {
+ /** @var IToken|MockObject $token */
+ $token = $this->createMock(IToken::class);
+ $event = new RemoteWipeFinished($token);
+ $token->method('getUID')->willReturn('nope');
+ $user = $this->createMock(IUser::class);
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('nope')
+ ->willReturn($user);
+ $user->method('getEMailAddress')->willReturn('user@domain.org');
+ $this->mailer->expects($this->once())
+ ->method('send')
+ ->willThrowException(new Exception());
+ $this->logger->expects($this->once())
+ ->method('logException');
+
+ $this->listener->handle($event);
+ }
+
+ public function testHandleRemoteWipeFinished() {
+ /** @var IToken|MockObject $token */
+ $token = $this->createMock(IToken::class);
+ $event = new RemoteWipeFinished($token);
+ $token->method('getUID')->willReturn('nope');
+ $user = $this->createMock(IUser::class);
+ $this->userManager->expects($this->once())
+ ->method('get')
+ ->with('nope')
+ ->willReturn($user);
+ $user->method('getEMailAddress')->willReturn('user@domain.org');
+ $message = $this->createMock(IMessage::class);
+ $this->mailer->expects($this->once())
+ ->method('createMessage')
+ ->willReturn($message);
+ $message->expects($this->once())
+ ->method('setTo')
+ ->with($this->equalTo(['user@domain.org']));
+ $this->mailer->expects($this->once())
+ ->method('send')
+ ->with($message);
+
+ $this->listener->handle($event);
+ }
+
+}