Skip to content

Commit 24d6a28

Browse files
committed
Repair step for link shares
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
1 parent 4c43e89 commit 24d6a28

File tree

7 files changed

+297
-1
lines changed

7 files changed

+297
-1
lines changed

core/Application.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
namespace OC\Core;
3030

31+
use OC\Core\Notification\RemoveLinkSharesNotifier;
3132
use OC\DB\MissingIndexInformation;
3233
use OC\DB\SchemaWrapper;
3334
use OCP\AppFramework\App;
@@ -54,6 +55,18 @@ public function __construct() {
5455
$server = $container->getServer();
5556
$eventDispatcher = $server->getEventDispatcher();
5657

58+
$notificationManager = $server->getNotificationManager();
59+
$notificationManager->registerNotifier(function() use ($server) {
60+
return new RemoveLinkSharesNotifier(
61+
$server->getL10NFactory()
62+
);
63+
}, function() use ($server) {
64+
return [
65+
'id' => 'core',
66+
'name' => 'core',
67+
];
68+
});
69+
5770
$eventDispatcher->addListener(IDBConnection::CHECK_MISSING_INDEXES_EVENT,
5871
function(GenericEvent $event) use ($container) {
5972
/** @var MissingIndexInformation $subject */
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
declare(strict_types=1);
3+
/**
4+
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
5+
*
6+
* @author Roeland Jago Douma <roeland@famdouma.nl>
7+
*
8+
* @license GNU AGPL version 3 or any later version
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU Affero General Public License as
12+
* published by the Free Software Foundation, either version 3 of the
13+
* License, or (at your option) any later version.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU Affero General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU Affero General Public License
21+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22+
*
23+
*/
24+
25+
namespace OC\Core\Notification;
26+
27+
use OCP\L10N\IFactory;
28+
use OCP\Notification\INotification;
29+
use OCP\Notification\INotifier;
30+
31+
class RemoveLinkSharesNotifier implements INotifier {
32+
/** @var IFactory */
33+
private $l10nFactory;
34+
35+
public function __construct(IFactory $factory) {
36+
$this->l10nFactory = $factory;
37+
}
38+
39+
public function prepare(INotification $notification, $languageCode): INotification {
40+
if($notification->getApp() !== 'core') {
41+
throw new \InvalidArgumentException();
42+
}
43+
$l = $this->l10nFactory->get('core', $languageCode);
44+
45+
if ($notification->getSubject() === 'repair_exposing_links') {
46+
$notification->setParsedSubject($l->t('Some of your link shares have been removed'));
47+
$notification->setParsedMessage($l->t('Due to a security bug we had to remove some of your link shares. Please see the link for more information.'));
48+
$notification->setLink('https://nextcloud.com/security/advisory/?id=NC-SA-2019-003');
49+
return $notification;
50+
}
51+
52+
throw new \InvalidArgumentException('Invalid subject');
53+
}
54+
55+
}

lib/composer/composer/autoload_classmap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@
711711
'OC\\Core\\Migrations\\Version15000Date20181029084625' => $baseDir . '/core/Migrations/Version15000Date20181029084625.php',
712712
'OC\\Core\\Migrations\\Version16000Date20190207141427' => $baseDir . '/core/Migrations/Version16000Date20190207141427.php',
713713
'OC\\Core\\Migrations\\Version16000Date20190212081545' => $baseDir . '/core/Migrations/Version16000Date20190212081545.php',
714+
'OC\\Core\\Notification\\RemoveLinkSharesNotifier' => $baseDir . '/core/Notification/RemoveLinkSharesNotifier.php',
714715
'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php',
715716
'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php',
716717
'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php',
@@ -1018,6 +1019,7 @@
10181019
'OC\\Repair\\OldGroupMembershipShares' => $baseDir . '/lib/private/Repair/OldGroupMembershipShares.php',
10191020
'OC\\Repair\\Owncloud\\DropAccountTermsTable' => $baseDir . '/lib/private/Repair/Owncloud/DropAccountTermsTable.php',
10201021
'OC\\Repair\\Owncloud\\SaveAccountsTableData' => $baseDir . '/lib/private/Repair/Owncloud/SaveAccountsTableData.php',
1022+
'OC\\Repair\\RemoveLinkShares' => $baseDir . '/lib/private/Repair/RemoveLinkShares.php',
10211023
'OC\\Repair\\RemoveRootShares' => $baseDir . '/lib/private/Repair/RemoveRootShares.php',
10221024
'OC\\Repair\\RepairInvalidShares' => $baseDir . '/lib/private/Repair/RepairInvalidShares.php',
10231025
'OC\\Repair\\RepairMimeTypes' => $baseDir . '/lib/private/Repair/RepairMimeTypes.php',

lib/composer/composer/autoload_static.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
741741
'OC\\Core\\Migrations\\Version15000Date20181029084625' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20181029084625.php',
742742
'OC\\Core\\Migrations\\Version16000Date20190207141427' => __DIR__ . '/../../..' . '/core/Migrations/Version16000Date20190207141427.php',
743743
'OC\\Core\\Migrations\\Version16000Date20190212081545' => __DIR__ . '/../../..' . '/core/Migrations/Version16000Date20190212081545.php',
744+
'OC\\Core\\Notification\\RemoveLinkSharesNotifier' => __DIR__ . '/../../..' . '/core/Notification/RemoveLinkSharesNotifier.php',
744745
'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php',
745746
'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php',
746747
'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php',
@@ -1048,6 +1049,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
10481049
'OC\\Repair\\OldGroupMembershipShares' => __DIR__ . '/../../..' . '/lib/private/Repair/OldGroupMembershipShares.php',
10491050
'OC\\Repair\\Owncloud\\DropAccountTermsTable' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/DropAccountTermsTable.php',
10501051
'OC\\Repair\\Owncloud\\SaveAccountsTableData' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/SaveAccountsTableData.php',
1052+
'OC\\Repair\\RemoveLinkShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveLinkShares.php',
10511053
'OC\\Repair\\RemoveRootShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveRootShares.php',
10521054
'OC\\Repair\\RepairInvalidShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairInvalidShares.php',
10531055
'OC\\Repair\\RepairMimeTypes' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairMimeTypes.php',

lib/private/Repair.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,15 @@
4848
use OC\Repair\OldGroupMembershipShares;
4949
use OC\Repair\Owncloud\DropAccountTermsTable;
5050
use OC\Repair\Owncloud\SaveAccountsTableData;
51+
use OC\Repair\RemoveLinkShares;
5152
use OC\Repair\RemoveRootShares;
5253
use OC\Repair\RepairInvalidShares;
5354
use OC\Repair\RepairMimeTypes;
5455
use OC\Repair\SqliteAutoincrement;
5556
use OC\Template\JSCombiner;
5657
use OC\Template\SCSSCacher;
5758
use OCP\AppFramework\QueryException;
59+
use OCP\AppFramework\Utility\ITimeFactory;
5860
use OCP\Migration\IOutput;
5961
use OCP\Migration\IRepairStep;
6062
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -152,6 +154,7 @@ public static function getRepairSteps() {
152154
new SetVcardDatabaseUID(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig(), \OC::$server->getLogger()),
153155
new CleanupCardDAVPhotoCache(\OC::$server->getConfig(), \OC::$server->getAppDataDir('dav-photocache'), \OC::$server->getLogger()),
154156
new AddClenupLoginFlowV2BackgroundJob(\OC::$server->getJobList()),
157+
new RemoveLinkShares(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig(), \OC::$server->getGroupManager(), \OC::$server->getNotificationManager(), \OC::$server->query(ITimeFactory::class)),
155158
];
156159
}
157160

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
<?php
2+
declare(strict_types=1);
3+
/**
4+
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
5+
*
6+
* @author Roeland Jago Douma <roeland@famdouma.nl>
7+
*
8+
* @license GNU AGPL version 3 or any later version
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU Affero General Public License as
12+
* published by the Free Software Foundation, either version 3 of the
13+
* License, or (at your option) any later version.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU Affero General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU Affero General Public License
21+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22+
*
23+
*/
24+
25+
namespace OC\Repair;
26+
27+
use Doctrine\DBAL\Driver\Statement;
28+
use OCP\AppFramework\Utility\ITimeFactory;
29+
use OCP\IConfig;
30+
use OCP\IDBConnection;
31+
use OCP\IGroupManager;
32+
use OCP\Migration\IOutput;
33+
use OCP\Migration\IRepairStep;
34+
use OCP\Notification\IManager;
35+
36+
class RemoveLinkShares implements IRepairStep {
37+
/** @var IDBConnection */
38+
private $connection;
39+
/** @var IConfig */
40+
private $config;
41+
/** @var string[] */
42+
private $userToNotify = [];
43+
/** @var IGroupManager */
44+
private $groupManager;
45+
/** @var IManager */
46+
private $notificationManager;
47+
/** @var ITimeFactory */
48+
private $timeFactory;
49+
50+
public function __construct(IDBConnection $connection,
51+
IConfig $config,
52+
IGroupManager $groupManager,
53+
IManager $notificationManager,
54+
ITimeFactory $timeFactory) {
55+
$this->connection = $connection;
56+
$this->config = $config;
57+
$this->groupManager = $groupManager;
58+
$this->notificationManager = $notificationManager;
59+
$this->timeFactory = $timeFactory;
60+
}
61+
62+
63+
public function getName(): string {
64+
return 'Remove potentially over exposing share links';
65+
}
66+
67+
private function shouldRun(): bool {
68+
$versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
69+
70+
if (version_compare($versionFromBeforeUpdate, '14.0.11', '<')) {
71+
return true;
72+
}
73+
if (version_compare($versionFromBeforeUpdate, '15.0.8', '<')) {
74+
return true;
75+
}
76+
if (version_compare($versionFromBeforeUpdate, '16.0.0', '<=')) {
77+
return true;
78+
}
79+
80+
return false;
81+
}
82+
83+
/**
84+
* Delete the share
85+
*
86+
* @param int $id
87+
*/
88+
private function deleteShare(int $id) {
89+
$qb = $this->connection->getQueryBuilder();
90+
$qb->delete('share')
91+
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
92+
$qb->execute();
93+
}
94+
95+
/**
96+
* Get the total of affected shares
97+
*
98+
* @return int
99+
*/
100+
private function getTotal(): int {
101+
$sql = 'SELECT COUNT(*) AS `total`
102+
FROM `*PREFIX*share`
103+
WHERE `id` IN (
104+
SELECT `s1`.`id`
105+
FROM (
106+
SELECT *
107+
FROM `*PREFIX*share`
108+
WHERE `parent` IS NOT NULL
109+
AND `share_type` = 3
110+
) AS s1
111+
JOIN `*PREFIX*share` AS s2
112+
ON `s1`.`parent` = `s2`.`id`
113+
WHERE (`s2`.`share_type` = 1 OR `s2`.`share_type` = 2)
114+
AND `s1`.`item_source` = `s2`.`item_source`
115+
)';
116+
$cursor = $this->connection->executeQuery($sql);
117+
$data = $cursor->fetchAll();
118+
$total = (int)$data[0]['total'];
119+
$cursor->closeCursor();
120+
121+
return $total;
122+
}
123+
124+
/**
125+
* Get the cursor to fetch all the shares
126+
*
127+
* @return \Doctrine\DBAL\Driver\Statement
128+
*/
129+
private function getShares(): Statement {
130+
$sql = 'SELECT `s1`.`id`, `s1`.`uid_owner`, `s1`.`uid_initiator`
131+
FROM (
132+
SELECT *
133+
FROM `*PREFIX*share`
134+
WHERE `parent` IS NOT NULL
135+
AND `share_type` = 3
136+
) AS s1
137+
JOIN `*PREFIX*share` AS s2
138+
ON `s1`.`parent` = `s2`.`id`
139+
WHERE (`s2`.`share_type` = 1 OR `s2`.`share_type` = 2)
140+
AND `s1`.`item_source` = `s2`.`item_source`';
141+
$cursor = $this->connection->executeQuery($sql);
142+
return $cursor;
143+
}
144+
145+
/**
146+
* Process a single share
147+
*
148+
* @param array $data
149+
*/
150+
private function processShare(array $data) {
151+
$id = $data['id'];
152+
153+
$this->addToNotify($data['uid_owner']);
154+
$this->addToNotify($data['uid_initiator']);
155+
156+
$this->deleteShare((int)$id);
157+
}
158+
159+
/**
160+
* Update list of users to notify
161+
*
162+
* @param string $uid
163+
*/
164+
private function addToNotify(string $uid) {
165+
if (!isset($this->userToNotify[$uid])) {
166+
$this->userToNotify[$uid] = true;
167+
}
168+
}
169+
170+
/**
171+
* Send all notifications
172+
*/
173+
private function sendNotification() {
174+
$time = $this->timeFactory->getDateTime();
175+
176+
$notification = $this->notificationManager->createNotification();
177+
$notification->setApp('core')
178+
->setDateTime($time)
179+
->setObject('repair', 'exposing_links')
180+
->setSubject('repair_exposing_links', []);
181+
182+
$users = array_keys($this->userToNotify);
183+
foreach ($users as $user) {
184+
$notification->setUser($user);
185+
$this->notificationManager->notify($notification);
186+
}
187+
}
188+
189+
private function repair(IOutput $output) {
190+
$total = $this->getTotal();
191+
$output->startProgress($total);
192+
193+
$shareCursor = $this->getShares();
194+
while($data = $shareCursor->fetch()) {
195+
$this->processShare($data);
196+
$output->advance();
197+
}
198+
$output->finishProgress();
199+
$shareCursor->closeCursor();
200+
201+
// Notifiy all admins
202+
$adminGroup = $this->groupManager->get('admin');
203+
$adminUsers = $adminGroup->getUsers();
204+
foreach ($adminUsers as $user) {
205+
$this->addToNotify($user->getUID());
206+
}
207+
208+
$output->info('Sending notifications to admins and affected users');
209+
$this->sendNotification();
210+
}
211+
212+
public function run(IOutput $output) {
213+
if ($this->shouldRun()) {
214+
$output->info('Removing potentially over exposing link shares');
215+
$this->repair($output);
216+
$output->info('Removed potentially over exposing link shares');
217+
} else {
218+
$output->info('No need to remove link shares.');
219+
}
220+
}
221+
}

version.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
3030
// when updating major/minor version number.
3131

32-
$OC_Version = array(17, 0, 0, 0);
32+
$OC_Version = array(17, 0, 0, 1);
3333

3434
// The human readable string
3535
$OC_VersionString = '17.0.0 alpha';

0 commit comments

Comments
 (0)