mirror of
https://github.com/netzbegruenung/circles.git
synced 2024-04-29 02:14:51 +02:00
bypass/limit permissions
Signed-off-by: Maxence Lange <maxence@artificial-owl.com> Co-authored-by: Carl Schwan <carl@carlschwan.eu>
This commit is contained in:
parent
87725112af
commit
d6544d41e3
|
@ -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;
|
||||
|
|
|
@ -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 {
|
|||
|
||||
|
||||
/**
|
||||
* @throws FederatedUserNotFoundException
|
||||
* @throws InvalidIdException
|
||||
* @return void
|
||||
* @throws FederatedUserException
|
||||
* @throws SingleCircleNotFoundException
|
||||
* @throws RequestBuilderException
|
||||
* @throws FederatedUserNotFoundException
|
||||
* @throws FrontendException
|
||||
* @throws InvalidIdException
|
||||
* @throws RequestBuilderException
|
||||
* @throws SingleCircleNotFoundException
|
||||
*/
|
||||
private function setCurrentFederatedUser() {
|
||||
private function setCurrentFederatedUser(): void {
|
||||
if (!$this->configService->getAppValueBool(ConfigService::FRONTEND_ENABLED)) {
|
||||
throw new FrontendException('frontend disabled');
|
||||
}
|
||||
|
|
35
lib/Exceptions/InsufficientPermissionException.php
Normal file
35
lib/Exceptions/InsufficientPermissionException.php
Normal file
|
@ -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 {
|
||||
}
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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',
|
||||
|
|
184
lib/Service/PermissionService.php
Normal file
184
lib/Service/PermissionService.php
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ 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 OCP\AppFramework\Http\DataResponse;
|
||||
|
@ -69,6 +70,9 @@ class LocalControllerTest extends TestCase {
|
|||
/** @var SearchService|MockObject */
|
||||
private $searchService;
|
||||
|
||||
/** @var PermissionService|MockObject */
|
||||
private $permissionService;
|
||||
|
||||
/** @var ConfigService|MockObject */
|
||||
private $configService;
|
||||
|
||||
|
@ -84,9 +88,19 @@ class LocalControllerTest extends TestCase {
|
|||
$this->memberService = $this->createMock(MemberService::class);
|
||||
$this->membershipService = $this->createMock(MembershipService::class);
|
||||
$this->searchService = $this->createMock(SearchService::class);
|
||||
$this->permissionService = $this->createMock(PermissionService::class);
|
||||
$this->configService = $this->createMock(ConfigService::class);
|
||||
$this->configService->expects($this->any())->method('getAppValueBool')->with(ConfigService::FRONTEND_ENABLED)->willReturn(true);
|
||||
$this->localController = new LocalController(Application::APP_ID, $this->request, $this->userSession, $this->federatedUserService, $this->circleService, $this->memberService, $this->membershipService, $this->searchService, $this->configService);
|
||||
$this->localController = new LocalController(Application::APP_ID,
|
||||
$this->request,
|
||||
$this->userSession,
|
||||
$this->federatedUserService,
|
||||
$this->circleService,
|
||||
$this->memberService,
|
||||
$this->membershipService,
|
||||
$this->permissionService,
|
||||
$this->searchService,
|
||||
$this->configService);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue