Skip to content

Commit f088b94

Browse files
authored
Merge pull request #26125 from nextcloud/backport/25533/stable20
[stable20] send share notification instead of erroring on duplicate share
2 parents 97d9b3f + 797645b commit f088b94

4 files changed

Lines changed: 121 additions & 63 deletions

File tree

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@
468468
'OCP\\Share' => $baseDir . '/lib/public/Share.php',
469469
'OCP\\Share\\Events\\ShareCreatedEvent' => $baseDir . '/lib/public/Share/Events/ShareCreatedEvent.php',
470470
'OCP\\Share\\Events\\VerifyMountPointEvent' => $baseDir . '/lib/public/Share/Events/VerifyMountPointEvent.php',
471+
'OCP\\Share\\Exceptions\\AlreadySharedException' => $baseDir . '/lib/public/Share/Exceptions/AlreadySharedException.php',
471472
'OCP\\Share\\Exceptions\\GenericShareException' => $baseDir . '/lib/public/Share/Exceptions/GenericShareException.php',
472473
'OCP\\Share\\Exceptions\\IllegalIDChangeException' => $baseDir . '/lib/public/Share/Exceptions/IllegalIDChangeException.php',
473474
'OCP\\Share\\Exceptions\\ShareNotFound' => $baseDir . '/lib/public/Share/Exceptions/ShareNotFound.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
497497
'OCP\\Share' => __DIR__ . '/../../..' . '/lib/public/Share.php',
498498
'OCP\\Share\\Events\\ShareCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareCreatedEvent.php',
499499
'OCP\\Share\\Events\\VerifyMountPointEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/VerifyMountPointEvent.php',
500+
'OCP\\Share\\Exceptions\\AlreadySharedException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/AlreadySharedException.php',
500501
'OCP\\Share\\Exceptions\\GenericShareException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/GenericShareException.php',
501502
'OCP\\Share\\Exceptions\\IllegalIDChangeException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/IllegalIDChangeException.php',
502503
'OCP\\Share\\Exceptions\\ShareNotFound' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/ShareNotFound.php',

lib/private/Share20/Manager.php

Lines changed: 69 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
use OCP\Security\IHasher;
6464
use OCP\Security\ISecureRandom;
6565
use OCP\Share;
66+
use OCP\Share\Exceptions\AlreadySharedException;
6667
use OCP\Share\Exceptions\GenericShareException;
6768
use OCP\Share\Exceptions\ShareNotFound;
6869
use OCP\Share\IManager;
@@ -564,7 +565,7 @@ protected function userCreateChecks(IShare $share) {
564565

565566
// Identical share already existst
566567
if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
567-
throw new \Exception('Path is already shared with this user');
568+
throw new AlreadySharedException('Path is already shared with this user', $existingShare);
568569
}
569570

570571
// The share is already shared with this user via a group share
@@ -574,7 +575,7 @@ protected function userCreateChecks(IShare $share) {
574575
$user = $this->userManager->get($share->getSharedWith());
575576

576577
if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
577-
throw new \Exception('Path is already shared with this user');
578+
throw new AlreadySharedException('Path is already shared with this user', $existingShare);
578579
}
579580
}
580581
}
@@ -619,7 +620,7 @@ protected function groupCreateChecks(IShare $share) {
619620
}
620621

621622
if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
622-
throw new \Exception('Path is already shared with this group');
623+
throw new AlreadySharedException('Path is already shared with this group', $existingShare);
623624
}
624625
}
625626
}
@@ -733,77 +734,82 @@ public function createShare(IShare $share) {
733734
}
734735
}
735736

