From 578e1e58c23194ce9ed66ac3fd8e027244f84e2e Mon Sep 17 00:00:00 2001 From: kibigo! Date: Thu, 10 Nov 2022 20:51:51 -0800 Subject: [PATCH] Add backend support for `` MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This produces a `` with: - A `property` attribute of `"tag:ns.1024.gdn,2022-11:spoiler_text"`. - A `content` attribute of the original text contents of the `` element. - Text contents which replace ASCII basic latin characters with their ROT13 equivalents and other alphabetic characters with REPLACEMENT CHARACTER. (The intent is that ROT13 gives a reasonable fallback for unsupporting servers for Latin‐script posts.) `property` and `content` are RDFa attributes and don’t have any notable security implications. They are disallowed on local posts because users should just use `` directly instead. Getting this to render nicely in the frontend is future work :) . --- app/lib/advanced_text_formatter.rb | 33 +++++++++++++++++++++++++++++ lib/sanitize_ext/sanitize_config.rb | 19 +++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/app/lib/advanced_text_formatter.rb b/app/lib/advanced_text_formatter.rb index ba6a5e868..c8c6e1d01 100644 --- a/app/lib/advanced_text_formatter.rb +++ b/app/lib/advanced_text_formatter.rb @@ -112,12 +112,45 @@ class AdvancedTextFormatter < TextFormatter end text_node.replace(replacement) end + + @tree.css('spoiler-text').each do |spoiler_node| + # Replace each ++ node with a span which reflects + # it. + # + # Note that this elimanates any markup within the + # ++ node. + content = spoiler_node.content + elt = Nokogiri::XML::Element.new('span', document) + elt['property'] = 'tag:ns.1024.gdn,2022-11-11:spoiler_text' + elt['content'] = content + elt << Nokogiri::XML::Text.new( + encode_spoiler(content), + document + ) + spoiler_node.replace(elt) + end end @tree end private + def encode_spoiler(text) + result = ''.dup + text.unicode_normalize(:nfkd).each_char do |char| + result << if /[A-Ma-m]/.match?(char) + char.codepoints[0] + 13 + elsif /[N-Zn-z]/.match?(char) + char.codepoints[0] - 13 + elsif /[[:alpha:]]/.match?(char) + 0xFFFD + else + char + end + end + result + end + def format_markdown(html) html = markdown_formatter.render(html) html.delete("\r").delete("\n") diff --git a/lib/sanitize_ext/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb index 946543868..546b745fc 100644 --- a/lib/sanitize_ext/sanitize_config.rb +++ b/lib/sanitize_ext/sanitize_config.rb @@ -36,6 +36,18 @@ class Sanitize node['class'] = class_list.join(' ') end + ## + # Deletes the +property+ and +content+ properties if the value of + # +property+ is not a recognized IRI. + PROPERTY_ALLOWLIST_TRANSFORMER = lambda do |env| + node = env[:node] + return if node['property'].present? && %w( + tag:ns.1024.gdn,2022-11-11:spoiler_text + ).include?(node['property']) + node.remove_attribute('property') + node.remove_attribute('content') + end + IMG_TAG_TRANSFORMER = lambda do |env| node = env[:node] @@ -76,7 +88,7 @@ class Sanitize attributes: { 'a' => %w(href rel class title), - 'span' => %w(class), + 'span' => %w(class property content), 'abbr' => %w(title), 'blockquote' => %w(cite), 'ol' => %w(start reversed), @@ -97,6 +109,7 @@ class Sanitize transformers: [ CLASS_WHITELIST_TRANSFORMER, + PROPERTY_ALLOWLIST_TRANSFORMER, IMG_TAG_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, ] @@ -151,9 +164,11 @@ class Sanitize end MASTODON_OUTGOING ||= freeze_config MASTODON_STRICT.merge( + elements: MASTODON_STRICT[:elements] + %w(spoiler-text), attributes: merge( MASTODON_STRICT[:attributes], - 'a' => %w(href rel class title target) + 'a' => %w(href rel class title target), + 'span' => %w(class) # do not allow manual property setting ), add_attributes: {}, -- 2.47.3