mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 05:42:36 +08:00
## Summary Correctly emit `URL` properties in ICS export without RFC 5545 TEXT escaping by introducing `IcalEncoder.encode_uri`, which decodes HTML entities, strips CR/LF characters, and leaves valid URI delimiters such as commas and semicolons intact. This change is applied to both the Discourse Events calendar feed and the user bookmarks ICS feed; all textual properties (`SUMMARY`, `LOCATION`, `DESCRIPTION`) continue to use the existing TEXT encoder. ## Source - Patch Triage: https://patch.discourse.org/patch-triage/1547 Co-authored-by: discourse-patch-triage <272280883+discourse-patch-triage[bot]@users.noreply.github.com>
32 lines
1.1 KiB
Ruby
Vendored
32 lines
1.1 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
module IcalEncoder
|
|
SANITIZER = Rails::Html::FullSanitizer.new
|
|
|
|
# Encodes a string for use in iCalendar text fields (SUMMARY, DESCRIPTION, LOCATION).
|
|
# Strips HTML tags, decodes HTML entities, and escapes special characters per RFC 5545.
|
|
def self.encode(text)
|
|
return "" if text.blank?
|
|
text = SANITIZER.sanitize(text)
|
|
text = CGI.unescapeHTML(text)
|
|
text
|
|
.gsub("\\", "\\\\\\\\")
|
|
.gsub(",", "\\,")
|
|
.gsub(";", "\\;")
|
|
.gsub("\r\n", "\\n")
|
|
.gsub("\n", "\\n")
|
|
.html_safe
|
|
end
|
|
|
|
# Encodes a URI for iCalendar URL properties (RFC 5545 §3.8.4.6).
|
|
# URL values are URIs per RFC 3986, so comma and semicolon (valid sub-delimiters)
|
|
# must not be TEXT-escaped. Entities are decoded first, then CR/LF stripped —
|
|
# order matters: stripping CR/LF after decoding neutralizes entity-encoded
|
|
# newlines (e.g. ` `) that would otherwise inject additional ICS
|
|
# properties on the following line.
|
|
def self.encode_uri(uri)
|
|
return "" if uri.blank?
|
|
|
|
CGI.unescapeHTML(uri.to_s).delete("\r\n").html_safe
|
|
end
|
|
end
|