From 3d68a526e7ede5e2db13ffa69177a933a278b806 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 29 Sep 2022 13:40:04 +0200 Subject: [PATCH] move share owner repair to occ command Signed-off-by: Robin Appelman --- .../Maintenance/RepairShareOwnership.php | 134 ++++++++++++++++++ core/register_command.php | 1 + lib/private/Repair.php | 1 - lib/private/Repair/RepairShareOwnership.php | 94 ------------ lib/private/Share20/Manager.php | 4 + 5 files changed, 139 insertions(+), 95 deletions(-) create mode 100644 core/Command/Maintenance/RepairShareOwnership.php delete mode 100644 lib/private/Repair/RepairShareOwnership.php diff --git a/core/Command/Maintenance/RepairShareOwnership.php b/core/Command/Maintenance/RepairShareOwnership.php new file mode 100644 index 00000000000..351f2b9b0ed --- /dev/null +++ b/core/Command/Maintenance/RepairShareOwnership.php @@ -0,0 +1,134 @@ + + * + * @author Arthur Schiwon + * + * @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 . + * + */ + +namespace OC\Core\Command\Maintenance; + +use Symfony\Component\Console\Command\Command; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Share\IManager; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class RepairShareOwnership extends Command { + private IDBConnection $dbConnection; + private IManager $shareManager; + private IUserManager $userManager; + + public function __construct( + IDBConnection $dbConnection, + IManager $shareManager, + IUserManager $userManager + ) { + $this->dbConnection = $dbConnection; + $this->shareManager = $shareManager; + $this->userManager = $userManager; + parent::__construct(); + } + + protected function configure() { + $this + ->setName('maintenance:repair-share-owner') + ->setDescription('repair invalid share-owner entries in the database') + ->addOption('dry-run', null, InputOption::VALUE_NONE, "List detected issues without fixing them") + ->addArgument('user', InputArgument::OPTIONAL, "User to fix incoming shares for, if omitted all users will be fixed"); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $dryRun = $input->getOption('dry-run'); + $userId = $input->getArgument('user'); + if ($userId) { + $user = $this->userManager->get($userId); + if (!$user) { + $output->writeln("user $userId not found"); + return 1; + } + $found = $this->repairWrongShareOwnershipForUser($user, $dryRun); + } else { + $found = []; + $userCount = $this->userManager->countSeenUsers(); + $progress = new ProgressBar($output, $userCount); + $this->userManager->callForSeenUsers(function (IUser $user) use ($dryRun, &$found, $progress) { + $progress->advance(); + $found = array_merge($found, $this->repairWrongShareOwnershipForUser($user, $dryRun)); + }); + $progress->finish(); + $output->writeln(""); + } + foreach ($found as $item) { + $output->writeln($item); + } + return 0; + } + + protected function repairWrongShareOwnershipForUser(IUser $user, bool $dryRun = true): array { + $qb = $this->dbConnection->getQueryBuilder(); + $brokenShare = $qb + ->select('s.id', 'm.user_id', 's.uid_owner', 's.uid_initiator', 's.share_with', 's.share_type') + ->from('share', 's') + ->join('s', 'filecache', 'f', $qb->expr()->eq('s.item_source', $qb->expr()->castColumn('f.fileid', IQueryBuilder::PARAM_STR))) + ->join('s', 'mounts', 'm', $qb->expr()->eq('f.storage', 'm.storage_id')) + ->where($qb->expr()->neq('m.user_id', 's.uid_owner')) + ->andWhere($qb->expr()->eq($qb->func()->concat($qb->expr()->literal('/'), 'm.user_id', $qb->expr()->literal('/')), 'm.mount_point')) + ->andWhere($qb->expr()->eq('s.share_with', $qb->createNamedParameter($user->getUID()))) + ->executeQuery() + ->fetchAll(); + + $found = []; + + foreach ($brokenShare as $queryResult) { + $shareId = (int) $queryResult['id']; + $shareType = (int) $queryResult['share_type']; + $initiator = $queryResult['uid_initiator']; + $receiver = $queryResult['share_with']; + $owner = $queryResult['uid_owner']; + $mountOwner = $queryResult['user_id']; + + $found[] = "Found share from $initiator to $receiver, owned by $owner, that should be owned by $mountOwner"; + + if ($dryRun) { + continue; + } + + $provider = $this->shareManager->getProviderForType($shareType); + $share = $provider->getShareById($shareId); + + if ($share->getShareOwner() === $share->getSharedBy()) { + $share->setSharedBy($mountOwner); + } + $share->setShareOwner($mountOwner); + + $this->shareManager->updateShare($share); + } + + return $found; + } +} diff --git a/core/register_command.php b/core/register_command.php index 943180da706..b6da0a6d44d 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -173,6 +173,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) { \OC::$server->get(\OCP\EventDispatcher\IEventDispatcher::class), \OC::$server->getAppManager() )); + $application->add(\OC::$server->query(OC\Core\Command\Maintenance\RepairShareOwnership::class)); $application->add(\OC::$server->query(\OC\Core\Command\Preview\Repair::class)); $application->add(\OC::$server->query(\OC\Core\Command\Preview\ResetRenderedTexts::class)); diff --git a/lib/private/Repair.php b/lib/private/Repair.php index b8875f19945..d8476338486 100644 --- a/lib/private/Repair.php +++ b/lib/private/Repair.php @@ -210,7 +210,6 @@ class Repair implements IOutput { \OCP\Server::get(LookupServerSendCheck::class), \OCP\Server::get(AddTokenCleanupJob::class), \OCP\Server::get(CleanUpAbandonedApps::class), - \OCP\Server::get(RepairShareOwnership::class), ]; } diff --git a/lib/private/Repair/RepairShareOwnership.php b/lib/private/Repair/RepairShareOwnership.php deleted file mode 100644 index b7ff476d5f4..00000000000 --- a/lib/private/Repair/RepairShareOwnership.php +++ /dev/null @@ -1,94 +0,0 @@ - - * - * @author Arthur Schiwon - * - * @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 . - * - */ -namespace OC\Repair; - -use OCP\IDBConnection; -use OCP\Share\IManager; -use OCP\Migration\IOutput; -use OCP\Migration\IRepairStep; - -class RepairShareOwnership implements IRepairStep { - private IDBConnection $dbConnection; - private IManager $shareManager; - - public function __construct( - IDBConnection $dbConnection, - IManager $shareManager - ) { - $this->dbConnection = $dbConnection; - $this->shareManager = $shareManager; - } - - /** - * @inheritDoc - */ - public function getName() { - return 'Repair shares ownership'; - } - - protected function repairWrongShareOwnership(IOutput $output, bool $dryRun = true) { - $qb = $this->dbConnection->getQueryBuilder(); - $brokenShare = $qb - ->select('s.id', 'm.user_id', 's.uid_owner', 's.uid_initiator', 's.share_with') - ->from('share', 's') - ->join('s', 'filecache', 'f', $qb->expr()->eq('s.item_source', 'f.fileid')) - ->join('s', 'mounts', 'm', $qb->expr()->eq('f.storage', 'm.storage_id')) - ->where($qb->expr()->neq('m.user_id', 's.uid_owner')) - ->andWhere($qb->expr()->eq($qb->func()->concat($qb->expr()->literal('/'), 'm.user_id', $qb->expr()->literal('/')), 'm.mount_point')) - ->executeQuery() - ->fetchAll(); - - foreach ($brokenShare as $queryResult) { - $shareId = $queryResult['id']; - $initiator = $queryResult['uid_initiator']; - $receiver = $queryResult['share_with']; - $owner = $queryResult['uid_owner']; - $mountOwner = $queryResult['user_id']; - - $output->info("Found share from $initiator to $receiver, owned by $owner, that should be owned by $mountOwner"); - - if ($dryRun) { - continue; - } - - $share = $this->shareManager->getShareById($shareId); - - if ($share->getShareOwner() === $share->getSharedBy()) { - $share->setSharedBy($mountOwner); - } - $share->setShareOwner($mountOwner); - - $this->shareManager->updateShare($share); - } - } - - /** - * @inheritDoc - */ - public function run(IOutput $output) { - $this->repairWrongShareOwnership($output); - } -} diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index ffd779707df..9e6a867cf1b 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -2088,4 +2088,8 @@ class Manager implements IManager { yield from $provider->getAllShares(); } } + + public function getProviderForType(int $shareType): IShareProvider { + return $this->factory->getProviderForType($shareType); + } } -- 2.39.5