From 81e1c8e3c4c02276fb890da7e3f684259aeb685c Mon Sep 17 00:00:00 2001 From: Keegan George Date: Thu, 12 Sep 2024 10:22:05 -0700 Subject: [PATCH] SECURITY: Fix XSS in calendar event name (#607) We need to sanitize event names to prevent XSS from occurring in events. --- .../initializers/discourse-calendar.js | 3 +- .../lib/full-calendar-default-options.js | 4 ++- plugin.rb | 2 +- .../category-events-calendar-test.js | 36 ++++++++++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/assets/javascripts/discourse/initializers/discourse-calendar.js b/assets/javascripts/discourse/initializers/discourse-calendar.js index 164d8762d..c682b38f7 100644 --- a/assets/javascripts/discourse/initializers/discourse-calendar.js +++ b/assets/javascripts/discourse/initializers/discourse-calendar.js @@ -1,5 +1,6 @@ import { isPresent } from "@ember/utils"; import $ from "jquery"; +import { escape } from "pretty-text/sanitizer"; import { Promise } from "rsvp"; import { ajax } from "discourse/lib/ajax"; import loadScript from "discourse/lib/load-script"; @@ -581,7 +582,7 @@ function initializeDiscourseCalendar(api) { if (detail.message.length > 100) { popupText += "…"; } - event.extendedProps.htmlContent = popupText; + event.extendedProps.htmlContent = escape(popupText); event.title = event.title.replace(/]*>/g, ""); calendar.addEvent(event); } diff --git a/assets/javascripts/discourse/lib/full-calendar-default-options.js b/assets/javascripts/discourse/lib/full-calendar-default-options.js index b91c53493..515a377f3 100644 --- a/assets/javascripts/discourse/lib/full-calendar-default-options.js +++ b/assets/javascripts/discourse/lib/full-calendar-default-options.js @@ -1,3 +1,4 @@ +import { escape } from "pretty-text/sanitizer"; import { getCalendarButtonsText, getCurrentBcp47Locale, @@ -13,7 +14,8 @@ export default function fullCalendarDefaultOptions() { buttonText: getCalendarButtonsText(), eventMouseEnter: function ({ event, jsEvent }) { destroyPopover(); - const htmlContent = event.title; + + const htmlContent = escape(event.title); buildPopover(jsEvent, htmlContent); }, eventMouseLeave: function () { diff --git a/plugin.rb b/plugin.rb index 19d3a2f36..22a7ecbae 100644 --- a/plugin.rb +++ b/plugin.rb @@ -3,7 +3,7 @@ # name: discourse-calendar # about: Adds the ability to create a dynamic calendar with events in a topic. # meta_topic_id: 97376 -# version: 0.4 +# version: 0.5 # author: Daniel Waterworth, Joffrey Jaffeux # url: https://github.com/discourse/discourse-calendar diff --git a/test/javascripts/acceptance/category-events-calendar-test.js b/test/javascripts/acceptance/category-events-calendar-test.js index 95cc4e493..092422194 100644 --- a/test/javascripts/acceptance/category-events-calendar-test.js +++ b/test/javascripts/acceptance/category-events-calendar-test.js @@ -74,17 +74,51 @@ acceptance("Discourse Calendar - Category Events Calendar", function (needs) { }, name: "Awesome Event 2", }, + { + id: 67502, + starts_at: moment() + .tz("Asia/Calcutta") + .add(2, "days") + .format("YYYY-MM-DDT15:14:00.000Z"), + ends_at: moment() + .tz("Asia/Calcutta") + .add(2, "days") + .format("YYYY-MM-DDT16:14:00.000Z"), + timezone: "Asia/Calcutta", + post: { + id: 67502, + post_number: 1, + url: "/t/this-is-an-event/18451/1", + topic: { + id: 18451, + title: "This is an event", + category_slug: "awesome-category", + }, + }, + name: "Awesome Event 3", + }, ], }); }); }); + test("event name is escaped correctly", async (assert) => { + await visit("/c/bug/1"); + + assert + .dom(".fc-event[href='/t/-/18451/1'] .fc-title") + .hasText( + "Awesome Event 3", + "Elements should be escaped and appear as text rather than be the actual element." + ); + }); + test("events display the color configured in the map_events_to_color site setting", async (assert) => { await visit("/c/bug/1"); assert .dom(".fc-event") - .exists({ count: 2 }, "One event is displayed on the calendar"); + .exists({ count: 3 }, "One event is displayed on the calendar"); assert.dom(".fc-event[href='/t/-/18449/1']").hasStyle({ "background-color": "rgb(231, 76, 60)",