diff --git a/lib/Listeners/Files/CreatingShareSendMail.php b/lib/Listeners/Files/CreatingShareSendMail.php index 18e7e00e3..9d53d20b7 100644 --- a/lib/Listeners/Files/CreatingShareSendMail.php +++ b/lib/Listeners/Files/CreatingShareSendMail.php @@ -101,6 +101,7 @@ public function handle(Event $event): void { } $circle = $event->getCircle(); + $federatedEvent = $event->getFederatedEvent(); $result = []; @@ -116,10 +117,12 @@ public function handle(Event $event): void { /** @var ShareWrapper $share */ $share = $federatedEvent->getParams()->gObj('wrappedShare', ShareWrapper::class); $this->shareWrapperService->getShareById((int)$share->getId()); + // we confirm share is not spoofed by the main instance of the Circle if ($share->getSharedWith() !== $circle->getSingleId()) { throw new ShareWrapperNotFoundException(); } + $shareToken = $this->shareTokenService->generateShareToken($share, $member); $share->setShareToken($shareToken); } catch (Exception $e) { diff --git a/lib/Listeners/Files/ShareCreatedSendMail.php b/lib/Listeners/Files/ShareCreatedSendMail.php index 17e1f21d5..92649fa61 100644 --- a/lib/Listeners/Files/ShareCreatedSendMail.php +++ b/lib/Listeners/Files/ShareCreatedSendMail.php @@ -36,6 +36,12 @@ use Exception; use OCA\Circles\AppInfo\Application; use OCA\Circles\Events\Files\FileShareCreatedEvent; +use OCA\Circles\Exceptions\FederatedItemException; +use OCA\Circles\Exceptions\RemoteInstanceException; +use OCA\Circles\Exceptions\RemoteNotFoundException; +use OCA\Circles\Exceptions\RemoteResourceNotFoundException; +use OCA\Circles\Exceptions\RequestBuilderException; +use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\Model\Member; use OCA\Circles\Model\ShareWrapper; use OCA\Circles\Service\ConfigService; @@ -100,6 +106,13 @@ public function __construct( /** * @param Event $event + * + * @throws FederatedItemException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws UnknownRemoteException */ public function handle(Event $event): void { if (!$event instanceof FileShareCreatedEvent) { @@ -108,7 +121,7 @@ public function handle(Event $event): void { $circle = $event->getCircle(); - foreach ($circle->getInheritedMembers() as $member) { + foreach ($circle->getInheritedMembers(false, false) as $member) { if ($member->getUserType() !== Member::TYPE_MAIL && $member->getUserType() !== Member::TYPE_CONTACT) { continue; @@ -123,6 +136,8 @@ public function handle(Event $event): void { } $data = $shares->gData($member->getId()); + + // TODO: this must be run even if there is no shares, and only if the $origin === $member->getInstance() and its aliases $mails = array_merge($mails, $data->gArray('mails')); // TODO: is it safe to use $origin to compare getInstance() ? diff --git a/lib/Model/Circle.php b/lib/Model/Circle.php index d9b20dc31..fe5cdb169 100644 --- a/lib/Model/Circle.php +++ b/lib/Model/Circle.php @@ -39,7 +39,13 @@ use DateTime; use JsonSerializable; use OCA\Circles\Exceptions\CircleNotFoundException; +use OCA\Circles\Exceptions\FederatedItemException; use OCA\Circles\Exceptions\OwnerNotFoundException; +use OCA\Circles\Exceptions\RemoteInstanceException; +use OCA\Circles\Exceptions\RemoteNotFoundException; +use OCA\Circles\Exceptions\RemoteResourceNotFoundException; +use OCA\Circles\Exceptions\RequestBuilderException; +use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\IMemberships; /** @@ -456,16 +462,55 @@ public function setInheritedMembers(array $members, bool $detailed): IMembership } /** + * @param array $members + * + * @return IMemberships + */ + public function addInheritedMembers(array $members): IMemberships { + $knownIds = array_map( + function (Member $member): string { + return $member->getId(); + }, $this->inheritedMembers + ); + + foreach ($members as $member) { + if (!array_key_exists($member->getId(), $knownIds)) { + $this->inheritedMembers[] = $member; + $knownIds[] = $member->getId(); + } + } + + return $this; + } + + + /** + * if $remote is true, it will returns also details on inherited members from remote+locals Circles. + * This should be used only if extra details are required (mail address ?) as it will send a request to + * the remote instance if the circleId is not locally known. + * because of the resource needed to retrieve this data, $remote=true should not be used on main process ! + * * @param bool $detailed + * @param bool $remote * * @return Member[] - */ - public function getInheritedMembers(bool $detailed = false): array { + * @throws FederatedItemException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws UnknownRemoteException + */ + public function getInheritedMembers(bool $detailed = false, bool $remote = false): array { if (is_null($this->inheritedMembers) || ($detailed && !$this->detailedInheritedMember)) { $this->getManager()->getInheritedMembers($this, $detailed); } + if ($remote) { + $this->getManager()->getRemoteInheritedMembers($this, $detailed); + } + return $this->inheritedMembers; } diff --git a/lib/Model/ModelManager.php b/lib/Model/ModelManager.php index 9a36771ed..697ec4ccc 100644 --- a/lib/Model/ModelManager.php +++ b/lib/Model/ModelManager.php @@ -31,24 +31,33 @@ namespace OCA\Circles\Model; +use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Logger; +use OCA\Circles\AppInfo\Application; +use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\CoreQueryBuilder; use OCA\Circles\Db\MemberRequest; use OCA\Circles\Db\MembershipRequest; use OCA\Circles\Exceptions\CircleNotFoundException; +use OCA\Circles\Exceptions\FederatedItemException; use OCA\Circles\Exceptions\FederatedUserNotFoundException; use OCA\Circles\Exceptions\FileCacheNotFoundException; use OCA\Circles\Exceptions\MemberNotFoundException; use OCA\Circles\Exceptions\MembershipNotFoundException; use OCA\Circles\Exceptions\OwnerNotFoundException; +use OCA\Circles\Exceptions\RemoteInstanceException; use OCA\Circles\Exceptions\RemoteNotFoundException; +use OCA\Circles\Exceptions\RemoteResourceNotFoundException; use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\UnknownInterfaceException; +use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\IMemberships; use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\InterfaceService; +use OCA\Circles\Service\RemoteService; use OCP\IURLGenerator; + /** * Class ModelManager * @@ -57,12 +66,18 @@ class ModelManager { + use TNC22Logger; + + /** @var IURLGenerator */ private $urlGenerator; /** @var CoreQueryBuilder */ private $coreRequestBuilder; + /** @var CircleRequest */ + private $circleRequest; + /** @var MemberRequest */ private $memberRequest; @@ -72,6 +87,9 @@ class ModelManager { /** @var InterfaceService */ private $interfaceService; + /** @var RemoteService */ + private $remoteService; + /** @var ConfigService */ private $configService; @@ -85,25 +103,33 @@ class ModelManager { * * @param IURLGenerator $urlGenerator * @param CoreQueryBuilder $coreRequestBuilder + * @param CircleRequest $circleRequest * @param MemberRequest $memberRequest * @param MembershipRequest $membershipRequest * @param InterfaceService $interfaceService + * @param RemoteService $remoteService * @param ConfigService $configService */ public function __construct( IURLGenerator $urlGenerator, CoreQueryBuilder $coreRequestBuilder, + CircleRequest $circleRequest, MemberRequest $memberRequest, MembershipRequest $membershipRequest, InterfaceService $interfaceService, + RemoteService $remoteService, ConfigService $configService ) { $this->urlGenerator = $urlGenerator; $this->coreRequestBuilder = $coreRequestBuilder; + $this->circleRequest = $circleRequest; $this->memberRequest = $memberRequest; $this->membershipRequest = $membershipRequest; $this->interfaceService = $interfaceService; + $this->remoteService = $remoteService; $this->configService = $configService; + + $this->setup('app', Application::APP_ID); } @@ -143,6 +169,36 @@ public function getInheritedMembers(Circle $circle, bool $detailed = false): voi } + /** + * @param Circle $circle + * @param bool $detailed + * + * @throws RemoteNotFoundException + * @throws RequestBuilderException + * @throws FederatedItemException + * @throws RemoteInstanceException + * @throws RemoteResourceNotFoundException + * @throws UnknownRemoteException + */ + public function getRemoteInheritedMembers(Circle $circle, bool $detailed = false): void { + foreach ($circle->getInheritedMembers() as $inherited) { + if ($inherited->getUserType() === Member::TYPE_CIRCLE + && !$this->configService->isLocalInstance($inherited->getInstance())) { + try { + $this->circleRequest->getCircle($inherited->getSingleId()); + } catch (CircleNotFoundException $e) { + $remote = $this->remoteService->getInheritedFromInstance( + $inherited->getSingleId(), + $inherited->getInstance() + ); + + $circle->addInheritedMembers($remote); + } + } + } + } + + /** * @param IMemberships $member */