diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2023-12-11 11:02:21 +0100 |
---|---|---|
committer | backportbot-nextcloud[bot] <backportbot-nextcloud[bot]@users.noreply.github.com> | 2023-12-11 17:28:42 +0000 |
commit | 4757d3ed7d9487f04d45d51bac192022084e8fca (patch) | |
tree | 476b4dd9a69f56cabc12622156491496464e20fa /apps/dav/tests | |
parent | 12bafe16d5635fe340bde43eb47f1d877f5b92c5 (diff) | |
download | nextcloud-server-4757d3ed7d9487f04d45d51bac192022084e8fca.tar.gz nextcloud-server-4757d3ed7d9487f04d45d51bac192022084e8fca.zip |
fix(dav): Prevent out-of-office event time drifts
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'apps/dav/tests')
-rw-r--r-- | apps/dav/tests/unit/Listener/OutOfOfficeListenerTest.php | 88 |
1 files changed, 82 insertions, 6 deletions
diff --git a/apps/dav/tests/unit/Listener/OutOfOfficeListenerTest.php b/apps/dav/tests/unit/Listener/OutOfOfficeListenerTest.php index 919cf0a9ccf..7d13dd22f69 100644 --- a/apps/dav/tests/unit/Listener/OutOfOfficeListenerTest.php +++ b/apps/dav/tests/unit/Listener/OutOfOfficeListenerTest.php @@ -25,11 +25,14 @@ declare(strict_types=1); namespace OCA\DAV\Tests\Unit\Listener; +use DateTimeImmutable; +use InvalidArgumentException; use OCA\DAV\CalDAV\Calendar; use OCA\DAV\CalDAV\CalendarHome; use OCA\DAV\CalDAV\CalendarObject; use OCA\DAV\CalDAV\InvitationResponse\InvitationResponseServer; use OCA\DAV\CalDAV\Plugin; +use OCA\DAV\CalDAV\TimezoneService; use OCA\DAV\Connector\Sabre\Server; use OCA\DAV\Listener\OutOfOfficeListener; use OCA\DAV\ServerFactory; @@ -45,6 +48,9 @@ use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Tree; +use Sabre\VObject\Component\VCalendar; +use Sabre\VObject\Component\VEvent; +use Sabre\VObject\Reader; use Test\TestCase; /** @@ -55,20 +61,23 @@ class OutOfOfficeListenerTest extends TestCase { private ServerFactory|MockObject $serverFactory; private IConfig|MockObject $appConfig; private LoggerInterface|MockObject $loggerInterface; - private OutOfOfficeListener $listener; + private MockObject|TimezoneService $timezoneService; private IManager|MockObject $manager; + private OutOfOfficeListener $listener; protected function setUp(): void { parent::setUp(); $this->serverFactory = $this->createMock(ServerFactory::class); $this->appConfig = $this->createMock(IConfig::class); + $this->timezoneService = $this->createMock(TimezoneService::class); $this->loggerInterface = $this->createMock(LoggerInterface::class); $this->manager = $this->createMock(IManager::class); $this->listener = new OutOfOfficeListener( $this->serverFactory, $this->appConfig, + $this->timezoneService, $this->loggerInterface, $this->manager ); @@ -166,11 +175,15 @@ class OutOfOfficeListenerTest extends TestCase { $this->listener->handle($event); } - public function testHandleScheduling(): void { + public function testHandleSchedulingWithDefaultTimezone(): void { $user = $this->createMock(IUser::class); $user->method('getUID')->willReturn('user123'); $data = $this->createMock(IOutOfOfficeData::class); $data->method('getUser')->willReturn($user); + $data->method('getStartDate') + ->willReturn((new DateTimeImmutable('2023-12-12T00:00:00Z'))->getTimestamp()); + $data->method('getEndDate') + ->willReturn((new DateTimeImmutable('2023-12-13T00:00:00Z'))->getTimestamp()); $davServer = $this->createMock(Server::class); $invitationServer = $this->createMock(InvitationResponseServer::class); $invitationServer->method('getServer')->willReturn($davServer); @@ -195,12 +208,28 @@ class OutOfOfficeListenerTest extends TestCase { ->with('user123', 'dav', 'defaultCalendar', 'personal') ->willReturn('personal-1'); $calendar = $this->createMock(Calendar::class); + $this->timezoneService->expects(self::once()) + ->method('getUserTimezone') + ->with('user123') + ->willReturn('Europe/Prague'); $calendarHome->expects(self::once()) ->method('getChild') ->with('personal-1') ->willReturn($calendar); $calendar->expects(self::once()) - ->method('createFile'); + ->method('createFile') + ->willReturnCallback(function ($name, $data) { + $vcalendar = Reader::read($data); + if (!($vcalendar instanceof VCalendar)) { + throw new InvalidArgumentException('Calendar data should be a VCALENDAR'); + } + $vevent = $vcalendar->VEVENT; + if ($vevent === null || !($vevent instanceof VEvent)) { + throw new InvalidArgumentException('Calendar data should contain a VEVENT'); + } + self::assertSame('Europe/Prague', $vevent->DTSTART['TZID']?->getValue()); + self::assertSame('Europe/Prague', $vevent->DTEND['TZID']?->getValue()); + }); $event = new OutOfOfficeScheduledEvent($data); $this->listener->handle($event); @@ -295,6 +324,10 @@ class OutOfOfficeListenerTest extends TestCase { $user->method('getUID')->willReturn('user123'); $data = $this->createMock(IOutOfOfficeData::class); $data->method('getUser')->willReturn($user); + $data->method('getStartDate') + ->willReturn((new DateTimeImmutable('2023-12-12T00:00:00Z'))->getTimestamp()); + $data->method('getEndDate') + ->willReturn((new DateTimeImmutable('2023-12-14T00:00:00Z'))->getTimestamp()); $davServer = $this->createMock(Server::class); $invitationServer = $this->createMock(InvitationResponseServer::class); $invitationServer->method('getServer')->willReturn($davServer); @@ -319,6 +352,13 @@ class OutOfOfficeListenerTest extends TestCase { ->with('user123', 'dav', 'defaultCalendar', 'personal') ->willReturn('personal-1'); $calendar = $this->createMock(Calendar::class); + $this->timezoneService->expects(self::once()) + ->method('getUserTimezone') + ->with('user123') + ->willReturn(null); + $this->timezoneService->expects(self::once()) + ->method('getDefaultTimezone') + ->willReturn('Europe/Berlin'); $calendarHome->expects(self::once()) ->method('getChild') ->with('personal-1') @@ -327,17 +367,33 @@ class OutOfOfficeListenerTest extends TestCase { ->method('getChild') ->willThrowException(new NotFound()); $calendar->expects(self::once()) - ->method('createFile'); + ->method('createFile') + ->willReturnCallback(function ($name, $data) { + $vcalendar = Reader::read($data); + if (!($vcalendar instanceof VCalendar)) { + throw new InvalidArgumentException('Calendar data should be a VCALENDAR'); + } + $vevent = $vcalendar->VEVENT; + if ($vevent === null || !($vevent instanceof VEvent)) { + throw new InvalidArgumentException('Calendar data should contain a VEVENT'); + } + self::assertSame('Europe/Berlin', $vevent->DTSTART['TZID']?->getValue()); + self::assertSame('Europe/Berlin', $vevent->DTEND['TZID']?->getValue()); + }); $event = new OutOfOfficeChangedEvent($data); $this->listener->handle($event); } - public function testHandleChange(): void { + public function testHandleChangeWithoutTimezone(): void { $user = $this->createMock(IUser::class); $user->method('getUID')->willReturn('user123'); $data = $this->createMock(IOutOfOfficeData::class); $data->method('getUser')->willReturn($user); + $data->method('getStartDate') + ->willReturn((new DateTimeImmutable('2023-01-12T00:00:00Z'))->getTimestamp()); + $data->method('getEndDate') + ->willReturn((new DateTimeImmutable('2023-12-14T00:00:00Z'))->getTimestamp()); $davServer = $this->createMock(Server::class); $invitationServer = $this->createMock(InvitationResponseServer::class); $invitationServer->method('getServer')->willReturn($davServer); @@ -367,11 +423,31 @@ class OutOfOfficeListenerTest extends TestCase { ->with('personal-1') ->willReturn($calendar); $eventNode = $this->createMock(CalendarObject::class); + $this->timezoneService->expects(self::once()) + ->method('getUserTimezone') + ->with('user123') + ->willReturn(null); + $this->timezoneService->expects(self::once()) + ->method('getDefaultTimezone') + ->willReturn('UTC'); $calendar->expects(self::once()) ->method('getChild') ->willReturn($eventNode); $eventNode->expects(self::once()) - ->method('put'); + ->method('put') + ->willReturnCallback(function ($data) { + $vcalendar = Reader::read($data); + if (!($vcalendar instanceof VCalendar)) { + throw new InvalidArgumentException('Calendar data should be a VCALENDAR'); + } + $vevent = $vcalendar->VEVENT; + if ($vevent === null || !($vevent instanceof VEvent)) { + throw new InvalidArgumentException('Calendar data should contain a VEVENT'); + } + // UTC datetimes are stored without a TZID + self::assertSame(null, $vevent->DTSTART['TZID']?->getValue()); + self::assertSame(null, $vevent->DTEND['TZID']?->getValue()); + }); $calendar->expects(self::never()) ->method('createFile'); $event = new OutOfOfficeChangedEvent($data); |