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

github.com/nextcloud/circles.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMaxence Lange <maxence@artificial-owl.com>2022-04-04 15:11:47 +0300
committerMaxence Lange <maxence@artificial-owl.com>2022-04-06 18:56:45 +0300
commitd6544d41e3e2ad5d3157003c2c8f662b73c43b00 (patch)
tree2f83f9f9df86cf6ebbcb2fe51d3920015d0319fe /lib
parent87725112afc2bfd679ac46a687446e080d443e20 (diff)
bypass/limit permissions
Signed-off-by: Maxence Lange <maxence@artificial-owl.com> Co-authored-by: Carl Schwan <carl@carlschwan.eu>
Diffstat (limited to 'lib')
-rw-r--r--lib/Command/CirclesConfig.php8
-rw-r--r--lib/Controller/LocalController.php20
-rw-r--r--lib/Exceptions/InsufficientPermissionException.php35
-rw-r--r--lib/FederatedItems/CircleConfig.php16
-rw-r--r--lib/Model/Member.php6
-rw-r--r--lib/Service/CircleService.php8
-rw-r--r--lib/Service/ConfigService.php7
-rw-r--r--lib/Service/PermissionService.php184
8 files changed, 273 insertions, 11 deletions
diff --git a/lib/Command/CirclesConfig.php b/lib/Command/CirclesConfig.php
index 5a823db3..68ecfa42 100644
--- a/lib/Command/CirclesConfig.php
+++ b/lib/Command/CirclesConfig.php
@@ -172,6 +172,14 @@ class CirclesConfig extends Base {
if (strtolower($input->getOption('output')) === 'json') {
$output->writeln(json_encode($outcome, JSON_PRETTY_PRINT));
+ } elseif (strtolower($input->getOption('output')) !== 'none') {
+ $circle = $this->circleService->getCircle($circleId);
+ $output->writeln(
+ json_encode(
+ Circle::getCircleFlags($circle, Circle::FLAGS_LONG),
+ JSON_PRETTY_PRINT
+ )
+ );
}
return 0;
diff --git a/lib/Controller/LocalController.php b/lib/Controller/LocalController.php
index efa78363..fa7a454e 100644
--- a/lib/Controller/LocalController.php
+++ b/lib/Controller/LocalController.php
@@ -31,8 +31,6 @@ declare(strict_types=1);
namespace OCA\Circles\Controller;
-use OCA\Circles\Tools\Traits\TDeserialize;
-use OCA\Circles\Tools\Traits\TNCLogger;
use Exception;
use OCA\Circles\Exceptions\FederatedUserException;
use OCA\Circles\Exceptions\FederatedUserNotFoundException;
@@ -49,7 +47,10 @@ use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\FederatedUserService;
use OCA\Circles\Service\MemberService;
use OCA\Circles\Service\MembershipService;
+use OCA\Circles\Service\PermissionService;
use OCA\Circles\Service\SearchService;
+use OCA\Circles\Tools\Traits\TDeserialize;
+use OCA\Circles\Tools\Traits\TNCLogger;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCSController;
@@ -81,6 +82,9 @@ class LocalController extends OcsController {
/** @var MembershipService */
private $membershipService;
+ /** @var PermissionService */
+ private $permissionService;
+
/** @var SearchService */
private $searchService;
@@ -109,6 +113,7 @@ class LocalController extends OcsController {
CircleService $circleService,
MemberService $memberService,
MembershipService $membershipService,
+ PermissionService $permissionService,
SearchService $searchService,
ConfigService $configService
) {
@@ -119,6 +124,7 @@ class LocalController extends OcsController {
$this->circleService = $circleService;
$this->memberService = $memberService;
$this->membershipService = $membershipService;
+ $this->permissionService = $permissionService;
$this->searchService = $searchService;
$this->configService = $configService;
@@ -139,6 +145,7 @@ class LocalController extends OcsController {
public function create(string $name, bool $personal = false, bool $local = false): DataResponse {
try {
$this->setCurrentFederatedUser();
+ $this->permissionService->confirmCircleCreation();
$circle = $this->circleService->create($name, null, $personal, $local);
@@ -572,14 +579,15 @@ class LocalController extends OcsController {
/**
+ * @return void
+ * @throws FederatedUserException
* @throws FederatedUserNotFoundException
+ * @throws FrontendException
* @throws InvalidIdException
- * @throws FederatedUserException
- * @throws SingleCircleNotFoundException
* @throws RequestBuilderException
- * @throws FrontendException
+ * @throws SingleCircleNotFoundException
*/
- private function setCurrentFederatedUser() {
+ private function setCurrentFederatedUser(): void {
if (!$this->configService->getAppValueBool(ConfigService::FRONTEND_ENABLED)) {
throw new FrontendException('frontend disabled');
}
diff --git a/lib/Exceptions/InsufficientPermissionException.php b/lib/Exceptions/InsufficientPermissionException.php
new file mode 100644
index 00000000..b3c07537
--- /dev/null
+++ b/lib/Exceptions/InsufficientPermissionException.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @copyright 2021
+ * @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\Circles\Exceptions;
+
+class InsufficientPermissionException extends FederatedItemForbiddenException {
+}
diff --git a/lib/FederatedItems/CircleConfig.php b/lib/FederatedItems/CircleConfig.php
index 522c0847..29339845 100644
--- a/lib/FederatedItems/CircleConfig.php
+++ b/lib/FederatedItems/CircleConfig.php
@@ -34,12 +34,14 @@ namespace OCA\Circles\FederatedItems;
use OCA\Circles\Db\CircleRequest;
use OCA\Circles\Exceptions\FederatedItemBadRequestException;
use OCA\Circles\Exceptions\FederatedItemException;
+use OCA\Circles\Exceptions\RequestBuilderException;
use OCA\Circles\IFederatedItem;
use OCA\Circles\IFederatedItemAsyncProcess;
use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Federated\FederatedEvent;
use OCA\Circles\Model\Helpers\MemberHelper;
use OCA\Circles\Service\ConfigService;
+use OCA\Circles\Service\PermissionService;
use OCA\Circles\Tools\Traits\TDeserialize;
/**
@@ -56,6 +58,9 @@ class CircleConfig implements
/** @var CircleRequest */
private $circleRequest;
+ /** @var PermissionService */
+ private $permissionService;
+
/** @var ConfigService */
private $configService;
@@ -64,10 +69,16 @@ class CircleConfig implements
* CircleConfig constructor.
*
* @param CircleRequest $circleRequest
+ * @param PermissionService $permissionService
* @param ConfigService $configService
*/
- public function __construct(CircleRequest $circleRequest, ConfigService $configService) {
+ public function __construct(
+ CircleRequest $circleRequest,
+ PermissionService $permissionService,
+ ConfigService $configService
+ ) {
$this->circleRequest = $circleRequest;
+ $this->permissionService = $permissionService;
$this->configService = $configService;
}
@@ -76,6 +87,7 @@ class CircleConfig implements
* @param FederatedEvent $event
*
* @throws FederatedItemException
+ * @throws RequestBuilderException
*/
public function verify(FederatedEvent $event): void {
$circle = $event->getCircle();
@@ -150,7 +162,7 @@ class CircleConfig implements
$new = clone $circle;
$new->setConfig($config);
- $this->configService->confirmAllowedCircleTypes($new);
+ $this->permissionService->confirmAllowedCircleTypes($new, $circle);
$event->getData()->sInt('config', $new->getConfig());
diff --git a/lib/Model/Member.php b/lib/Model/Member.php
index 35ce1b21..4dd420b8 100644
--- a/lib/Model/Member.php
+++ b/lib/Model/Member.php
@@ -738,8 +738,10 @@ class Member extends ManagedModel implements
* @throws RequestBuilderException
*/
public function getLink(string $singleId, bool $detailed = false): Membership {
- $this->getManager()->getLink($this, $singleId, $detailed);
-
+ if ($singleId !== '') {
+ $this->getManager()->getLink($this, $singleId, $detailed);
+ }
+
throw new MembershipNotFoundException();
}
diff --git a/lib/Service/CircleService.php b/lib/Service/CircleService.php
index bf33bc47..b5f2d967 100644
--- a/lib/Service/CircleService.php
+++ b/lib/Service/CircleService.php
@@ -101,6 +101,9 @@ class CircleService {
/** @var MemberService */
private $memberService;
+ /** @var PermissionService */
+ private $permissionService;
+
/** @var ConfigService */
private $configService;
@@ -114,6 +117,7 @@ class CircleService {
* @param FederatedUserService $federatedUserService
* @param FederatedEventService $federatedEventService
* @param MemberService $memberService
+ * @param PermissionService $permissionService
* @param ConfigService $configService
*/
public function __construct(
@@ -125,6 +129,7 @@ class CircleService {
FederatedUserService $federatedUserService,
FederatedEventService $federatedEventService,
MemberService $memberService,
+ PermissionService $permissionService,
ConfigService $configService
) {
$this->l10n = $l10n;
@@ -135,6 +140,7 @@ class CircleService {
$this->federatedUserService = $federatedUserService;
$this->federatedEventService = $federatedEventService;
$this->memberService = $memberService;
+ $this->permissionService = $permissionService;
$this->configService = $configService;
$this->setup('app', Application::APP_ID);
@@ -197,7 +203,7 @@ class CircleService {
}
$this->confirmName($circle);
- $this->configService->confirmAllowedCircleTypes($circle);
+ $this->permissionService->confirmAllowedCircleTypes($circle);
$member = new Member();
$member->importFromIFederatedUser($owner);
diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php
index 03315bd0..649c4c30 100644
--- a/lib/Service/ConfigService.php
+++ b/lib/Service/ConfigService.php
@@ -106,6 +106,10 @@ class ConfigService {
public const ALLOWED_TYPES = 'allowed_types';
public const CIRCLE_TYPES_FORCE = 'circle_types_force';
public const CIRCLE_TYPES_BLOCK = 'circle_types_block';
+
+ public const BYPASS_CIRCLE_TYPES = 'bypass_circle_types';
+ public const LIMIT_CIRCLE_CREATION = 'limit_circle_creation';
+
public const MIGRATION_BYPASS = 'migration_bypass';
public const MIGRATION_22 = 'migration_22';
public const MIGRATION_22_1 = 'migration_22_1';
@@ -183,6 +187,9 @@ class ConfigService {
self::CIRCLE_TYPES_FORCE => '0',
self::CIRCLE_TYPES_BLOCK => '0',
+ self::BYPASS_CIRCLE_TYPES => '',
+ self::LIMIT_CIRCLE_CREATION => '',
+
self::MIGRATION_BYPASS => '0',
self::MIGRATION_22 => '0',
self::MIGRATION_22_1 => '0',
diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php
new file mode 100644
index 00000000..81c8fbb9
--- /dev/null
+++ b/lib/Service/PermissionService.php
@@ -0,0 +1,184 @@
+<?php
+
+declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @copyright 2022
+ * @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\Circles\Service;
+
+use OCA\Circles\Exceptions\InitiatorNotFoundException;
+use OCA\Circles\Exceptions\InsufficientPermissionException;
+use OCA\Circles\Exceptions\MembershipNotFoundException;
+use OCA\Circles\Exceptions\RequestBuilderException;
+use OCA\Circles\Model\Circle;
+use OCP\IL10N;
+
+class PermissionService {
+
+
+ /** @var IL10N */
+ private $l10n;
+
+ /** @var FederatedUserService */
+ private $federatedUserService;
+
+ /** @var ConfigService */
+ private $configService;
+
+
+ /**
+ * @param IL10N $l10n
+ * @param FederatedUserService $federatedUserService
+ * @param ConfigService $configService
+ */
+ public function __construct(
+ IL10N $l10n,
+ FederatedUserService $federatedUserService,
+ ConfigService $configService
+ ) {
+ $this->l10n = $l10n;
+ $this->federatedUserService = $federatedUserService;
+ $this->configService = $configService;
+ }
+
+
+ /**
+ * @throws RequestBuilderException
+ * @throws InitiatorNotFoundException
+ * @throws InsufficientPermissionException
+ */
+ public function confirmCircleCreation(): void {
+ try {
+ $this->confirm(ConfigService::LIMIT_CIRCLE_CREATION);
+ } catch (InsufficientPermissionException $e) {
+ throw new InsufficientPermissionException(
+ $this->l10n->t('You have no permission to create a new circle')
+ );
+ }
+ }
+
+
+ /**
+ * @param string $config
+ *
+ * @throws InsufficientPermissionException
+ * @throws RequestBuilderException
+ * @throws InitiatorNotFoundException
+ */
+ private function confirm(string $config): void {
+ $singleId = $this->configService->getAppValue($config);
+ if ($singleId === '') {
+ return;
+ }
+
+ $this->federatedUserService->mustHaveCurrentUser();
+ $federatedUser = $this->federatedUserService->getCurrentUser();
+ try {
+ $federatedUser->getLink($singleId);
+ } catch (MembershipNotFoundException $e) {
+ throw new InsufficientPermissionException();
+ }
+ }
+
+
+ /**
+ * @param Circle $circle
+ *
+ * @return bool
+ * @throws RequestBuilderException
+ */
+ private function canBypassCircleTypes(Circle $circle): bool {
+ try {
+ if (!$circle->hasInitiator()) {
+ throw new MembershipNotFoundException();
+ }
+
+ $circle->getInitiator()->getLink(
+ $this->configService->getAppValue(ConfigService::BYPASS_CIRCLE_TYPES)
+ );
+
+ return true;
+ } catch (MembershipNotFoundException $e) {
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Enforce or Block circle's config/type
+ *
+ * @param Circle $circle
+ * @param Circle|null $previous
+ *
+ * @throws RequestBuilderException
+ */
+ public function confirmAllowedCircleTypes(Circle $circle, ?Circle $previous = null): void {
+ if ($this->canBypassCircleTypes($circle)) {
+ return;
+ }
+
+ $config = $circle->getConfig();
+ $force = $this->configService->getAppValueInt(ConfigService::CIRCLE_TYPES_FORCE);
+ $block = $this->configService->getAppValueInt(ConfigService::CIRCLE_TYPES_BLOCK);
+
+ if (is_null($previous)) {
+ $config |= $force;
+ $config &= ~$block;
+ } else {
+ // if we have a previous entry, we compare old and new config.
+ foreach (array_merge($this->extractBitwise($force), $this->extractBitwise($block)) as $bit) {
+ if ($previous->isConfig($bit)) {
+ $config |= $bit;
+ } else {
+ $config &= ~$bit;
+ }
+ }
+ }
+
+ $circle->setConfig($config);
+ }
+
+
+ /**
+ * @return int[]
+ */
+ private function extractBitwise(int $bitwise): array {
+ $values = [];
+ $b = 1;
+ while ($b <= $bitwise) {
+ if (($bitwise & $b) !== 0) {
+ $values[] = $b;
+ }
+
+ $b = $b << 1;
+ }
+
+ return $values;
+ }
+}