Merge pull request #45667 from nextcloud/fix/caldav/strict-default-calendar-checks
fix(caldav): stricter default calendar checkspull/46685/head
commit
e54d39b076
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\CalDAV;
|
||||
|
||||
use Sabre\DAV\Exception as DavException;
|
||||
|
||||
class DefaultCalendarValidator {
|
||||
/**
|
||||
* Check if a given Calendar node is suitable to be used as the default calendar for scheduling.
|
||||
*
|
||||
* @throws DavException If the calendar is not suitable to be used as the default calendar
|
||||
*/
|
||||
public function validateScheduleDefaultCalendar(Calendar $calendar): void {
|
||||
// Sanity checks for a calendar that should handle invitations
|
||||
if ($calendar->isSubscription()
|
||||
|| !$calendar->canWrite()
|
||||
|| $calendar->isShared()
|
||||
|| $calendar->isDeleted()) {
|
||||
throw new DavException('Calendar is a subscription, not writable, shared or deleted');
|
||||
}
|
||||
|
||||
// Calendar must support VEVENTs
|
||||
$sCCS = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
|
||||
$calendarProperties = $calendar->getProperties([$sCCS]);
|
||||
if (isset($calendarProperties[$sCCS])) {
|
||||
$supportedComponents = $calendarProperties[$sCCS]->getValue();
|
||||
} else {
|
||||
$supportedComponents = ['VJOURNAL', 'VTODO', 'VEVENT'];
|
||||
}
|
||||
if (!in_array('VEVENT', $supportedComponents, true)) {
|
||||
throw new DavException('Calendar does not support VEVENT components');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\Tests\unit\CalDAV;
|
||||
|
||||
use OCA\DAV\CalDAV\Calendar;
|
||||
use OCA\DAV\CalDAV\DefaultCalendarValidator;
|
||||
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
|
||||
use Test\TestCase;
|
||||
|
||||
class DefaultCalendarValidatorTest extends TestCase {
|
||||
private DefaultCalendarValidator $validator;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->validator = new DefaultCalendarValidator();
|
||||
}
|
||||
|
||||
public function testValidateScheduleDefaultCalendar(): void {
|
||||
$node = $this->createMock(Calendar::class);
|
||||
$node->expects(self::once())
|
||||
->method('isSubscription')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('canWrite')
|
||||
->willReturn(true);
|
||||
$node->expects(self::once())
|
||||
->method('isShared')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('isDeleted')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('getProperties')
|
||||
->willReturn([
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VEVENT']),
|
||||
]);
|
||||
|
||||
$this->validator->validateScheduleDefaultCalendar($node);
|
||||
}
|
||||
|
||||
public function testValidateScheduleDefaultCalendarWithEmptyProperties(): void {
|
||||
$node = $this->createMock(Calendar::class);
|
||||
$node->expects(self::once())
|
||||
->method('isSubscription')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('canWrite')
|
||||
->willReturn(true);
|
||||
$node->expects(self::once())
|
||||
->method('isShared')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('isDeleted')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('getProperties')
|
||||
->willReturn([]);
|
||||
|
||||
$this->validator->validateScheduleDefaultCalendar($node);
|
||||
}
|
||||
|
||||
public function testValidateScheduleDefaultCalendarWithSubscription(): void {
|
||||
$node = $this->createMock(Calendar::class);
|
||||
$node->expects(self::once())
|
||||
->method('isSubscription')
|
||||
->willReturn(true);
|
||||
$node->expects(self::never())
|
||||
->method('canWrite');
|
||||
$node->expects(self::never())
|
||||
->method('isShared');
|
||||
$node->expects(self::never())
|
||||
->method('isDeleted');
|
||||
$node->expects(self::never())
|
||||
->method('getProperties');
|
||||
|
||||
$this->expectException(\Sabre\DAV\Exception::class);
|
||||
$this->validator->validateScheduleDefaultCalendar($node);
|
||||
}
|
||||
|
||||
public function testValidateScheduleDefaultCalendarWithoutWrite(): void {
|
||||
$node = $this->createMock(Calendar::class);
|
||||
$node->expects(self::once())
|
||||
->method('isSubscription')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('canWrite')
|
||||
->willReturn(false);
|
||||
$node->expects(self::never())
|
||||
->method('isShared');
|
||||
$node->expects(self::never())
|
||||
->method('isDeleted');
|
||||
$node->expects(self::never())
|
||||
->method('getProperties');
|
||||
|
||||
$this->expectException(\Sabre\DAV\Exception::class);
|
||||
$this->validator->validateScheduleDefaultCalendar($node);
|
||||
}
|
||||
|
||||
public function testValidateScheduleDefaultCalendarWithShared(): void {
|
||||
$node = $this->createMock(Calendar::class);
|
||||
$node->expects(self::once())
|
||||
->method('isSubscription')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('canWrite')
|
||||
->willReturn(true);
|
||||
$node->expects(self::once())
|
||||
->method('isShared')
|
||||
->willReturn(true);
|
||||
$node->expects(self::never())
|
||||
->method('isDeleted');
|
||||
$node->expects(self::never())
|
||||
->method('getProperties');
|
||||
|
||||
$this->expectException(\Sabre\DAV\Exception::class);
|
||||
$this->validator->validateScheduleDefaultCalendar($node);
|
||||
}
|
||||
|
||||
public function testValidateScheduleDefaultCalendarWithDeleted(): void {
|
||||
$node = $this->createMock(Calendar::class);
|
||||
$node->expects(self::once())
|
||||
->method('isSubscription')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('canWrite')
|
||||
->willReturn(true);
|
||||
$node->expects(self::once())
|
||||
->method('isShared')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('isDeleted')
|
||||
->willReturn(true);
|
||||
$node->expects(self::never())
|
||||
->method('getProperties');
|
||||
|
||||
$this->expectException(\Sabre\DAV\Exception::class);
|
||||
$this->validator->validateScheduleDefaultCalendar($node);
|
||||
}
|
||||
|
||||
public function testValidateScheduleDefaultCalendarWithoutVeventSupport(): void {
|
||||
$node = $this->createMock(Calendar::class);
|
||||
$node->expects(self::once())
|
||||
->method('isSubscription')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('canWrite')
|
||||
->willReturn(true);
|
||||
$node->expects(self::once())
|
||||
->method('isShared')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('isDeleted')
|
||||
->willReturn(false);
|
||||
$node->expects(self::once())
|
||||
->method('getProperties')
|
||||
->willReturn([
|
||||
'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new SupportedCalendarComponentSet(['VTODO']),
|
||||
]);
|
||||
|
||||
$this->expectException(\Sabre\DAV\Exception::class);
|
||||
$this->validator->validateScheduleDefaultCalendar($node);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue