]> cat aescling's git repositories - mastodon.git/commitdiff
Add backend support for `<spoiler-text>`
authorkibigo! <go@kibi.family>
Fri, 11 Nov 2022 04:51:51 +0000 (20:51 -0800)
committerkibigo! <go@kibi.family>
Sun, 13 Nov 2022 04:50:44 +0000 (20:50 -0800)
This produces a `<span>` with:

- A `property` attribute of `"tag:ns.1024.gdn,2022-11:spoiler_text"`.

- A `content` attribute of the original text contents of the
  `<spoiler-text>` 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 `<spoiler-text>` directly instead.

Getting this to render nicely in the frontend is future work :) .

app/lib/advanced_text_formatter.rb
lib/sanitize_ext/sanitize_config.rb

index ba6a5e868921e6e8e241901ee6f48559cb797720..c8c6e1d01f150435cc7e480119b00c13bd21fdb0 100644 (file)
@@ -112,12 +112,45 @@ class AdvancedTextFormatter < TextFormatter
         end
         text_node.replace(replacement)
       end
+
+      @tree.css('spoiler-text').each do |spoiler_node|
+        # Replace each +<spoiler-text>+ node with a span which reflects
+        # it.
+        #
+        # Note that this elimanates any markup within the
+        # +<spoiler-text>+ 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")
index 946543868a516ef572324179d1f394990fcc2b41..546b745fc5307d1462db5156e80756fbe7447217 100644 (file)
@@ -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: {},