736-
//Verify share type
737-
if ($share->getShareType() === IShare::TYPE_USER) {
738-
$this->userCreateChecks($share);
739-
740-
//Verify the expiration date
741-
$share = $this->validateExpirationDateInternal($share);
742-
} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
743-
$this->groupCreateChecks($share);
737+
try {
738+
//Verify share type
739+
if ($share->getShareType() === IShare::TYPE_USER) {
740+
$this->userCreateChecks($share);
744741

745-
//Verify the expiration date
746-
$share = $this->validateExpirationDateInternal($share);
747-
} elseif ($share->getShareType() === IShare::TYPE_LINK) {
748-
$this->linkCreateChecks($share);
749-
$this->setLinkParent($share);
742+
//Verify the expiration date
743+
$share = $this->validateExpirationDateInternal($share);
744+
} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
745+
$this->groupCreateChecks($share);
750746

751-
/*
752-
* For now ignore a set token.
753-
*/
754-
$share->setToken(
755-
$this->secureRandom->generate(
756-
\OC\Share\Constants::TOKEN_LENGTH,
757-
\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
758-
)
759-
);
747+
//Verify the expiration date
748+
$share = $this->validateExpirationDateInternal($share);
749+
} elseif ($share->getShareType() === IShare::TYPE_LINK) {
750+
$this->linkCreateChecks($share);
751+
$this->setLinkParent($share);
752+
753+
/*
754+
* For now ignore a set token.
755+
*/
756+
$share->setToken(
757+
$this->secureRandom->generate(
758+
\OC\Share\Constants::TOKEN_LENGTH,
759+
\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
760+
)
761+
);
760762

761-
//Verify the expiration date
762-
$share = $this->validateExpirationDate($share);
763+
//Verify the expiration date
764+
$share = $this->validateExpirationDate($share);
763765

764-
//Verify the password
765-
$this->verifyPassword($share->getPassword());
766+
//Verify the password
767+
$this->verifyPassword($share->getPassword());
766768

767-
// If a password is set. Hash it!
768-
if ($share->getPassword() !== null) {
769-
$share->setPassword($this->hasher->hash($share->getPassword()));
769+
// If a password is set. Hash it!
770+
if ($share->getPassword() !== null) {
771+
$share->setPassword($this->hasher->hash($share->getPassword()));
772+
}
773+
} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
774+
$share->setToken(
775+
$this->secureRandom->generate(
776+
\OC\Share\Constants::TOKEN_LENGTH,
777+
\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
778+
)
779+
);
770780
}
771-
} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
772-
$share->setToken(
773-
$this->secureRandom->generate(
774-
\OC\Share\Constants::TOKEN_LENGTH,
775-
\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
776-
)
777-
);
778-
}
779781

780-
// Cannot share with the owner
781-
if ($share->getShareType() === IShare::TYPE_USER &&
782-
$share->getSharedWith() === $share->getShareOwner()) {
783-
throw new \InvalidArgumentException('Can’t share with the share owner');
784-
}
782+
// Cannot share with the owner
783+
if ($share->getShareType() === IShare::TYPE_USER &&
784+
$share->getSharedWith() === $share->getShareOwner()) {
785+
throw new \InvalidArgumentException('Can’t share with the share owner');
786+
}
785787

786-
// Generate the target
787-
$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
788-
$target = \OC\Files\Filesystem::normalizePath($target);
789-
$share->setTarget($target);
788+
// Generate the target
789+
$target = $this->config->getSystemValue('share_folder', '/') . '/' . $share->getNode()->getName();
790+
$target = \OC\Files\Filesystem::normalizePath($target);
791+
$share->setTarget($target);
790792

791-
// Pre share event
792-
$event = new GenericEvent($share);
793-
$this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
794-
if ($event->isPropagationStopped() && $event->hasArgument('error')) {
795-
throw new \Exception($event->getArgument('error'));
796-
}
793+
// Pre share event
794+
$event = new GenericEvent($share);
795+
$this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
796+
if ($event->isPropagationStopped() && $event->hasArgument('error')) {
797+
throw new \Exception($event->getArgument('error'));
798+
}
797799

798-
$oldShare = $share;
799-
$provider = $this->factory->getProviderForType($share->getShareType());
800-
$share = $provider->create($share);
801-
//reuse the node we already have
802-
$share->setNode($oldShare->getNode());
800+
$oldShare = $share;
801+
$provider = $this->factory->getProviderForType($share->getShareType());
802+
$share = $provider->create($share);
803+
//reuse the node we already have
804+
$share->setNode($oldShare->getNode());
803805

804-
// Reset the target if it is null for the new share
805-
if ($share->getTarget() === '') {
806-
$share->setTarget($target);
806+
// Reset the target if it is null for the new share
807+
if ($share->getTarget() === '') {
808+
$share->setTarget($target);
809+
}
810+
} catch (AlreadySharedException $e) {
811+
// if a share for the same target already exists, dont create a new one, but do trigger the hooks and notifications again
812+
$share = $e->getExistingShare();
807813
}
808814

809815
// Post share event
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2021 Robin Appelman <robin@icewind.nl>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
namespace OCP\Share\Exceptions;
25+
26+
use OCP\Share\IShare;
27+
28+
/**
29+
* @since 22.0.0
30+
*/
31+
class AlreadySharedException extends GenericShareException {
32+
/** @var IShare */
33+
private $existingShare;
34+
35+
/**
36+
* @since 22.0.0
37+
*/
38+
public function __construct(string $message, IShare $existingShare) {
39+
parent::__construct($message);
40+
41+
$this->existingShare = $existingShare;
42+
}
43+
44+
/**
45+
* @since 22.0.0
46+
*/
47+
public function getExistingShare(): IShare {
48+
return $this->existingShare;
49+
}
50+
}

0 commit comments

Comments
 (0)