mirror of
https://github.com/nextcloud/server.git
synced 2026-06-17 12:42:50 -04:00
fix(caldav): respect federation settings
Signed-off-by: Hamza <hamzamahjoubi221@gmail.com>
This commit is contained in:
parent
64f8a02b93
commit
4fe03d470b
6 changed files with 218 additions and 5 deletions
|
|
@ -9,15 +9,36 @@ declare(strict_types=1);
|
|||
|
||||
namespace OCA\DAV\CalDAV\Federation;
|
||||
|
||||
use OCP\AppFramework\Services\IAppConfig;
|
||||
use OCP\IAppConfig;
|
||||
|
||||
class CalendarFederationConfig {
|
||||
public function __construct(
|
||||
private readonly IAppConfig $appConfig,
|
||||
private \OCP\GlobalScale\IConfig $gsConfig,
|
||||
) {
|
||||
}
|
||||
|
||||
public function isFederationEnabled(): bool {
|
||||
return $this->appConfig->getAppValueBool('enableCalendarFederation', true);
|
||||
return $this->appConfig->getValueBool('dav', 'enableCalendarFederation', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if users are allowed to create federated shares
|
||||
*/
|
||||
public function isOutgoingServer2serverShareEnabled(): bool {
|
||||
if ($this->gsConfig->onlyInternalFederation()) {
|
||||
return false;
|
||||
}
|
||||
return $this->appConfig->getValueBool('files_sharing', 'outgoing_server2server_share_enabled', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if users are allowed to receive federated shares
|
||||
*/
|
||||
public function isIncomingServer2serverShareEnabled(): bool {
|
||||
if ($this->gsConfig->onlyInternalFederation()) {
|
||||
return false;
|
||||
}
|
||||
return $this->appConfig->getValueBool('files_sharing', 'incoming_server2server_share_enabled', true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,15 @@ class CalendarFederationProvider implements ICloudFederationProvider {
|
|||
);
|
||||
}
|
||||
|
||||
if (!$this->calendarFederationConfig->isIncomingServer2serverShareEnabled()) {
|
||||
$this->logger->debug('Received a federated calendar share which is not allowed on this instance');
|
||||
throw new ProviderCouldNotAddShareException(
|
||||
'Instance does not support receiving federated calendar shares',
|
||||
'',
|
||||
Http::STATUS_SERVICE_UNAVAILABLE,
|
||||
);
|
||||
}
|
||||
|
||||
if (!in_array($share->getShareType(), $this->getSupportedShareTypes(), true)) {
|
||||
$this->logger->debug('Received a federation invite for invalid share type');
|
||||
throw new ProviderCouldNotAddShareException(
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class FederationSharingService {
|
|||
private readonly LoggerInterface $logger,
|
||||
private readonly ISecureRandom $random,
|
||||
private readonly SharingMapper $sharingMapper,
|
||||
private readonly CalendarFederationConfig $config,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -70,6 +71,14 @@ class FederationSharingService {
|
|||
public function shareWith(IShareable $shareable, string $principal, int $access): void {
|
||||
$baseError = 'Failed to create federated calendar share: ';
|
||||
|
||||
if (!$this->config->isOutgoingServer2serverShareEnabled()) {
|
||||
$this->logger->error('cannot share with remote user because federated sharing is disabled on this instance', [
|
||||
'shareable' => $shareable->getName(),
|
||||
'encodedShareWith' => $principal,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Validate share data
|
||||
$shareWith = $this->decodeRemoteUserPrincipal($principal);
|
||||
if ($shareWith === null) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ declare(strict_types=1);
|
|||
namespace OCA\DAV\Tests\unit\CalDAV\Federation;
|
||||
|
||||
use OCA\DAV\CalDAV\Federation\CalendarFederationConfig;
|
||||
use OCP\AppFramework\Services\IAppConfig;
|
||||
use OCP\GlobalScale\IConfig;
|
||||
use OCP\IAppConfig;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Test\TestCase;
|
||||
|
|
@ -19,14 +20,17 @@ class CalendarFederationConfigTest extends TestCase {
|
|||
private CalendarFederationConfig $config;
|
||||
|
||||
private IAppConfig&MockObject $appConfig;
|
||||
private IConfig&MockObject $gsConfig;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->appConfig = $this->createMock(IAppConfig::class);
|
||||
$this->gsConfig = $this->createMock(IConfig::class);
|
||||
|
||||
$this->config = new CalendarFederationConfig(
|
||||
$this->appConfig,
|
||||
$this->gsConfig,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -40,10 +44,74 @@ class CalendarFederationConfigTest extends TestCase {
|
|||
#[DataProvider(methodName: 'provideIsFederationEnabledData')]
|
||||
public function testIsFederationEnabled(bool $configValue): void {
|
||||
$this->appConfig->expects(self::once())
|
||||
->method('getAppValueBool')
|
||||
->with('enableCalendarFederation', true)
|
||||
->method('getValueBool')
|
||||
->with('dav', 'enableCalendarFederation', true)
|
||||
->willReturn($configValue);
|
||||
|
||||
$this->assertEquals($configValue, $this->config->isFederationEnabled());
|
||||
}
|
||||
|
||||
public static function provideIsOutgoingServer2serverShareEnabledData(): array {
|
||||
return [
|
||||
[false, false, false],
|
||||
[false, true, true],
|
||||
[true, false, false],
|
||||
[true, false, false],
|
||||
];
|
||||
}
|
||||
|
||||
#[DataProvider(methodName: 'provideIsOutgoingServer2serverShareEnabledData')]
|
||||
public function testIsOutgoingServer2serverShareEnabled(
|
||||
bool $globalScaleEnabled,
|
||||
bool $expected,
|
||||
bool $configValue,
|
||||
): void {
|
||||
$this->gsConfig->expects(self::once())
|
||||
->method('onlyInternalFederation')
|
||||
->willReturn($globalScaleEnabled);
|
||||
|
||||
if (!$globalScaleEnabled) {
|
||||
$this->appConfig->expects(self::once())
|
||||
->method('getValueBool')
|
||||
->with('files_sharing', 'outgoing_server2server_share_enabled', true)
|
||||
->willReturn($configValue);
|
||||
} else {
|
||||
$this->appConfig->expects(self::never())
|
||||
->method('getValueBool');
|
||||
}
|
||||
|
||||
$this->assertEquals($expected, $this->config->isOutgoingServer2serverShareEnabled());
|
||||
}
|
||||
|
||||
public static function provideIsIncomingServer2serverShareEnabledData(): array {
|
||||
return [
|
||||
[false, false, false],
|
||||
[false, true, true],
|
||||
[true, false, false],
|
||||
[true, false, true],
|
||||
];
|
||||
}
|
||||
|
||||
#[DataProvider(methodName: 'provideIsIncomingServer2serverShareEnabledData')]
|
||||
public function testIsIncomingServer2serverShareEnabled(
|
||||
bool $globalScaleEnabled,
|
||||
bool $expected,
|
||||
bool $configValue,
|
||||
): void {
|
||||
$this->gsConfig->expects(self::once())
|
||||
->method('onlyInternalFederation')
|
||||
->willReturn($globalScaleEnabled);
|
||||
|
||||
if (!$globalScaleEnabled) {
|
||||
$this->appConfig->expects(self::once())
|
||||
->method('getValueBool')
|
||||
->with('files_sharing', 'incoming_server2server_share_enabled', true)
|
||||
->willReturn($configValue);
|
||||
} else {
|
||||
$this->appConfig->expects(self::never())
|
||||
->method('getValueBool');
|
||||
}
|
||||
|
||||
$this->assertEquals($expected, $this->config->isIncomingServer2serverShareEnabled());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->federatedCalendarMapper->expects(self::once())
|
||||
->method('findByUri')
|
||||
->with(
|
||||
|
|
@ -150,6 +154,10 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$existingCalendar = new FederatedCalendarEntity();
|
||||
$existingCalendar->setId(10);
|
||||
$existingCalendar->setPrincipaluri('principals/users/sharee1');
|
||||
|
|
@ -204,6 +212,10 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->federatedCalendarMapper->expects(self::never())
|
||||
->method('insert');
|
||||
$this->jobList->expects(self::never())
|
||||
|
|
@ -232,6 +244,10 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->federatedCalendarMapper->expects(self::never())
|
||||
->method('insert');
|
||||
$this->jobList->expects(self::never())
|
||||
|
|
@ -261,6 +277,30 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
$this->calendarFederationProvider->shareReceived($share);
|
||||
}
|
||||
|
||||
public function testShareReceivedWithIncomingServer2serverShareDisabled(): void {
|
||||
$share = $this->createMock(ICloudFederationShare::class);
|
||||
$share->method('getShareType')
|
||||
->willReturn('user');
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(false);
|
||||
|
||||
$this->federatedCalendarMapper->expects(self::never())
|
||||
->method('insert');
|
||||
$this->jobList->expects(self::never())
|
||||
->method('add');
|
||||
|
||||
$this->expectException(ProviderCouldNotAddShareException::class);
|
||||
$this->expectExceptionMessage('Instance does not support receiving federated calendar shares');
|
||||
$this->expectExceptionCode(503);
|
||||
$this->calendarFederationProvider->shareReceived($share);
|
||||
}
|
||||
|
||||
public function testShareReceivedWithUnsupportedShareType(): void {
|
||||
$share = $this->createMock(ICloudFederationShare::class);
|
||||
$share->method('getShareType')
|
||||
|
|
@ -270,6 +310,10 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->federatedCalendarMapper->expects(self::never())
|
||||
->method('insert');
|
||||
$this->jobList->expects(self::never())
|
||||
|
|
@ -322,6 +366,10 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->federatedCalendarMapper->expects(self::never())
|
||||
->method('insert');
|
||||
$this->jobList->expects(self::never())
|
||||
|
|
@ -359,6 +407,10 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->federatedCalendarMapper->expects(self::once())
|
||||
->method('findByUri')
|
||||
->with(
|
||||
|
|
@ -418,6 +470,10 @@ class CalendarFederationProviderTest extends TestCase {
|
|||
->method('isFederationEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->calendarFederationConfig->expects(self::once())
|
||||
->method('isIncomingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->federatedCalendarMapper->expects(self::never())
|
||||
->method('insert');
|
||||
$this->jobList->expects(self::never())
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace OCA\DAV\Tests\unit\CalDAV\Federation;
|
||||
|
||||
use OCA\DAV\CalDAV\Calendar;
|
||||
use OCA\DAV\CalDAV\Federation\CalendarFederationConfig;
|
||||
use OCA\DAV\CalDAV\Federation\FederationSharingService;
|
||||
use OCA\DAV\DAV\Sharing\IShareable;
|
||||
use OCA\DAV\DAV\Sharing\SharingMapper;
|
||||
|
|
@ -38,6 +39,7 @@ class FederationSharingServiceTest extends TestCase {
|
|||
private readonly LoggerInterface&MockObject $logger;
|
||||
private readonly ISecureRandom&MockObject $random;
|
||||
private readonly SharingMapper&MockObject $sharingMapper;
|
||||
private readonly CalendarFederationConfig&MockObject $config;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
|
@ -49,6 +51,7 @@ class FederationSharingServiceTest extends TestCase {
|
|||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->random = $this->createMock(ISecureRandom::class);
|
||||
$this->sharingMapper = $this->createMock(SharingMapper::class);
|
||||
$this->config = $this->createMock(CalendarFederationConfig::class);
|
||||
|
||||
$this->federationSharingService = new FederationSharingService(
|
||||
$this->federationManager,
|
||||
|
|
@ -58,6 +61,7 @@ class FederationSharingServiceTest extends TestCase {
|
|||
$this->logger,
|
||||
$this->random,
|
||||
$this->sharingMapper,
|
||||
$this->config,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +87,10 @@ class FederationSharingServiceTest extends TestCase {
|
|||
]
|
||||
});
|
||||
|
||||
$this->config->expects(self::once())
|
||||
->method('isOutgoingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$hostUser = $this->createMock(IUser::class);
|
||||
$hostUser->method('getCloudId')
|
||||
->willReturn('host1@nextcloud.host');
|
||||
|
|
@ -195,6 +203,10 @@ class FederationSharingServiceTest extends TestCase {
|
|||
]
|
||||
});
|
||||
|
||||
$this->config->expects(self::once())
|
||||
->method('isOutgoingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$hostUser = $this->createMock(IUser::class);
|
||||
$hostUser->method('getCloudId')
|
||||
->willReturn('host1@nextcloud.host');
|
||||
|
|
@ -299,6 +311,10 @@ class FederationSharingServiceTest extends TestCase {
|
|||
]
|
||||
});
|
||||
|
||||
$this->config->expects(self::once())
|
||||
->method('isOutgoingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$hostUser = $this->createMock(IUser::class);
|
||||
$hostUser->method('getCloudId')
|
||||
->willReturn('host1@nextcloud.host');
|
||||
|
|
@ -381,6 +397,34 @@ class FederationSharingServiceTest extends TestCase {
|
|||
);
|
||||
}
|
||||
|
||||
public function testShareWithWithOutgoingServer2serverShareDisabled(): void {
|
||||
$shareable = $this->createMock(Calendar::class);
|
||||
$shareable->method('getOwner')
|
||||
->willReturn('principals/users/host1');
|
||||
$shareable->method('getName')
|
||||
->willReturn('cal1');
|
||||
|
||||
$this->config->expects(self::once())
|
||||
->method('isOutgoingServer2serverShareEnabled')
|
||||
->willReturn(false);
|
||||
|
||||
$this->userManager->expects(self::never())
|
||||
->method('get');
|
||||
|
||||
$this->federationManager->expects(self::never())
|
||||
->method('sendCloudShare');
|
||||
$this->sharingMapper->expects(self::never())
|
||||
->method('deleteShare');
|
||||
$this->sharingMapper->expects(self::never())
|
||||
->method('shareWithToken');
|
||||
|
||||
$this->federationSharingService->shareWith(
|
||||
$shareable,
|
||||
'principals/remote-users/cmVtb3RlMUBuZXh0Y2xvdWQucmVtb3Rl',
|
||||
3, // Read-only
|
||||
);
|
||||
}
|
||||
|
||||
public static function provideInvalidRemoteUserPrincipalData(): array {
|
||||
return [
|
||||
['principals/users/foobar'],
|
||||
|
|
@ -418,6 +462,9 @@ class FederationSharingServiceTest extends TestCase {
|
|||
$shareable->method('getOwner')
|
||||
->willReturn('principals/users/host1');
|
||||
|
||||
$this->config->method('isOutgoingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->userManager->expects(self::once())
|
||||
->method('get')
|
||||
->with('host1')
|
||||
|
|
@ -442,6 +489,9 @@ class FederationSharingServiceTest extends TestCase {
|
|||
$shareable->method('getOwner')
|
||||
->willReturn('principals/users/host1');
|
||||
|
||||
$this->config->method('isOutgoingServer2serverShareEnabled')
|
||||
->willReturn(true);
|
||||
|
||||
$this->userManager->expects(self::once())
|
||||
->method('get')
|
||||
->with('host1')
|
||||
|
|
|
|||
Loading…
Reference in a new issue