aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElmar Ludwig <elmar.ludwig@uni-osnabrueck.de>2026-02-27 14:50:39 +0100
committerElmar Ludwig <elmar.ludwig@uni-osnabrueck.de>2026-02-27 15:32:11 +0100
commit06de328b48d3d6e84cf07cac1c0be9cc5f4928c7 (patch)
tree495a15c9ec778294d4781d4f67bfdeab5f3e4e9f
parente4f38e0e8cdc2cdd1dce822ca62260df3f588446 (diff)
fix XSS issues with date formatting, fixes #6277
Closes #6277 Merge request studip/studip!4751
-rw-r--r--app/controllers/admin/courses.php7
-rw-r--r--app/controllers/course/block_appointments.php2
-rw-r--r--app/controllers/course/overview.php2
-rw-r--r--app/controllers/course/timesrooms.php22
-rw-r--r--app/controllers/tree.php2
-rw-r--r--app/views/course/overview/index.php4
-rw-r--r--app/views/course/room_requests/_new_request_header.php2
-rw-r--r--app/views/resources/_common/_request_info.php2
-rw-r--r--app/views/resources/_common/_request_tr.php2
-rw-r--r--app/views/resources/admin/global_locks.php2
-rw-r--r--app/views/resources/booking/add_from_request.php2
-rw-r--r--app/views/resources/room_request/planning.php2
-rw-r--r--app/views/resources/room_request/resolve.php2
-rw-r--r--lib/models/CourseDate.php6
-rw-r--r--lib/models/SeminarCycleDate.php28
-rw-r--r--lib/models/resources/ResourceRequest.php2
-rw-r--r--templates/dates/course_date_list.php22
-rw-r--r--templates/filesystem/topic_folder/description.php2
18 files changed, 67 insertions, 46 deletions
diff --git a/app/controllers/admin/courses.php b/app/controllers/admin/courses.php
index fb65f70..38ce72b 100644
--- a/app/controllers/admin/courses.php
+++ b/app/controllers/admin/courses.php
@@ -658,8 +658,7 @@ class Admin_CoursesController extends AuthenticatedController
$d['type'] = htmlReady($semtype['name']);
}
if (in_array('room_time', $activated_fields)) {
- $strings = $course->getAllDatesInSemester($this->semester)->toStringArray();
- $d['room_time'] = implode('<br>', $strings) ?: _('nicht angegeben');
+ $d['room_time'] = $course->getAllDatesInSemester($this->semester)->toHtml();
}
if (in_array('semester', $activated_fields)) {
$d['semester'] = htmlReady($course->semester_text);
@@ -1005,9 +1004,7 @@ class Admin_CoursesController extends AuthenticatedController
}
if (in_array('room_time', $filter_config)) {
- $dates = $course->getAllDatesInSemester($this->semester);
- $date_strings = $dates->toStringArray(true);
- $row['room_time'] = implode("\n", $date_strings) ?: _('nicht angegeben');
+ $row['room_time'] = (string) $course->getAllDatesInSemester($this->semester);
}
if (in_array('requests', $filter_config)) {
diff --git a/app/controllers/course/block_appointments.php b/app/controllers/course/block_appointments.php
index 88d7378..bc8d387 100644
--- a/app/controllers/course/block_appointments.php
+++ b/app/controllers/course/block_appointments.php
@@ -245,7 +245,7 @@ class Course_BlockAppointmentsController extends AuthenticatedController
$room = Resource::find(Request::option('room_id'))?->getDerivedClassInstance();
$d->bookRoom($room);
}
- return $result ? $d->getFullName() : null;
+ return $result ? htmlReady($d->getFullName()) : null;
}, $dates));
if ($date_count > 1) {
$dates_created = array_count_values($dates_created);
diff --git a/app/controllers/course/overview.php b/app/controllers/course/overview.php
index 4313cdc..f1aa52d 100644
--- a/app/controllers/course/overview.php
+++ b/app/controllers/course/overview.php
@@ -67,7 +67,7 @@ class Course_OverviewController extends AuthenticatedController
$this->next_date = $this->course->getNextDate();
$this->first_date = $this->course->getFirstDate();
$show_link = $GLOBALS["perm"]->have_studip_perm('autor', $this->course_id) && $this->course->isToolActive('schedule');
- $this->times_rooms = implode('<br>', $this->course->getAllDatesInSemester()->toStringArray());
+ $this->times_rooms = $this->course->getAllDatesInSemester()->toHtml();
//Load lecturers:
$lecturers = $this->course->getMembersWithStatus('dozent');
diff --git a/app/controllers/course/timesrooms.php b/app/controllers/course/timesrooms.php
index 8ee11ac..f196101 100644
--- a/app/controllers/course/timesrooms.php
+++ b/app/controllers/course/timesrooms.php
@@ -578,9 +578,9 @@ class Course_TimesroomsController extends AuthenticatedController
studip_interpolate(
_('Der Raum %{room_name} wird an dem Termin %{date} bereits durch die Veranstaltung %{course_name} belegt.'),
[
- 'room_name' => $room->name,
- 'date' => $termin->getFullName(),
- 'course_name' => $course->name
+ 'room_name' => htmlReady($room->name),
+ 'date' => htmlReady($termin->getFullName()),
+ 'course_name' => htmlReady($course->name)
]
),
$message_links
@@ -590,8 +590,8 @@ class Course_TimesroomsController extends AuthenticatedController
studip_interpolate(
_('Der Raum %{room_name} wird an dem Termin %{date} bereits anderweitig belegt.'),
[
- 'room_name' => $room->name,
- 'date' => $termin->getFullName()
+ 'room_name' => htmlReady($room->name),
+ 'date' => htmlReady($termin->getFullName())
]
),
$message_links
@@ -1144,7 +1144,7 @@ class Course_TimesroomsController extends AuthenticatedController
$error_messages[] = sprintf(
studip_interpolate(
_('%{date}: Die eingegebene Rüstzeit überschreitet das erlaubte Maximum von %d Minuten!'),
- ['date' => $singledate->getFullName()]
+ ['date' => htmlReady($singledate->getFullName())]
),
$max_preparation_time
);
@@ -1168,17 +1168,17 @@ class Course_TimesroomsController extends AuthenticatedController
$error_messages[] = studip_interpolate(
_('Der Raum %{room_name} wird an dem Termin %{date} bereits durch die Veranstaltung %{course_name} belegt.'),
[
- 'room_name' => $room->name,
- 'date' => $singledate->getFullName(),
- 'course_name' => $course->name
+ 'room_name' => htmlReady($room->name),
+ 'date' => htmlReady($singledate->getFullName()),
+ 'course_name' => htmlReady($course->name)
]
);
} else {
$error_messages[] = studip_interpolate(
_('Der Raum %{room_name} wird an dem Termin %{date} bereits anderweitig belegt.'),
[
- 'room_name' => $room->name,
- 'date' => $singledate->getFullName()
+ 'room_name' => htmlReady($room->name),
+ 'date' => htmlReady($singledate->getFullName())
]
);
}
diff --git a/app/controllers/tree.php b/app/controllers/tree.php
index 22135a5..9bde648 100644
--- a/app/controllers/tree.php
+++ b/app/controllers/tree.php
@@ -39,7 +39,7 @@ class TreeController extends AuthenticatedController
$course->veranstaltungsnummer,
$course->getFullName('type-number-name'),
$course->getTextualSemester(),
- strip_tags(implode("\n", $course->getAllDatesInSemester()->toStringArray())),
+ implode("\n", $course->getAllDatesInSemester()->toStringArray()),
implode(', ', $lecturers),
implode("\n", $studyAreaPaths)
];
diff --git a/app/views/course/overview/index.php b/app/views/course/overview/index.php
index 03fc848..fa14efd 100644
--- a/app/views/course/overview/index.php
+++ b/app/views/course/overview/index.php
@@ -17,12 +17,12 @@
</dd>
<? if ($next_date) : ?>
<dt><?= _('Nächster Termin') ?></dt>
- <dd><?= $next_date->getFullName('long') ?></dd>
+ <dd><?= htmlReady($next_date->getFullName('long')) ?></dd>
<? else : ?>
<dt><?= _('Erster Termin') ?></dt>
<dd>
<? if ($first_date) : ?>
- <?= $first_date->getFullName('long') ?>
+ <?= htmlReady($first_date->getFullName('long')) ?>
<? else : ?>
<?= _('Die Zeiten der Veranstaltung stehen nicht fest.') ?>
<? endif ?>
diff --git a/app/views/course/room_requests/_new_request_header.php b/app/views/course/room_requests/_new_request_header.php
index cd0d381..c63d8a8 100644
--- a/app/views/course/room_requests/_new_request_header.php
+++ b/app/views/course/room_requests/_new_request_header.php
@@ -7,7 +7,7 @@
<?
$dates = $request->getDateString(true);
?>
- <?= tooltipHtmlIcon(implode('<br>', $dates)) ?>
+ <?= tooltipHtmlIcon(implode('<br>', array_map('htmlReady', $dates))) ?>
<? endif ?>
</section>
</section>
diff --git a/app/views/resources/_common/_request_info.php b/app/views/resources/_common/_request_info.php
index 8a0c7b4..c698fad 100644
--- a/app/views/resources/_common/_request_info.php
+++ b/app/views/resources/_common/_request_info.php
@@ -5,7 +5,7 @@
?>
<dl>
<dt><?= _('Termine') ?>:</dt>
- <dd><?= $request->getDateString() ?></dd>
+ <dd><?= htmlReady($request->getDateString()) ?></dd>
<dt><?= !empty($timesrooms_page) ? _('Rüstzeit vor dem Termin') : _('Rüstzeit vor der Buchung') ?>:</dt>
<dd>
<? $preparation_time_minutes = intval($request->preparation_time / 60) ?>
diff --git a/app/views/resources/_common/_request_tr.php b/app/views/resources/_common/_request_tr.php
index 8f0510e..7c18ed1 100644
--- a/app/views/resources/_common/_request_tr.php
+++ b/app/views/resources/_common/_request_tr.php
@@ -49,7 +49,7 @@
</td>
<? $intervals = $request->getTimeIntervals() ?>
<td data-sort-value="<?= htmlReady(isset($intervals[0]) ? $intervals[0]['begin'] : '') ?>">
- <?= $request->getTypeString() ?>
+ <?= htmlReady($request->getTypeString()) ?>
<? if ($request->isSimpleRequest()): ?>
<?
$begin = $request->getStartDate();
diff --git a/app/views/resources/admin/global_locks.php b/app/views/resources/admin/global_locks.php
index ef6bccd..6f44630 100644
--- a/app/views/resources/admin/global_locks.php
+++ b/app/views/resources/admin/global_locks.php
@@ -13,7 +13,7 @@
<tr>
<td><?= date('d.m.Y H:i', $lock->begin) ?></td>
<td><?= date('d.m.Y H:i', $lock->end) ?></td>
- <td><?= $lock->getTypeString() ?></td>
+ <td><?= htmlReady($lock->getTypeString()) ?></td>
<td class="actions">
<?= ActionMenu::get()->setContext(
sprintf(
diff --git a/app/views/resources/booking/add_from_request.php b/app/views/resources/booking/add_from_request.php
index e7c3d37..f5b5573 100644
--- a/app/views/resources/booking/add_from_request.php
+++ b/app/views/resources/booking/add_from_request.php
@@ -12,7 +12,7 @@
<legend><?= _('Details zur Anfrage') ?></legend>
<h3><?= _('Angefragte Zeiträume')?></h3>
<ul>
- <? $appointments = explode("\n", $request->getDateString()) ?>
+ <? $appointments = $request->getDateString(true) ?>
<? foreach ($appointments as $appointment): ?>
<li><?= htmlReady($appointment) ?></li>
<? endforeach ?>
diff --git a/app/views/resources/room_request/planning.php b/app/views/resources/room_request/planning.php
index 1ad51fd..1d0fbc2 100644
--- a/app/views/resources/room_request/planning.php
+++ b/app/views/resources/room_request/planning.php
@@ -276,7 +276,7 @@
<? endif ?>
</td>
<td>
- <?= $request->getTypeString() ?>
+ <?= htmlReady($request->getTypeString()) ?>
</td>
</tr>
<? endforeach ?>
diff --git a/app/views/resources/room_request/resolve.php b/app/views/resources/room_request/resolve.php
index 7c518fb..9458491 100644
--- a/app/views/resources/room_request/resolve.php
+++ b/app/views/resources/room_request/resolve.php
@@ -125,7 +125,7 @@
<dd>
<? $dates = $request->getDateString(true, false) ?>
<? if ($dates) : ?>
- <?= implode('<br>', $dates) ?>
+ <?= implode('<br>', array_map('htmlReady', $dates)) ?>
<? else : ?>
<?= _('Keine') ?>
<? endif ?>
diff --git a/lib/models/CourseDate.php b/lib/models/CourseDate.php
index 038a120..e2c5ffa 100644
--- a/lib/models/CourseDate.php
+++ b/lib/models/CourseDate.php
@@ -356,11 +356,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event
if (in_array($format, ['include-room', 'long-include-room'])) {
$room = $this->getRoom();
if ($room) {
- $string = sprintf('%s <a href="%s" target="_blank">%s</a>',
- $string,
- $room->getActionURL('booking_plan'),
- htmlReady($room->name)
- );
+ $string .= ' ' . $room->name;
} elseif ($this->raum) {
//Use the freetext room name:
$string .= ' ' . $this->raum;
diff --git a/lib/models/SeminarCycleDate.php b/lib/models/SeminarCycleDate.php
index 4f7b6dc..45d3e6a 100644
--- a/lib/models/SeminarCycleDate.php
+++ b/lib/models/SeminarCycleDate.php
@@ -214,7 +214,7 @@ class SeminarCycleDate extends SimpleORMap
*
* @returns string The formatted string.
*/
- public function toString(string $format = 'short') : string
+ public function toString(string $format = 'short', bool $as_html = false) : string
{
if (!in_array($format, ['short', 'long', 'long-start', 'full'])) {
//Invalid format:
@@ -246,16 +246,24 @@ class SeminarCycleDate extends SimpleORMap
$room = $this->getMostBookedRoom();
if ($room) {
- $parameters['room_name'] = sprintf(
- '<a href="%1$s" data-dialog="size=auto">%2$s</a>',
- $room->getActionLink(),
- htmlReady($room->name)
- );
+ if ($as_html) {
+ $parameters['room_name'] = sprintf(
+ '<a href="%1$s" data-dialog="size=auto">%2$s</a>',
+ $room->getActionLink(),
+ htmlReady($room->name)
+ );
+ } else {
+ $parameters['room_name'] = $room->name;
+ }
} else {
//Use the freetext room name:
$room = $this->getMostUsedFreetextRoomName();
if ($room) {
- $parameters['room_name'] = $room;
+ if ($as_html) {
+ $parameters['room_name'] = htmlReady($room);
+ } else {
+ $parameters['room_name'] = $room;
+ }
}
}
$first_date = $this->getFirstDate();
@@ -273,7 +281,11 @@ class SeminarCycleDate extends SimpleORMap
} elseif ($format === 'full') {
$parameters['start_week'] = $this->week_offset + 1;
if ($this->description) {
- $parameters['description'] = $this->description;
+ if ($as_html) {
+ $parameters['description'] = htmlReady($this->description);
+ } else {
+ $parameters['description'] = $this->description;
+ }
}
if ($this->end_offset) {
$parameters['end_week'] = $this->end_offset;
diff --git a/lib/models/resources/ResourceRequest.php b/lib/models/resources/ResourceRequest.php
index 526a67f..a7881ee 100644
--- a/lib/models/resources/ResourceRequest.php
+++ b/lib/models/resources/ResourceRequest.php
@@ -1509,7 +1509,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen
$begin_date = date('Ymd', $this->begin);
$end_date = date('Ymd', $this->end);
if($this->resource) {
- $resource_name = htmlReady($this->resource->getFullName());
+ $resource_name = $this->resource->getFullName();
}
if ($begin_date == $end_date) {
$strings[] = strftime('%a., %x, %R', $this->begin) . ' - '
diff --git a/templates/dates/course_date_list.php b/templates/dates/course_date_list.php
index 8fdcd69..997152d 100644
--- a/templates/dates/course_date_list.php
+++ b/templates/dates/course_date_list.php
@@ -12,14 +12,30 @@
<? if (!$collection->isEmpty()) : ?>
<ul class="list-unstyled">
<? foreach ($collection->getRegularDates() as $regular_date) : ?>
- <li><?= $regular_date->toString('long-start') ?></li>
+ <li>
+ <?= $regular_date->toString('long-start', true) ?>
+ </li>
<? endforeach ?>
<? foreach ($collection->getSingleDates() as $single_date) : ?>
- <li><?= $single_date->getFullName($with_room_names ? 'long-include-room' : 'long') ?></li>
+ <li>
+ <?= htmlReady($single_date->getFullName('long')) ?>
+ <? if ($with_room_names): ?>
+ <? $room = $single_date->getRoom() ?>
+ <? if ($room): ?>
+ <a href="<?= $room->getActionLink() ?>" data-dialog>
+ <?= htmlReady($room->name) ?>
+ </a>
+ <? else: ?>
+ <?= htmlReady($single_date->raum) ?>
+ <? endif ?>
+ <? endif ?>
+ </li>
<? endforeach ?>
<? if ($with_cancelled_dates) : ?>
<? foreach ($collection->getCancelledDates() as $cancelled_date) : ?>
- <li><?= $cancelled_date->getFullName() ?></li>
+ <li>
+ <?= htmlReady($cancelled_date->getFullName()) ?>
+ </li>
<? endforeach ?>
<? endif ?>
</ul>
diff --git a/templates/filesystem/topic_folder/description.php b/templates/filesystem/topic_folder/description.php
index b80740f..9028773 100644
--- a/templates/filesystem/topic_folder/description.php
+++ b/templates/filesystem/topic_folder/description.php
@@ -12,7 +12,7 @@
<?=_('Folgende Termine sind diesem Thema zugeordnet:') ?>
<div>
<strong>
- <?=join('; ', $dates)?>
+ <?= htmlReady(join('; ', $dates)) ?>
</strong>
</div>
<? endif ?>