Skip to content

Commit d9d4f1e

Browse files
st3inyAndyScherzinger
authored andcommitted
fix(caldav): encode calendar URIs with umlauts for activities
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
1 parent 3b7172b commit d9d4f1e

File tree

2 files changed

+62
-8
lines changed

2 files changed

+62
-8
lines changed

apps/dav/lib/CalDAV/Activity/Provider/Event.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,15 @@ protected function generateObjectParameter(array $eventData, string $affectedUse
9797
// The calendar app needs to be manually loaded for the routes to be loaded
9898
OC_App::loadApp('calendar');
9999
$linkData = $eventData['link'];
100+
$calendarUri = $this->urlencodeLowerHex($linkData['calendar_uri']);
100101
if ($affectedUser === $linkData['owner']) {
101-
$objectId = base64_encode($this->url->getWebroot() . '/remote.php/dav/calendars/' . $linkData['owner'] . '/' . $linkData['calendar_uri'] . '/' . $linkData['object_uri']);
102+
$objectId = base64_encode($this->url->getWebroot() . '/remote.php/dav/calendars/' . $linkData['owner'] . '/' . $calendarUri . '/' . $linkData['object_uri']);
102103
} else {
103104
// Can't use the "real" owner and calendar names here because we create a custom
104105
// calendar for incoming shares with the name "<calendar>_shared_by_<sharer>".
105106
// Hack: Fix the link by generating it for the incoming shared calendar instead,
106107
// as seen from the affected user.
107-
$objectId = base64_encode($this->url->getWebroot() . '/remote.php/dav/calendars/' . $affectedUser . '/' . $linkData['calendar_uri'] . '_shared_by_' . $linkData['owner'] . '/' . $linkData['object_uri']);
108+
$objectId = base64_encode($this->url->getWebroot() . '/remote.php/dav/calendars/' . $affectedUser . '/' . $calendarUri . '_shared_by_' . $linkData['owner'] . '/' . $linkData['object_uri']);
108109
}
109110
$link = [
110111
'view' => 'dayGridMonth',
@@ -262,4 +263,16 @@ private function generateClassifiedObjectParameter(array $eventData, string $aff
262263
}
263264
return $parameter;
264265
}
266+
267+
/**
268+
* Return urlencoded string but with lower cased hex sequences.
269+
* The remaining casing will be untouched.
270+
*/
271+
private function urlencodeLowerHex(string $raw): string {
272+
return preg_replace_callback(
273+
'/%[0-9A-F]{2}/',
274+
static fn (array $matches) => strtolower($matches[0]),
275+
urlencode($raw),
276+
);
277+
}
265278
}

apps/dav/tests/unit/CalDAV/Activity/Provider/EventTest.php

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,17 +146,58 @@ public function testGenerateObjectParameter(int $id, string $name, ?array $link,
146146
$this->assertEquals($result, $this->invokePrivate($this->provider, 'generateObjectParameter', [$objectParameter, $affectedUser]));
147147
}
148148

149-
public function testGenerateObjectParameterWithSharedCalendar(): void {
150-
$link = [
151-
'object_uri' => 'someuuid.ics',
152-
'calendar_uri' => 'personal',
153-
'owner' => 'sharer'
149+
public static function generateObjectParameterLinkEncodingDataProvider(): array {
150+
return [
151+
[ // Shared calendar
152+
[
153+
'object_uri' => 'someuuid.ics',
154+
'calendar_uri' => 'personal',
155+
'owner' => 'sharer'
156+
],
157+
base64_encode('/remote.php/dav/calendars/sharee/personal_shared_by_sharer/someuuid.ics'),
158+
],
159+
[ // Shared calendar with umlauts
160+
[
161+
'object_uri' => 'someuuid.ics',
162+
'calendar_uri' => 'umlaut_äüöß',
163+
'owner' => 'sharer'
164+
],
165+
base64_encode('/remote.php/dav/calendars/sharee/umlaut_%c3%a4%c3%bc%c3%b6%c3%9f_shared_by_sharer/someuuid.ics'),
166+
],
167+
[ // Shared calendar with umlauts and mixed casing
168+
[
169+
'object_uri' => 'someuuid.ics',
170+
'calendar_uri' => 'Umlaut_äüöß',
171+
'owner' => 'sharer'
172+
],
173+
base64_encode('/remote.php/dav/calendars/sharee/Umlaut_%c3%a4%c3%bc%c3%b6%c3%9f_shared_by_sharer/someuuid.ics'),
174+
],
175+
[ // Owned calendar with umlauts
176+
[
177+
'object_uri' => 'someuuid.ics',
178+
'calendar_uri' => 'umlaut_äüöß',
179+
'owner' => 'sharee'
180+
],
181+
base64_encode('/remote.php/dav/calendars/sharee/umlaut_%c3%a4%c3%bc%c3%b6%c3%9f/someuuid.ics'),
182+
],
183+
[ // Owned calendar with umlauts and mixed casing
184+
[
185+
'object_uri' => 'someuuid.ics',
186+
'calendar_uri' => 'Umlaut_äüöß',
187+
'owner' => 'sharee'
188+
],
189+
base64_encode('/remote.php/dav/calendars/sharee/Umlaut_%c3%a4%c3%bc%c3%b6%c3%9f/someuuid.ics'),
190+
],
154191
];
192+
}
193+
194+
/** @dataProvider generateObjectParameterLinkEncodingDataProvider */
195+
public function testGenerateObjectParameterLinkEncoding(array $link, string $objectId): void {
155196
$generatedLink = [
156197
'view' => 'dayGridMonth',
157198
'timeRange' => 'now',
158199
'mode' => 'sidebar',
159-
'objectId' => base64_encode('/remote.php/dav/calendars/sharee/' . $link['calendar_uri'] . '_shared_by_sharer/' . $link['object_uri']),
200+
'objectId' => $objectId,
160201
'recurrenceId' => 'next'
161202
];
162203
$this->appManager->expects($this->once())

0 commit comments

Comments
 (0)