diff --git a/lib/sanitize_ext/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb index 70efe7c1ae5..db81244104e 100644 --- a/lib/sanitize_ext/sanitize_config.rb +++ b/lib/sanitize_ext/sanitize_config.rb @@ -64,6 +64,43 @@ class Sanitize current_node.wrap('

') end + # We assume that incomming nodes are of the form + # ...... + # according to the [FEP]. We try to grab the most relevant plain-text + # annotation from the semantics node, and use it to display a representation + # of the mathematics. + # + # FEP: https://codeberg.org/fediverse/fep/src/branch/main/fep/dc88/fep-dc88.md + MATH_TRANSFORMER = lambda do |env| + math = env[:node] + return if env[:is_allowlisted] + return unless math.element? && env[:node_name] == 'math' + + semantics = math.element_children[0] + return if semantics.nil? || semantics.name != 'semantics' + + # next, we find the plain-text description + is_annotation_with_encoding = lambda do |encoding, node| + return false unless node.name == 'annotation' + + node.attributes['encoding'].value == encoding + end + + annotation = semantics.children.find(&is_annotation_with_encoding.curry['application/x-tex']) + if annotation + if math.attributes['display']&.value == 'block' + math.swap("$$#{annotation.content}$$") + else + math.swap("$#{annotation.content}$") + end + return + end + # Don't bother surrounding 'text/plain' annotations with dollar signs, + # since it isn't LaTeX + annotation = semantics.children.find(&is_annotation_with_encoding.curry['text/plain']) + math.swap(annotation.content) unless annotation.nil? + end + MASTODON_STRICT = freeze_config( elements: %w(p br span a del pre blockquote code b strong u i em ul ol li), @@ -86,6 +123,7 @@ class Sanitize transformers: [ CLASS_WHITELIST_TRANSFORMER, TRANSLATE_TRANSFORMER, + MATH_TRANSFORMER, UNSUPPORTED_ELEMENTS_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, ] diff --git a/spec/lib/sanitize/config_spec.rb b/spec/lib/sanitize/config_spec.rb index 2d8dc2f63be..aa39b9becab 100644 --- a/spec/lib/sanitize/config_spec.rb +++ b/spec/lib/sanitize/config_spec.rb @@ -53,5 +53,25 @@ describe Sanitize::Config do it 'keeps a with supported scheme and no host' do expect(Sanitize.fragment('Test', subject)).to eq 'Test' end + + it 'sanitizes math to LaTeX' do + mathml = 'xn+yx^n+y' + expect(Sanitize.fragment(mathml, subject)).to eq '$x^n+y$' + end + + it 'sanitizes math blocks to LaTeX' do + mathml = 'xn+yx^n+y' + expect(Sanitize.fragment(mathml, subject)).to eq '$$x^n+y$$' + end + + it 'math sanitizer falls back to plaintext' do + mathml = 'xsqrt(x)' + expect(Sanitize.fragment(mathml, subject)).to eq 'sqrt(x)' + end + + it 'prefers latex' do + mathml = 'xsqrt(x)\\sqrt x' + expect(Sanitize.fragment(mathml, subject)).to eq '$\sqrt x$' + end end end