aboutsummaryrefslogtreecommitdiffstats
path: root/apps/twofactor_backupcodes/lib
diff options
context:
space:
mode:
Diffstat (limited to 'apps/twofactor_backupcodes/lib')
-rw-r--r--apps/twofactor_backupcodes/lib/Activity/Provider.php49
-rw-r--r--apps/twofactor_backupcodes/lib/AppInfo/Application.php77
-rw-r--r--apps/twofactor_backupcodes/lib/BackgroundJob/CheckBackupCodes.php49
-rw-r--r--apps/twofactor_backupcodes/lib/BackgroundJob/RememberBackupCodesJob.php77
-rw-r--r--apps/twofactor_backupcodes/lib/Controller/SettingsController.php56
-rw-r--r--apps/twofactor_backupcodes/lib/Db/BackupCode.php25
-rw-r--r--apps/twofactor_backupcodes/lib/Db/BackupCodeMapper.php46
-rw-r--r--apps/twofactor_backupcodes/lib/Event/CodesGenerated.php28
-rw-r--r--apps/twofactor_backupcodes/lib/Listener/ActivityPublisher.php44
-rw-r--r--apps/twofactor_backupcodes/lib/Listener/ClearNotifications.php35
-rw-r--r--apps/twofactor_backupcodes/lib/Listener/ProviderDisabled.php43
-rw-r--r--apps/twofactor_backupcodes/lib/Listener/ProviderEnabled.php40
-rw-r--r--apps/twofactor_backupcodes/lib/Listener/RegistryUpdater.php31
-rw-r--r--apps/twofactor_backupcodes/lib/Listener/UserDeleted.php31
-rw-r--r--apps/twofactor_backupcodes/lib/Migration/CheckBackupCodes.php29
-rw-r--r--apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607104347.php37
-rw-r--r--apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607113030.php35
-rw-r--r--apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php32
-rw-r--r--apps/twofactor_backupcodes/lib/Migration/Version1002Date20170926101419.php10
-rw-r--r--apps/twofactor_backupcodes/lib/Migration/Version1002Date20180821043638.php34
-rw-r--r--apps/twofactor_backupcodes/lib/Notifications/Notifier.php73
-rw-r--r--apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php103
-rw-r--r--apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php108
-rw-r--r--apps/twofactor_backupcodes/lib/Settings/Personal.php85
24 files changed, 719 insertions, 458 deletions
diff --git a/apps/twofactor_backupcodes/lib/Activity/Provider.php b/apps/twofactor_backupcodes/lib/Activity/Provider.php
index 739ac9bbe13..eba38147bd7 100644
--- a/apps/twofactor_backupcodes/lib/Activity/Provider.php
+++ b/apps/twofactor_backupcodes/lib/Activity/Provider.php
@@ -1,28 +1,14 @@
<?php
+declare(strict_types=1);
+
/**
- * @author Christoph Wurst <christoph@winzerhof-wurst.at>
- * @copyright Copyright (c) 2016 Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * Two-factor backup codes
- *
- * 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/>
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Activity;
-use InvalidArgumentException;
+use OCP\Activity\Exceptions\UnknownActivityException;
use OCP\Activity\IEvent;
use OCP\Activity\IManager;
use OCP\Activity\IProvider;
@@ -31,29 +17,21 @@ use OCP\L10N\IFactory as L10nFactory;
class Provider implements IProvider {
- /** @var L10nFactory */
- private $l10n;
-
- /** @var IURLGenerator */
- private $urlGenerator;
-
- /** @var IManager */
- private $activityManager;
-
/**
* @param L10nFactory $l10n
* @param IURLGenerator $urlGenerator
* @param IManager $activityManager
*/
- public function __construct(L10nFactory $l10n, IURLGenerator $urlGenerator, IManager $activityManager) {
- $this->urlGenerator = $urlGenerator;
- $this->activityManager = $activityManager;
- $this->l10n = $l10n;
+ public function __construct(
+ private L10nFactory $l10n,
+ private IURLGenerator $urlGenerator,
+ private IManager $activityManager,
+ ) {
}
- public function parse($language, IEvent $event, IEvent $previousEvent = null) {
+ public function parse($language, IEvent $event, ?IEvent $previousEvent = null): IEvent {
if ($event->getApp() !== 'twofactor_backupcodes') {
- throw new InvalidArgumentException();
+ throw new UnknownActivityException();
}
$l = $this->l10n->get('twofactor_backupcodes', $language);
@@ -69,9 +47,8 @@ class Provider implements IProvider {
}
break;
default:
- throw new InvalidArgumentException();
+ throw new UnknownActivityException();
}
return $event;
}
-
}
diff --git a/apps/twofactor_backupcodes/lib/AppInfo/Application.php b/apps/twofactor_backupcodes/lib/AppInfo/Application.php
index 050473f7efe..e9a1ec1c72c 100644
--- a/apps/twofactor_backupcodes/lib/AppInfo/Application.php
+++ b/apps/twofactor_backupcodes/lib/AppInfo/Application.php
@@ -1,54 +1,51 @@
<?php
+
+declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
- *
- * @author Joas Schilling <coding@schilljs.com>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\AppInfo;
-use OCA\TwoFactorBackupCodes\Db\BackupCodeMapper;
+use OCA\TwoFactorBackupCodes\Event\CodesGenerated;
+use OCA\TwoFactorBackupCodes\Listener\ActivityPublisher;
+use OCA\TwoFactorBackupCodes\Listener\ClearNotifications;
+use OCA\TwoFactorBackupCodes\Listener\ProviderDisabled;
+use OCA\TwoFactorBackupCodes\Listener\ProviderEnabled;
+use OCA\TwoFactorBackupCodes\Listener\RegistryUpdater;
+use OCA\TwoFactorBackupCodes\Listener\UserDeleted;
+use OCA\TwoFactorBackupCodes\Notifications\Notifier;
+use OCA\TwoFactorBackupCodes\Provider\BackupCodesProvider;
use OCP\AppFramework\App;
-use OCP\Util;
+use OCP\AppFramework\Bootstrap\IBootContext;
+use OCP\AppFramework\Bootstrap\IBootstrap;
+use OCP\AppFramework\Bootstrap\IRegistrationContext;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserUnregistered;
+use OCP\User\Events\UserDeletedEvent;
-class Application extends App {
- public function __construct () {
- parent::__construct('twofactor_backupcodes');
- }
+class Application extends App implements IBootstrap {
+ public const APP_ID = 'twofactor_backupcodes';
- /**
- * Register the different app parts
- */
- public function register() {
- $this->registerHooksAndEvents();
+ public function __construct() {
+ parent::__construct(self::APP_ID);
}
- /**
- * Register the hooks and events
- */
- public function registerHooksAndEvents() {
- Util::connectHook('OC_User', 'post_deleteUser', $this, 'deleteUser');
+ public function register(IRegistrationContext $context): void {
+ $context->registerNotifierService(Notifier::class);
+
+ $context->registerEventListener(CodesGenerated::class, ActivityPublisher::class);
+ $context->registerEventListener(CodesGenerated::class, RegistryUpdater::class);
+ $context->registerEventListener(CodesGenerated::class, ClearNotifications::class);
+ $context->registerEventListener(TwoFactorProviderForUserRegistered::class, ProviderEnabled::class);
+ $context->registerEventListener(TwoFactorProviderForUserUnregistered::class, ProviderDisabled::class);
+ $context->registerEventListener(UserDeletedEvent::class, UserDeleted::class);
+
+
+ $context->registerTwoFactorProvider(BackupCodesProvider::class);
}
- public function deleteUser($params) {
- /** @var BackupCodeMapper $mapper */
- $mapper = $this->getContainer()->query(BackupCodeMapper::class);
- $mapper->deleteCodesByUserId($params['uid']);
+ public function boot(IBootContext $context): void {
}
}
diff --git a/apps/twofactor_backupcodes/lib/BackgroundJob/CheckBackupCodes.php b/apps/twofactor_backupcodes/lib/BackgroundJob/CheckBackupCodes.php
new file mode 100644
index 00000000000..bc26cb260f4
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/BackgroundJob/CheckBackupCodes.php
@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\BackgroundJob;
+
+use OC\Authentication\TwoFactorAuth\Manager;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Authentication\TwoFactorAuth\IRegistry;
+use OCP\BackgroundJob\IJobList;
+use OCP\BackgroundJob\QueuedJob;
+use OCP\IUser;
+use OCP\IUserManager;
+
+class CheckBackupCodes extends QueuedJob {
+
+ /** @var Manager */
+ private $twofactorManager;
+
+ public function __construct(
+ ITimeFactory $timeFactory,
+ private IUserManager $userManager,
+ private IJobList $jobList,
+ Manager $twofactorManager,
+ private IRegistry $registry,
+ ) {
+ parent::__construct($timeFactory);
+ $this->twofactorManager = $twofactorManager;
+ }
+
+ protected function run($argument) {
+ $this->userManager->callForSeenUsers(function (IUser $user): void {
+ if (!$user->isEnabled()) {
+ return;
+ }
+
+ $providers = $this->registry->getProviderStates($user);
+ $isTwoFactorAuthenticated = $this->twofactorManager->isTwoFactorAuthenticated($user);
+
+ if ($isTwoFactorAuthenticated && isset($providers['backup_codes']) && $providers['backup_codes'] === false) {
+ $this->jobList->add(RememberBackupCodesJob::class, ['uid' => $user->getUID()]);
+ }
+ });
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/BackgroundJob/RememberBackupCodesJob.php b/apps/twofactor_backupcodes/lib/BackgroundJob/RememberBackupCodesJob.php
new file mode 100644
index 00000000000..5e853479f0a
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/BackgroundJob/RememberBackupCodesJob.php
@@ -0,0 +1,77 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\BackgroundJob;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Authentication\TwoFactorAuth\IRegistry;
+use OCP\BackgroundJob\IJobList;
+use OCP\BackgroundJob\TimedJob;
+use OCP\IUserManager;
+use OCP\Notification\IManager;
+
+class RememberBackupCodesJob extends TimedJob {
+
+ public function __construct(
+ private IRegistry $registry,
+ private IUserManager $userManager,
+ ITimeFactory $timeFactory,
+ private IManager $notificationManager,
+ private IJobList $jobList,
+ ) {
+ parent::__construct($timeFactory);
+ $this->time = $timeFactory;
+
+ $this->setInterval(60 * 60 * 24 * 14);
+ $this->setTimeSensitivity(self::TIME_INSENSITIVE);
+ }
+
+ protected function run($argument) {
+ $uid = $argument['uid'];
+ $user = $this->userManager->get($uid);
+
+ if ($user === null) {
+ // We can't run with an invalid user
+ $this->jobList->remove(self::class, $argument);
+ return;
+ }
+
+ $providers = $this->registry->getProviderStates($user);
+ $state2fa = array_reduce($providers, function (bool $carry, bool $state) {
+ return $carry || $state;
+ }, false);
+
+ /*
+ * If no provider is active or if the backup codes are already generate
+ * we can remove the job
+ */
+ if ($state2fa === false || (isset($providers['backup_codes']) && $providers['backup_codes'] === true)) {
+ // Backup codes already generated lets remove this job
+ $this->jobList->remove(self::class, $argument);
+ return;
+ }
+
+ $date = new \DateTime();
+ $date->setTimestamp($this->time->getTime());
+
+ $notification = $this->notificationManager->createNotification();
+ $notification->setApp('twofactor_backupcodes')
+ ->setUser($user->getUID())
+ ->setObject('create', 'codes')
+ ->setSubject('create_backupcodes');
+ $this->notificationManager->markProcessed($notification);
+
+ if (!$user->isEnabled()) {
+ // Don't recreate a notification for a user that can not read it
+ $this->jobList->remove(self::class, $argument);
+ return;
+ }
+ $notification->setDateTime($date);
+ $this->notificationManager->notify($notification);
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Controller/SettingsController.php b/apps/twofactor_backupcodes/lib/Controller/SettingsController.php
index 9b0b0fc57ba..effc058e05c 100644
--- a/apps/twofactor_backupcodes/lib/Controller/SettingsController.php
+++ b/apps/twofactor_backupcodes/lib/Controller/SettingsController.php
@@ -1,69 +1,44 @@
<?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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Controller;
use OCA\TwoFactorBackupCodes\Service\BackupCodeStorage;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
+use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest;
use OCP\IUserSession;
class SettingsController extends Controller {
- /** @var BackupCodeStorage */
- private $storage;
-
- /** @var IUserSession */
- private $userSession;
-
/**
* @param string $appName
* @param IRequest $request
* @param BackupCodeStorage $storage
* @param IUserSession $userSession
*/
- public function __construct($appName, IRequest $request, BackupCodeStorage $storage, IUserSession $userSession) {
+ public function __construct(
+ $appName,
+ IRequest $request,
+ private BackupCodeStorage $storage,
+ private IUserSession $userSession,
+ ) {
parent::__construct($appName, $request);
- $this->userSession = $userSession;
- $this->storage = $storage;
}
/**
- * @NoAdminRequired
* @return JSONResponse
*/
- public function state() {
- $user = $this->userSession->getUser();
- return $this->storage->getBackupCodesState($user);
- }
-
- /**
- * @NoAdminRequired
- * @PasswordConfirmationRequired
- *
- * @return JSONResponse
- */
- public function createCodes() {
+ #[NoAdminRequired]
+ #[PasswordConfirmationRequired]
+ public function createCodes(): JSONResponse {
$user = $this->userSession->getUser();
$codes = $this->storage->createCodes($user);
return new JSONResponse([
@@ -71,5 +46,4 @@ class SettingsController extends Controller {
'state' => $this->storage->getBackupCodesState($user),
]);
}
-
}
diff --git a/apps/twofactor_backupcodes/lib/Db/BackupCode.php b/apps/twofactor_backupcodes/lib/Db/BackupCode.php
index cff515dd4aa..252b9b77faa 100644
--- a/apps/twofactor_backupcodes/lib/Db/BackupCode.php
+++ b/apps/twofactor_backupcodes/lib/Db/BackupCode.php
@@ -1,27 +1,13 @@
<?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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Db;
-
use OCP\AppFramework\Db\Entity;
/**
@@ -42,5 +28,4 @@ class BackupCode extends Entity {
/** @var int */
protected $used;
-
}
diff --git a/apps/twofactor_backupcodes/lib/Db/BackupCodeMapper.php b/apps/twofactor_backupcodes/lib/Db/BackupCodeMapper.php
index 03fe7bb5ec8..fbbc3d0403c 100644
--- a/apps/twofactor_backupcodes/lib/Db/BackupCodeMapper.php
+++ b/apps/twofactor_backupcodes/lib/Db/BackupCodeMapper.php
@@ -1,33 +1,22 @@
<?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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Db;
-use OCP\AppFramework\Db\Mapper;
+use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUser;
-class BackupCodeMapper extends Mapper {
-
+/**
+ * @template-extends QBMapper<BackupCode>
+ */
+class BackupCodeMapper extends QBMapper {
public function __construct(IDBConnection $db) {
parent::__construct($db, 'twofactor_backupcodes');
}
@@ -36,34 +25,28 @@ class BackupCodeMapper extends Mapper {
* @param IUser $user
* @return BackupCode[]
*/
- public function getBackupCodes(IUser $user) {
+ public function getBackupCodes(IUser $user): array {
/* @var IQueryBuilder $qb */
$qb = $this->db->getQueryBuilder();
$qb->select('id', 'user_id', 'code', 'used')
->from('twofactor_backupcodes')
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($user->getUID())));
- $result = $qb->execute();
- $rows = $result->fetchAll();
- $result->closeCursor();
-
- return array_map(function ($row) {
- return BackupCode::fromRow($row);
- }, $rows);
+ return self::findEntities($qb);
}
/**
* @param IUser $user
*/
- public function deleteCodes(IUser $user) {
+ public function deleteCodes(IUser $user): void {
$this->deleteCodesByUserId($user->getUID());
}
/**
* @param string $uid
*/
- public function deleteCodesByUserId($uid) {
+ public function deleteCodesByUserId(string $uid): void {
/* @var IQueryBuilder $qb */
$qb = $this->db->getQueryBuilder();
@@ -71,5 +54,4 @@ class BackupCodeMapper extends Mapper {
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($uid)));
$qb->execute();
}
-
}
diff --git a/apps/twofactor_backupcodes/lib/Event/CodesGenerated.php b/apps/twofactor_backupcodes/lib/Event/CodesGenerated.php
new file mode 100644
index 00000000000..90dc6206f71
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Event/CodesGenerated.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Event;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+class CodesGenerated extends Event {
+
+ public function __construct(
+ private IUser $user,
+ ) {
+ parent::__construct();
+ }
+
+ /**
+ * @return IUser
+ */
+ public function getUser(): IUser {
+ return $this->user;
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Listener/ActivityPublisher.php b/apps/twofactor_backupcodes/lib/Listener/ActivityPublisher.php
new file mode 100644
index 00000000000..b52f1f2c098
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Listener/ActivityPublisher.php
@@ -0,0 +1,44 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Listener;
+
+use BadMethodCallException;
+use OCA\TwoFactorBackupCodes\Event\CodesGenerated;
+use OCP\Activity\IManager;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use Psr\Log\LoggerInterface;
+
+/** @template-implements IEventListener<CodesGenerated> */
+class ActivityPublisher implements IEventListener {
+ public function __construct(
+ private IManager $activityManager,
+ private LoggerInterface $logger,
+ ) {
+ }
+
+ /**
+ * Push an event to the user's activity stream
+ */
+ public function handle(Event $event): void {
+ if ($event instanceof CodesGenerated) {
+ $activity = $this->activityManager->generateEvent();
+ $activity->setApp('twofactor_backupcodes')
+ ->setType('security')
+ ->setAuthor($event->getUser()->getUID())
+ ->setAffectedUser($event->getUser()->getUID())
+ ->setSubject('codes_generated');
+ try {
+ $this->activityManager->publish($activity);
+ } catch (BadMethodCallException $e) {
+ $this->logger->error('Could not publish backup code creation activity', ['exception' => $e]);
+ }
+ }
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Listener/ClearNotifications.php b/apps/twofactor_backupcodes/lib/Listener/ClearNotifications.php
new file mode 100644
index 00000000000..46bb1583004
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Listener/ClearNotifications.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Listener;
+
+use OCA\TwoFactorBackupCodes\Event\CodesGenerated;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Notification\IManager;
+
+/** @template-implements IEventListener<CodesGenerated> */
+class ClearNotifications implements IEventListener {
+
+ public function __construct(
+ private IManager $manager,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof CodesGenerated)) {
+ return;
+ }
+
+ $notification = $this->manager->createNotification();
+ $notification->setApp('twofactor_backupcodes')
+ ->setUser($event->getUser()->getUID())
+ ->setObject('create', 'codes');
+ $this->manager->markProcessed($notification);
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Listener/ProviderDisabled.php b/apps/twofactor_backupcodes/lib/Listener/ProviderDisabled.php
new file mode 100644
index 00000000000..a8d51e55c1b
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Listener/ProviderDisabled.php
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Listener;
+
+use OCA\TwoFactorBackupCodes\BackgroundJob\RememberBackupCodesJob;
+use OCP\Authentication\TwoFactorAuth\IRegistry;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserUnregistered;
+use OCP\BackgroundJob\IJobList;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+/** @template-implements IEventListener<TwoFactorProviderForUserUnregistered> */
+class ProviderDisabled implements IEventListener {
+
+ public function __construct(
+ private IRegistry $registry,
+ private IJobList $jobList,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof TwoFactorProviderForUserUnregistered)) {
+ return;
+ }
+
+ $providers = $this->registry->getProviderStates($event->getUser());
+
+ // Loop over all providers. If all are disabled we remove the job
+ $state = array_reduce($providers, function (bool $carry, bool $enabled) {
+ return $carry || $enabled;
+ }, false);
+
+ if ($state === false) {
+ $this->jobList->remove(RememberBackupCodesJob::class, ['uid' => $event->getUser()->getUID()]);
+ }
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Listener/ProviderEnabled.php b/apps/twofactor_backupcodes/lib/Listener/ProviderEnabled.php
new file mode 100644
index 00000000000..4ec510e7194
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Listener/ProviderEnabled.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Listener;
+
+use OCA\TwoFactorBackupCodes\BackgroundJob\RememberBackupCodesJob;
+use OCP\Authentication\TwoFactorAuth\IRegistry;
+use OCP\Authentication\TwoFactorAuth\TwoFactorProviderForUserRegistered;
+use OCP\BackgroundJob\IJobList;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+/** @template-implements IEventListener<TwoFactorProviderForUserRegistered> */
+class ProviderEnabled implements IEventListener {
+
+ public function __construct(
+ private IRegistry $registry,
+ private IJobList $jobList,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof TwoFactorProviderForUserRegistered)) {
+ return;
+ }
+
+ $providers = $this->registry->getProviderStates($event->getUser());
+ if (isset($providers['backup_codes']) && $providers['backup_codes'] === true) {
+ // Backup codes already generated nothing to do here
+ return;
+ }
+
+ $this->jobList->add(RememberBackupCodesJob::class, ['uid' => $event->getUser()->getUID()]);
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Listener/RegistryUpdater.php b/apps/twofactor_backupcodes/lib/Listener/RegistryUpdater.php
new file mode 100644
index 00000000000..1cb07bd9805
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Listener/RegistryUpdater.php
@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Listener;
+
+use OCA\TwoFactorBackupCodes\Event\CodesGenerated;
+use OCA\TwoFactorBackupCodes\Provider\BackupCodesProvider;
+use OCP\Authentication\TwoFactorAuth\IRegistry;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+
+/** @template-implements IEventListener<CodesGenerated> */
+class RegistryUpdater implements IEventListener {
+
+ public function __construct(
+ private IRegistry $registry,
+ private BackupCodesProvider $provider,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if ($event instanceof CodesGenerated) {
+ $this->registry->enableProviderFor($this->provider, $event->getUser());
+ }
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Listener/UserDeleted.php b/apps/twofactor_backupcodes/lib/Listener/UserDeleted.php
new file mode 100644
index 00000000000..72fd504b338
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Listener/UserDeleted.php
@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Listener;
+
+use OCA\TwoFactorBackupCodes\Db\BackupCodeMapper;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\User\Events\UserDeletedEvent;
+
+/** @template-implements IEventListener<UserDeletedEvent> */
+class UserDeleted implements IEventListener {
+
+ public function __construct(
+ private BackupCodeMapper $backupCodeMapper,
+ ) {
+ }
+
+ public function handle(Event $event): void {
+ if (!($event instanceof UserDeletedEvent)) {
+ return;
+ }
+
+ $this->backupCodeMapper->deleteCodes($event->getUser());
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Migration/CheckBackupCodes.php b/apps/twofactor_backupcodes/lib/Migration/CheckBackupCodes.php
new file mode 100644
index 00000000000..9c0c676134b
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Migration/CheckBackupCodes.php
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Migration;
+
+use OCP\BackgroundJob\IJobList;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class CheckBackupCodes implements IRepairStep {
+
+ public function __construct(
+ private IJobList $jobList,
+ ) {
+ }
+
+ public function getName(): string {
+ return 'Add background job to check for backup codes';
+ }
+
+ public function run(IOutput $output) {
+ $this->jobList->add(\OCA\TwoFactorBackupCodes\BackgroundJob\CheckBackupCodes::class);
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607104347.php b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607104347.php
index 9d369ae3a8d..ce752541bac 100644
--- a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607104347.php
+++ b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607104347.php
@@ -1,32 +1,17 @@
<?php
+
+declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
- *
- * @author Joas Schilling <coding@schilljs.com>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Migration;
+use Doctrine\DBAL\Types\Types;
use OCP\DB\ISchemaWrapper;
-use Doctrine\DBAL\Types\Type;
-use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
class Version1002Date20170607104347 extends SimpleMigrationStep {
/**
@@ -43,20 +28,20 @@ class Version1002Date20170607104347 extends SimpleMigrationStep {
if (!$schema->hasTable('twofactor_backupcodes')) {
$table = $schema->createTable('twofactor_backupcodes');
- $table->addColumn('id', Type::INTEGER, [
+ $table->addColumn('id', Types::INTEGER, [
'autoincrement' => true,
'notnull' => true,
'length' => 20,
]);
- $table->addColumn('user_id', Type::STRING, [
+ $table->addColumn('user_id', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
- $table->addColumn('code', Type::STRING, [
+ $table->addColumn('code', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
- $table->addColumn('used', Type::INTEGER, [
+ $table->addColumn('used', Types::INTEGER, [
'notnull' => true,
'length' => 1,
'default' => 0,
diff --git a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607113030.php b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607113030.php
index 6895aa44a51..bed733cd413 100644
--- a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607113030.php
+++ b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170607113030.php
@@ -1,44 +1,27 @@
<?php
+
+declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
- *
- * @author Joas Schilling <coding@schilljs.com>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Migration;
use OCP\DB\ISchemaWrapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
-use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
class Version1002Date20170607113030 extends SimpleMigrationStep {
- /** @var IDBConnection */
- protected $connection;
-
/**
* @param IDBConnection $connection
*/
- public function __construct(IDBConnection $connection) {
- $this->connection = $connection;
+ public function __construct(
+ protected IDBConnection $connection,
+ ) {
}
/**
diff --git a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php
index 5cbbcb2ecca..2ca390e6edd 100644
--- a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php
+++ b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170919123342.php
@@ -1,32 +1,18 @@
<?php
+
+declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
- *
- * @author Joas Schilling <coding@schilljs.com>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Migration;
use Doctrine\DBAL\Types\Type;
+use Doctrine\DBAL\Types\Types;
use OCP\DB\ISchemaWrapper;
-use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
class Version1002Date20170919123342 extends SimpleMigrationStep {
@@ -46,8 +32,8 @@ class Version1002Date20170919123342 extends SimpleMigrationStep {
$column->setDefault('');
$column = $table->getColumn('used');
- if ($column->getType()->getName() !== Type::SMALLINT) {
- $column->setType(Type::getType(Type::SMALLINT));
+ if ($column->getType()->getName() !== Types::SMALLINT) {
+ $column->setType(Type::getType(Types::SMALLINT));
$column->setOptions(['length' => 6]);
}
diff --git a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170926101419.php b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170926101419.php
index 0e19fe2a35e..d19fda49182 100644
--- a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170926101419.php
+++ b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20170926101419.php
@@ -1,4 +1,11 @@
<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
namespace OCA\TwoFactorBackupCodes\Migration;
use OCP\Migration\BigIntMigration;
@@ -10,7 +17,7 @@ class Version1002Date20170926101419 extends BigIntMigration {
/**
* @return array Returns an array with the following structure
- * ['table1' => ['column1', 'column2'], ...]
+ * ['table1' => ['column1', 'column2'], ...]
* @since 13.0.0
*/
protected function getColumnsByTable() {
@@ -18,5 +25,4 @@ class Version1002Date20170926101419 extends BigIntMigration {
'twofactor_backupcodes' => ['id'],
];
}
-
}
diff --git a/apps/twofactor_backupcodes/lib/Migration/Version1002Date20180821043638.php b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20180821043638.php
new file mode 100644
index 00000000000..04d6d58c783
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Migration/Version1002Date20180821043638.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Migration;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+class Version1002Date20180821043638 extends SimpleMigrationStep {
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ *
+ * @return ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+ $table = $schema->getTable('twofactor_backupcodes');
+
+ $table->getColumn('code')->setLength(128);
+
+ return $schema;
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Notifications/Notifier.php b/apps/twofactor_backupcodes/lib/Notifications/Notifier.php
new file mode 100644
index 00000000000..e8144f52a56
--- /dev/null
+++ b/apps/twofactor_backupcodes/lib/Notifications/Notifier.php
@@ -0,0 +1,73 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCA\TwoFactorBackupCodes\Notifications;
+
+use OCP\IURLGenerator;
+use OCP\L10N\IFactory;
+use OCP\Notification\INotification;
+use OCP\Notification\INotifier;
+use OCP\Notification\UnknownNotificationException;
+
+class Notifier implements INotifier {
+
+ public function __construct(
+ private IFactory $factory,
+ private IURLGenerator $url,
+ ) {
+ }
+
+ /**
+ * Identifier of the notifier, only use [a-z0-9_]
+ *
+ * @return string
+ * @since 17.0.0
+ */
+ public function getID(): string {
+ return 'twofactor_backupcodes';
+ }
+
+ /**
+ * Human readable name describing the notifier
+ *
+ * @return string
+ * @since 17.0.0
+ */
+ public function getName(): string {
+ return $this->factory->get('twofactor_backupcodes')->t('Second-factor backup codes');
+ }
+
+ public function prepare(INotification $notification, string $languageCode): INotification {
+ if ($notification->getApp() !== 'twofactor_backupcodes') {
+ // Not my app => throw
+ throw new UnknownNotificationException();
+ }
+
+ // Read the language from the notification
+ $l = $this->factory->get('twofactor_backupcodes', $languageCode);
+
+ switch ($notification->getSubject()) {
+ case 'create_backupcodes':
+ $notification->setParsedSubject(
+ $l->t('Generate backup codes')
+ )->setParsedMessage(
+ $l->t('You enabled two-factor authentication but did not generate backup codes yet. They are needed to restore access to your account in case you lose your second factor.')
+ );
+
+ $notification->setLink($this->url->linkToRouteAbsolute('settings.PersonalSettings.index', ['section' => 'security']));
+
+ $notification->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/password.svg')));
+
+ return $notification;
+
+ default:
+ // Unknown subject => Unknown notification => throw
+ throw new UnknownNotificationException();
+ }
+ }
+}
diff --git a/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php b/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php
index 5c5500862e6..c521329e203 100644
--- a/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php
+++ b/apps/twofactor_backupcodes/lib/Provider/BackupCodesProvider.php
@@ -1,59 +1,34 @@
<?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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Provider;
use OC\App\AppManager;
use OCA\TwoFactorBackupCodes\Service\BackupCodeStorage;
-use OCP\Authentication\TwoFactorAuth\IProvider;
+use OCA\TwoFactorBackupCodes\Settings\Personal;
+use OCP\AppFramework\Services\IInitialState;
+use OCP\Authentication\TwoFactorAuth\IDeactivatableByAdmin;
+use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
+use OCP\Authentication\TwoFactorAuth\IProvidesPersonalSettings;
use OCP\IL10N;
use OCP\IUser;
-use OCP\Template;
-
-class BackupCodesProvider implements IProvider {
-
- /** @var string */
- private $appName;
-
- /** @var BackupCodeStorage */
- private $storage;
-
- /** @var IL10N */
- private $l10n;
-
- /** @var AppManager */
- private $appManager;
-
- /**
- * @param string $appName
- * @param BackupCodeStorage $storage
- * @param IL10N $l10n
- * @param AppManager $appManager
- */
- public function __construct($appName, BackupCodeStorage $storage, IL10N $l10n, AppManager $appManager) {
- $this->appName = $appName;
- $this->l10n = $l10n;
- $this->storage = $storage;
- $this->appManager = $appManager;
+use OCP\Template\ITemplate;
+use OCP\Template\ITemplateManager;
+
+class BackupCodesProvider implements IDeactivatableByAdmin, IProvidesPersonalSettings {
+ public function __construct(
+ private string $appName,
+ private BackupCodeStorage $storage,
+ private IL10N $l10n,
+ private AppManager $appManager,
+ private IInitialState $initialState,
+ private ITemplateManager $templateManager,
+ ) {
}
/**
@@ -61,7 +36,7 @@ class BackupCodesProvider implements IProvider {
*
* @return string
*/
- public function getId() {
+ public function getId(): string {
return 'backup_codes';
}
@@ -70,7 +45,7 @@ class BackupCodesProvider implements IProvider {
*
* @return string
*/
- public function getDisplayName() {
+ public function getDisplayName(): string {
return $this->l10n->t('Backup code');
}
@@ -79,7 +54,7 @@ class BackupCodesProvider implements IProvider {
*
* @return string
*/
- public function getDescription() {
+ public function getDescription(): string {
return $this->l10n->t('Use backup code');
}
@@ -87,11 +62,10 @@ class BackupCodesProvider implements IProvider {
* Get the template for rending the 2FA provider view
*
* @param IUser $user
- * @return Template
+ * @return ITemplate
*/
- public function getTemplate(IUser $user) {
- $tmpl = new Template('twofactor_backupcodes', 'challenge');
- return $tmpl;
+ public function getTemplate(IUser $user): ITemplate {
+ return $this->templateManager->getTemplate('twofactor_backupcodes', 'challenge');
}
/**
@@ -99,8 +73,9 @@ class BackupCodesProvider implements IProvider {
*
* @param IUser $user
* @param string $challenge
+ * @return bool
*/
- public function verifyChallenge(IUser $user, $challenge) {
+ public function verifyChallenge(IUser $user, string $challenge): bool {
return $this->storage->validateCode($user, $challenge);
}
@@ -110,7 +85,7 @@ class BackupCodesProvider implements IProvider {
* @param IUser $user
* @return boolean
*/
- public function isTwoFactorAuthEnabledForUser(IUser $user) {
+ public function isTwoFactorAuthEnabledForUser(IUser $user): bool {
return $this->storage->hasBackupCodes($user);
}
@@ -125,8 +100,8 @@ class BackupCodesProvider implements IProvider {
* @param IUser $user
* @return boolean
*/
- public function isActive(IUser $user) {
- $appIds = array_filter($this->appManager->getEnabledAppsForUser($user), function($appId) {
+ public function isActive(IUser $user): bool {
+ $appIds = array_filter($this->appManager->getEnabledAppsForUser($user), function ($appId) {
return $appId !== $this->appName;
});
foreach ($appIds as $appId) {
@@ -138,4 +113,18 @@ class BackupCodesProvider implements IProvider {
return false;
}
+ /**
+ * @param IUser $user
+ *
+ * @return IPersonalProviderSettings
+ */
+ public function getPersonalSettings(IUser $user): IPersonalProviderSettings {
+ $state = $this->storage->getBackupCodesState($user);
+ $this->initialState->provideInitialState('state', $state);
+ return new Personal();
+ }
+
+ public function disableFor(IUser $user): void {
+ $this->storage->deleteCodes($user);
+ }
}
diff --git a/apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php b/apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php
index 84bf54d3379..7dd6b3949e2 100644
--- a/apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php
+++ b/apps/twofactor_backupcodes/lib/Service/BackupCodeStorage.php
@@ -1,76 +1,38 @@
<?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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCA\TwoFactorBackupCodes\Service;
-use BadMethodCallException;
use OCA\TwoFactorBackupCodes\Db\BackupCode;
use OCA\TwoFactorBackupCodes\Db\BackupCodeMapper;
-use OCP\Activity\IManager;
-use OCP\ILogger;
+use OCA\TwoFactorBackupCodes\Event\CodesGenerated;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\IUser;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
class BackupCodeStorage {
-
private static $CODE_LENGTH = 16;
- /** @var BackupCodeMapper */
- private $mapper;
-
- /** @var IHasher */
- private $hasher;
-
- /** @var ISecureRandom */
- private $random;
-
- /** @var IManager */
- private $activityManager;
-
- /** @var ILogger */
- private $logger;
-
- /**
- * @param BackupCodeMapper $mapper
- * @param ISecureRandom $random
- * @param IHasher $hasher
- * @param IManager $activityManager
- * @param ILogger $logger
- */
- public function __construct(BackupCodeMapper $mapper, ISecureRandom $random, IHasher $hasher,
- IManager $activityManager, ILogger $logger) {
- $this->mapper = $mapper;
- $this->hasher = $hasher;
- $this->random = $random;
- $this->activityManager = $activityManager;
- $this->logger = $logger;
+ public function __construct(
+ private BackupCodeMapper $mapper,
+ private ISecureRandom $random,
+ private IHasher $hasher,
+ private IEventDispatcher $eventDispatcher,
+ ) {
}
/**
* @param IUser $user
+ * @param int $number
* @return string[]
*/
- public function createCodes(IUser $user, $number = 10) {
+ public function createCodes(IUser $user, int $number = 10): array {
$result = [];
// Delete existing ones
@@ -78,7 +40,7 @@ class BackupCodeStorage {
$uid = $user->getUID();
foreach (range(1, min([$number, 20])) as $i) {
- $code = $this->random->generate(self::$CODE_LENGTH, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS);
+ $code = $this->random->generate(self::$CODE_LENGTH, ISecureRandom::CHAR_HUMAN_READABLE);
$dbCode = new BackupCode();
$dbCode->setUserId($uid);
@@ -86,40 +48,19 @@ class BackupCodeStorage {
$dbCode->setUsed(0);
$this->mapper->insert($dbCode);
- array_push($result, $code);
+ $result[] = $code;
}
- $this->publishEvent($user, 'codes_generated');
+ $this->eventDispatcher->dispatchTyped(new CodesGenerated($user));
return $result;
}
/**
- * Push an event the user's activity stream
- *
- * @param IUser $user
- * @param string $event
- */
- private function publishEvent(IUser $user, $event) {
- $activity = $this->activityManager->generateEvent();
- $activity->setApp('twofactor_backupcodes')
- ->setType('security')
- ->setAuthor($user->getUID())
- ->setAffectedUser($user->getUID())
- ->setSubject($event);
- try {
- $this->activityManager->publish($activity);
- } catch (BadMethodCallException $e) {
- $this->logger->warning('could not publish backup code creation activity', ['app' => 'twofactor_backupcodes']);
- $this->logger->logException($e, ['app' => 'twofactor_backupcodes']);
- }
- }
-
- /**
* @param IUser $user
* @return bool
*/
- public function hasBackupCodes(IUser $user) {
+ public function hasBackupCodes(IUser $user): bool {
$codes = $this->mapper->getBackupCodes($user);
return count($codes) > 0;
}
@@ -128,12 +69,12 @@ class BackupCodeStorage {
* @param IUser $user
* @return array
*/
- public function getBackupCodesState(IUser $user) {
+ public function getBackupCodesState(IUser $user): array {
$codes = $this->mapper->getBackupCodes($user);
$total = count($codes);
$used = 0;
- array_walk($codes, function (BackupCode $code) use (&$used) {
- if (1 === (int) $code->getUsed()) {
+ array_walk($codes, function (BackupCode $code) use (&$used): void {
+ if ((int)$code->getUsed() === 1) {
$used++;
}
});
@@ -149,11 +90,11 @@ class BackupCodeStorage {
* @param string $code
* @return bool
*/
- public function validateCode(IUser $user, $code) {
+ public function validateCode(IUser $user, string $code): bool {
$dbCodes = $this->mapper->getBackupCodes($user);
foreach ($dbCodes as $dbCode) {
- if (0 === (int) $dbCode->getUsed() && $this->hasher->verify($code, $dbCode->getCode())) {
+ if ((int)$dbCode->getUsed() === 0 && $this->hasher->verify($code, $dbCode->getCode())) {
$dbCode->setUsed(1);
$this->mapper->update($dbCode);
return true;
@@ -162,4 +103,7 @@ class BackupCodeStorage {
return false;
}
+ public function deleteCodes(IUser $user): void {
+ $this->mapper->deleteCodes($user);
+ }
}
diff --git a/apps/twofactor_backupcodes/lib/Settings/Personal.php b/apps/twofactor_backupcodes/lib/Settings/Personal.php
index eb28dacb42b..e03c3d303db 100644
--- a/apps/twofactor_backupcodes/lib/Settings/Personal.php
+++ b/apps/twofactor_backupcodes/lib/Settings/Personal.php
@@ -1,82 +1,21 @@
<?php
+
+declare(strict_types=1);
+
/**
- * @copyright Copyright (c) 2017 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @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/>.
- *
+ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\TwoFactorBackupCodes\Settings;
+use OCP\Authentication\TwoFactorAuth\IPersonalProviderSettings;
+use OCP\Server;
+use OCP\Template\ITemplate;
+use OCP\Template\ITemplateManager;
-use OCA\TwoFactorBackupCodes\AppInfo\Application;
-use OCA\TwoFactorBackupCodes\Provider\BackupCodesProvider;
-use OCP\AppFramework\Http\TemplateResponse;
-use OCP\IUserSession;
-use OCP\Settings\ISettings;
-
-class Personal implements ISettings {
-
- /** @var Application */
- private $app;
- /** @var BackupCodesProvider */
- private $provider;
- /** @var IUserSession */
- private $userSession;
-
- public function __construct(Application $app, BackupCodesProvider $provider, IUserSession $userSession) {
- $this->app = $app;
- $this->provider = $provider;
- $this->userSession = $userSession;
- }
-
- /**
- * @return TemplateResponse returns the instance with all parameters set, ready to be rendered
- * @since 9.1
- */
- public function getForm() {
- $templateOwner = 'settings';
- $templateName = 'settings/empty';
- if ($this->provider->isActive($this->userSession->getUser())) {
- $templateOwner = $this->app->getContainer()->getAppName();
- $templateName = 'personal';
- }
-
- return new TemplateResponse($templateOwner, $templateName, [], '');
- }
-
- /**
- * @return string the section ID, e.g. 'sharing'
- * @since 9.1
- */
- public function getSection() {
- return 'security';
- }
-
- /**
- * @return int whether the form should be rather on the top or bottom of
- * the admin section. The forms are arranged in ascending order of the
- * priority values. It is required to return a value between 0 and 100.
- *
- * E.g.: 70
- * @since 9.1
- */
- public function getPriority() {
- return 40;
+class Personal implements IPersonalProviderSettings {
+ public function getBody(): ITemplate {
+ return Server::get(ITemplateManager::class)->getTemplate('twofactor_backupcodes', 'personal');
}
}