Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/twofactor_totp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Kesselberg <mail@danielkesselberg.de>2022-09-13 20:11:28 +0300
committerDaniel Kesselberg <mail@danielkesselberg.de>2022-09-13 23:08:42 +0300
commitf1a24d038ece5d83e6dd73cc1e4fa0df664489fb (patch)
tree19d043fad3b557749d3e1d40eb29e048efd31017
parentf1d274eed6952849eb032df4122f0a05bd8eea64 (diff)
Add command to cleanup topt secretsdebt/noid/cleanup
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
-rw-r--r--appinfo/info.xml5
-rw-r--r--lib/AppInfo/Application.php3
-rw-r--r--lib/Command/CleanUp.php106
-rw-r--r--lib/Db/TotpSecretMapper.php13
-rw-r--r--lib/Listener/UserDeleted.php58
5 files changed, 184 insertions, 1 deletions
diff --git a/appinfo/info.xml b/appinfo/info.xml
index fabf4ca..9cc1aeb 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -5,7 +5,7 @@
<name>Two-Factor TOTP Provider</name>
<summary>TOTP two-factor provider</summary>
<description>A Two-Factor-Auth Provider for TOTP (RFC 6238)</description>
- <version>6.4.0-alpha.1</version>
+ <version>6.4.0-alpha.2</version>
<licence>agpl</licence>
<author>Christoph Wurst</author>
<namespace>TwoFactorTOTP</namespace>
@@ -23,6 +23,9 @@
<two-factor-providers>
<provider>OCA\TwoFactorTOTP\Provider\TotpProvider</provider>
</two-factor-providers>
+ <commands>
+ <command>OCA\TwoFactorTOTP\Command\CleanUp</command>
+ </commands>
<activity>
<settings>
<setting>OCA\TwoFactorTOTP\Activity\Setting</setting>
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index ff5f7f4..d5aeffc 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -27,12 +27,14 @@ use OCA\TwoFactorTOTP\Event\DisabledByAdmin;
use OCA\TwoFactorTOTP\Event\StateChanged;
use OCA\TwoFactorTOTP\Listener\StateChangeActivity;
use OCA\TwoFactorTOTP\Listener\StateChangeRegistryUpdater;
+use OCA\TwoFactorTOTP\Listener\UserDeleted;
use OCA\TwoFactorTOTP\Service\ITotp;
use OCA\TwoFactorTOTP\Service\Totp;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
+use OCP\User\Events\UserDeletedEvent;
class Application extends App implements IBootstrap {
public const APP_ID = 'twofactor_totp';
@@ -49,6 +51,7 @@ class Application extends App implements IBootstrap {
$context->registerEventListener(StateChanged::class, StateChangeActivity::class);
$context->registerEventListener(StateChanged::class, StateChangeRegistryUpdater::class);
$context->registerEventListener(DisabledByAdmin::class, StateChangeActivity::class);
+ $context->registerEventListener(UserDeletedEvent::class, UserDeleted::class);
}
public function boot(IBootContext $context): void {
diff --git a/lib/Command/CleanUp.php b/lib/Command/CleanUp.php
new file mode 100644
index 0000000..a68fb1f
--- /dev/null
+++ b/lib/Command/CleanUp.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Daniel Kesselberg <mail@danielkesselberg.de>
+ *
+ * @author Daniel Kesselberg <mail@danielkesselberg.de>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * 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/>
+ *
+ */
+
+namespace OCA\TwoFactorTOTP\Command;
+
+use OCA\TwoFactorTOTP\Db\TotpSecretMapper;
+use OCP\DB\Exception;
+use OCP\IDBConnection;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+class CleanUp extends Command {
+ /** @var IDBConnection */
+ private $db;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var TotpSecretMapper */
+ private $totpSecretMapper;
+
+ public function __construct(
+ IDBConnection $db,
+ IUserManager $userManager,
+ TotpSecretMapper $totpSecretMapper
+ ) {
+ parent::__construct();
+
+ $this->db = $db;
+ $this->userManager = $userManager;
+ $this->totpSecretMapper = $totpSecretMapper;
+ }
+
+ protected function configure(): void {
+ $this
+ ->setName('twofactor_totp:cleanup')
+ ->setDescription('Remove orphaned totp secrets');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $io = new SymfonyStyle($input, $output);
+ $io->title('Remove totp secrets for deleted users');
+
+ foreach ($this->findUserIds() as $userId) {
+ if ($this->userManager->userExists($userId) === false) {
+ try {
+ $io->text('Delete secret for uid "' . $userId . '"');
+ $this->totpSecretMapper->deleteSecretByUserId($userId);
+ } catch (Exception $e) {
+ $io->caution('Error deleting secret: ' . $e->getMessage());
+ }
+ }
+ }
+
+ $io->success('Orphaned totp secrets removed.');
+
+ $io->text('Thank you for using Two-Factor TOTP!');
+ return 0;
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function findUserIds(): array {
+ $userIds = [];
+
+ $qb = $this->db->getQueryBuilder()
+ ->selectDistinct('user_id')
+ ->from($this->totpSecretMapper->getTableName());
+
+ $result = $qb->executeQuery();
+
+ while ($row = $result->fetch()) {
+ $userIds[] = $row['user_id'];
+ }
+
+ $result->closeCursor();
+
+ return $userIds;
+ }
+}
diff --git a/lib/Db/TotpSecretMapper.php b/lib/Db/TotpSecretMapper.php
index 50c605d..6428eee 100644
--- a/lib/Db/TotpSecretMapper.php
+++ b/lib/Db/TotpSecretMapper.php
@@ -26,6 +26,7 @@ namespace OCA\TwoFactorTOTP\Db;
use Doctrine\DBAL\Statement;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
+use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\IUser;
@@ -61,4 +62,16 @@ class TotpSecretMapper extends QBMapper {
}
return TotpSecret::fromRow($row);
}
+
+ /**
+ * @param string $uid
+ * @throws Exception
+ */
+ public function deleteSecretByUserId(string $uid): void {
+ $qb = $this->db->getQueryBuilder();
+
+ $qb->delete($this->getTableName())
+ ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($uid)));
+ $qb->executeStatement();
+ }
}
diff --git a/lib/Listener/UserDeleted.php b/lib/Listener/UserDeleted.php
new file mode 100644
index 0000000..53631db
--- /dev/null
+++ b/lib/Listener/UserDeleted.php
@@ -0,0 +1,58 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Daniel Kesselberg <mail@danielkesselberg.de>
+ *
+ * @author Daniel Kesselberg <mail@danielkesselberg.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/>.
+ *
+ */
+
+namespace OCA\TwoFactorTOTP\Listener;
+
+use OCA\TwoFactorTOTP\Db\TotpSecretMapper;
+use OCP\DB\Exception;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\User\Events\UserDeletedEvent;
+use Psr\Log\LoggerInterface;
+
+class UserDeleted implements IEventListener {
+
+ /** @var TotpSecretMapper */
+ private $totpSecretMapper;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ public function __construct(TotpSecretMapper $totpSecretMapper, LoggerInterface $logger) {
+ $this->totpSecretMapper = $totpSecretMapper;
+ $this->logger = $logger;
+ }
+
+ public function handle(Event $event): void {
+ if ($event instanceof UserDeletedEvent) {
+ try {
+ $this->totpSecretMapper->deleteSecretByUserId($event->getUser()->getUID());
+ } catch (Exception $e) {
+ $this->logger->warning($e->getMessage(), ['uid' => $event->getUser()->getUID()]);
+ }
+ }
+ }
+}