Project

General

Profile

Patch #42737 » 0001-Replacing-html-pipeline-with-Loofah-for-HTML-Filteri.patch

Takashi Kato, 2025-05-17 06:41

View differences:

Gemfile
33 33
gem 'rotp', '>= 5.0.0'
34 34
gem 'rqrcode'
35 35

  
36
# HTML pipeline and sanitization
37
gem "html-pipeline", "~> 2.13.2"
38
gem "sanitize", "~> 6.0"
36
# HTML sanitization
37
gem "sanitize", "~> 7.0"
39 38

  
40 39
# Optional gem for LDAP authentication
41 40
group :ldap do
lib/redmine/wiki_formatting/common_mark/external_links_filter.rb → lib/redmine/wiki_formatting/common_mark/external_links_scrubber.rb
24 24
    module CommonMark
25 25
      # adds class="external" to external links, and class="email" to mailto
26 26
      # links
27
      class ExternalLinksFilter < HTML::Pipeline::Filter
28
        def call
29
          doc.search("a").each do |node|
27
      class ExternalLinksScrubber < Loofah::Scrubber
28
        def scrub(node)
29
          if node.name == 'a'
30 30
            url = node["href"]
31
            next unless url
32
            next if url.starts_with?("/") || url.starts_with?("#") || !url.include?(':')
31
            return unless url
32
            return if url.starts_with?("/") || url.starts_with?("#") || !url.include?(':')
33 33

  
34 34
            scheme = begin
35 35
              URI.parse(url).scheme
36 36
            rescue
37 37
              nil
38 38
            end
39
            next if scheme.blank?
39
            return if scheme.blank?
40 40

  
41 41
            klass = node["class"].presence
42 42
            node["class"] = [
......
50 50
              node["rel"] = rel.join(" ")
51 51
            end
52 52
          end
53
          doc
54 53
        end
55 54
      end
56 55
    end
lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter.rb → lib/redmine/wiki_formatting/common_mark/fixup_auto_links_scrubber.rb
26 26
      #   @<a href="mailto:user@example.org">user@example.org</a>
27 27
      # - autolinked hi res image names that look like email addresses:
28 28
      #   <a href="mailto:printscreen@2x.png">printscreen@2x.png</a>
29
      class FixupAutoLinksFilter < HTML::Pipeline::Filter
29
      class FixupAutoLinksScrubber < Loofah::Scrubber
30 30
        USER_LINK_PREFIX = /(@|user:)\z/
31 31
        HIRES_IMAGE = /.+@\dx\.(bmp|gif|jpg|jpe|jpeg|png)\z/
32 32

  
33
        def call
34
          doc.search("a").each do |node|
35
            unless (url = node['href']) && url.starts_with?('mailto:')
36
              next
37
            end
33
        def scrub(node)
34
          if node.name == 'a'
35
            return unless (url = node['href']) && url.starts_with?('mailto:')
38 36

  
39 37
            if ((p = node.previous) && p.text? &&
40 38
                p.text =~(USER_LINK_PREFIX)) ||
......
43 41
              node.replace node.text
44 42
            end
45 43
          end
46
          doc
47 44
        end
48 45
      end
49 46
    end
lib/redmine/wiki_formatting/common_mark/formatter.rb
17 17
# along with this program; if not, write to the Free Software
18 18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 19

  
20
require 'html/pipeline'
21

  
22 20
module Redmine
23 21
  module WikiFormatting
24 22
    module CommonMark
......
53 51
        }.freeze,
54 52
      }.freeze
55 53

  
56
      MarkdownPipeline = HTML::Pipeline.new [
57
        MarkdownFilter,
58
        SanitizationFilter,
59
        SyntaxHighlightFilter,
60
        FixupAutoLinksFilter,
61
        ExternalLinksFilter
62
      ], PIPELINE_CONFIG
54
      SANITIZER = SanitizationFilter.new
55
      SCRUBBERS = [
56
        SyntaxHighlightScrubber.new,
57
        FixupAutoLinksScrubber.new,
58
        ExternalLinksScrubber.new
59
      ]
63 60

  
64 61
      class Formatter
65 62
        include Redmine::WikiFormatting::SectionHelper
......
69 66
        end
70 67

  
71 68
        def to_html(*args)
72
          result = MarkdownPipeline.call @text
73
          result[:output].to_s
69
          html = MarkdownFilter.new(@text, PIPELINE_CONFIG).call
70
          fragment = Redmine::WikiFormatting::HtmlParser.parse(html)
71
          SANITIZER.call(fragment)
72
          SCRUBBERS.each do |scrubber|
73
            fragment.scrub!(scrubber)
74
          end
75
          fragment.to_s
74 76
        end
75 77
      end
76 78
    end
lib/redmine/wiki_formatting/common_mark/markdown_filter.rb
25 25
      # We do not use the stock HTML::Pipeline::MarkdownFilter because this
26 26
      # does not allow for straightforward configuration of render and parsing
27 27
      # options
28
      class MarkdownFilter < HTML::Pipeline::TextFilter
29
        def initialize(text, context = nil, result = nil)
30
          super
31
          @text = @text.delete "\r"
28
      class MarkdownFilter
29
        attr_reader :context
30

  
31
        def initialize(text, context = nil)
32
          @text = text.delete "\r"
33
          @context = context
32 34
        end
33 35

  
34 36
        def call
lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
21 21
  module WikiFormatting
22 22
    module CommonMark
23 23
      # sanitizes rendered HTML using the Sanitize gem
24
      class SanitizationFilter < HTML::Pipeline::SanitizationFilter
24
      class SanitizationFilter
25 25
        include Redmine::Helpers::URL
26

  
27
        attr_accessor :allowlist
28

  
29
        LISTS     = Set.new(%w[ul ol].freeze)
30
        LIST_ITEM = 'li'
31

  
32
        # List of table child elements. These must be contained by a <table> element
33
        # or they are not allowed through. Otherwise they can be used to break out
34
        # of places we're using tables to contain formatted user content (like pull
35
        # request review comments).
36
        TABLE_ITEMS = Set.new(%w[tr td th].freeze)
37
        TABLE = 'table'
38
        TABLE_SECTIONS = Set.new(%w[thead tbody tfoot].freeze)
39

  
40
        # The main sanitization allowlist. Only these elements and attributes are
41
        # allowed through by default.
42
        ALLOWLIST = {
43
          :elements => %w[
44
            h1 h2 h3 h4 h5 h6 br b i strong em a pre code img input tt u
45
            div ins del sup sub p ol ul table thead tbody tfoot blockquote
46
            dl dt dd kbd q samp var hr ruby rt rp li tr td th s strike summary
47
            details caption figure figcaption
48
            abbr bdo cite dfn mark small span time wbr
49
          ].freeze,
50
            :remove_contents => ['script'].freeze,
51
            :attributes => {
52
              'a'          => %w[href id name].freeze,
53
              'img'        => %w[src longdesc].freeze,
54
              'code'       => ['class'].freeze,
55
              'div'        => %w[class itemscope itemtype].freeze,
56
              'li'         => %w[id class].freeze,
57
              'input'      => %w[class type].freeze,
58
              'p'          => ['class'].freeze,
59
              'ul'         => ['class'].freeze,
60
              'blockquote' => ['cite'].freeze,
61
              'del'        => ['cite'].freeze,
62
              'ins'        => ['cite'].freeze,
63
              'q'          => ['cite'].freeze,
64
              :all => %w[
65
                abbr accept accept-charset
66
                accesskey action align alt
67
                aria-describedby aria-hidden aria-label aria-labelledby
68
                axis border cellpadding cellspacing char
69
                charoff charset checked
70
                clear cols colspan color
71
                compact coords datetime dir
72
                disabled enctype for frame
73
                headers height hreflang
74
                hspace ismap label lang
75
                maxlength media method
76
                multiple nohref noshade
77
                nowrap open progress prompt readonly rel rev
78
                role rows rowspan rules scope
79
                selected shape size span
80
                start style summary tabindex target
81
                title type usemap valign value
82
                vspace width itemprop
83
              ].freeze
84
            }.freeze,
85
            :protocols => {
86
              'blockquote' => { 'cite' => ['http', 'https', :relative].freeze },
87
              'del'        => { 'cite' => ['http', 'https', :relative].freeze },
88
              'ins'        => { 'cite' => ['http', 'https', :relative].freeze },
89
              'q'          => { 'cite' => ['http', 'https', :relative].freeze },
90
              'img'        => {
91
                'src'      => ['http', 'https', :relative].freeze,
92
                'longdesc' => ['http', 'https', :relative].freeze
93
              }.freeze
94
            },
95
            :transformers => [
96
              # Top-level <li> elements are removed because they can break out of
97
              # containing markup.
98
              lambda { |env|
99
                name = env[:node_name]
100
                node = env[:node]
101
                if name == LIST_ITEM && node.ancestors.none? { |n| LISTS.include?(n.name) }
102
                  node.replace(node.children)
103
                end
104
              },
105

  
106
              # Table child elements that are not contained by a <table> are removed.
107
              lambda { |env|
108
                name = env[:node_name]
109
                node = env[:node]
110
                if (TABLE_SECTIONS.include?(name) || TABLE_ITEMS.include?(name)) && node.ancestors.none? { |n| n.name == TABLE }
111
                  node.replace(node.children)
112
                end
113
              }
114
            ].freeze,
115
            :css => {
116
              :properties => %w[
117
                color background-color
118
                width min-width max-width
119
                height min-height max-height
120
                padding padding-left padding-right padding-top padding-bottom
121
                margin margin-left margin-right margin-top margin-bottom
122
                border border-left border-right border-top border-bottom border-radius border-style border-collapse border-spacing
123
                font font-style font-variant font-weight font-stretch font-size line-height font-family
124
                text-align
125
                float
126
              ].freeze
127
            }
128
        }.freeze
129

  
26 130
        RELAXED_PROTOCOL_ATTRS = {
27 131
          "a" => %w(href).freeze,
28 132
        }.freeze
29 133

  
30
        ALLOWED_CSS_PROPERTIES = %w[
31
          color background-color
32
          width min-width max-width
33
          height min-height max-height
34
          padding padding-left padding-right padding-top padding-bottom
35
          margin margin-left margin-right margin-top margin-bottom
36
          border border-left border-right border-top border-bottom border-radius border-style border-collapse border-spacing
37
          font font-style font-variant font-weight font-stretch font-size line-height font-family
38
          text-align
39
          float
40
        ].freeze
41

  
42
        def allowlist
43
          @allowlist ||= customize_allowlist(super.deep_dup)
134
        def initialize
135
          @allowlist = default_allowlist
136
          add_transformers
44 137
        end
45 138

  
46
        private
47

  
48
        # customizes the allowlist defined in
49
        # https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/sanitization_filter.rb
50
        def customize_allowlist(allowlist)
51
          # Disallow `name` attribute globally, allow on `a`
52
          allowlist[:attributes][:all].delete("name")
53
          allowlist[:attributes]["a"].push("name")
139
        def call(doc)
140
          # Sanitize is applied to the whole document, so the API is different from loofeh's scrubber.
141
          Sanitize.clean_node!(doc, allowlist)
142
        end
54 143

  
55
          allowlist[:attributes][:all].push("style")
56
          allowlist[:css] = { properties: ALLOWED_CSS_PROPERTIES }
144
        private
57 145

  
146
        def add_transformers
58 147
          # allow class on code tags (this holds the language info from fenced
59 148
          # code bocks and has the format language-foo)
60
          allowlist[:attributes]["code"] = %w(class)
61
          allowlist[:transformers].push lambda{|env|
149
          allowlist[:transformers].push lambda {|env|
62 150
            node = env[:node]
63 151
            return unless node.name == "code"
64 152
            return unless node.has_attribute?("class")
......
70 158

  
71 159
          # Allow class on div and p tags only for alert blocks
72 160
          # (must be exactly: "markdown-alert markdown-alert-*" for div, and "markdown-alert-title" for p)
73
          (allowlist[:attributes]["div"] ||= []) << "class"
74
          (allowlist[:attributes]["p"] ||= []) << "class"
75
          allowlist[:transformers].push lambda{|env|
161
          allowlist[:transformers].push lambda {|env|
76 162
            node = env[:node]
77 163
            return unless node.element?
78 164

  
......
98 184
          # allowlist[:attributes]["td"] = %w(style)
99 185
          # allowlist[:css] = { properties: ["text-align"] }
100 186

  
101
          # Allow `id` in a elements for footnotes
102
          allowlist[:attributes]["a"].push "id"
103 187
          # Remove any `id` property not matching for footnotes
104
          allowlist[:transformers].push lambda{|env|
188
          allowlist[:transformers].push lambda {|env|
105 189
            node = env[:node]
106 190
            return unless node.name == "a"
107 191
            return unless node.has_attribute?("id")
......
112 196

  
113 197
          # allow `id` in li element for footnotes
114 198
          # allow `class` in li element for task list items
115
          allowlist[:attributes]["li"] = %w(id class)
116
          allowlist[:transformers].push lambda{|env|
199
          allowlist[:transformers].push lambda {|env|
117 200
            node = env[:node]
118 201
            return unless node.name == "li"
119 202

  
......
128 211

  
129 212
          # allow input type = "checkbox" with class "task-list-item-checkbox"
130 213
          # for task list items
131
          allowlist[:elements].push('input')
132
          allowlist[:attributes]["input"] = %w(class type)
133
          allowlist[:transformers].push lambda{|env|
214
          allowlist[:transformers].push lambda {|env|
134 215
            node = env[:node]
135

  
136 216
            return unless node.name == "input"
137 217
            return if node['type'] == "checkbox" && node['class'] == "task-list-item-checkbox"
138 218

  
......
140 220
          }
141 221

  
142 222
          # allow class "contains-task-list" on ul for task list items
143
          allowlist[:attributes]["ul"] = %w(class)
144
          allowlist[:transformers].push lambda{|env|
223
          allowlist[:transformers].push lambda {|env|
145 224
            node = env[:node]
146

  
147 225
            return unless node.name == "ul"
148 226
            return if node["class"] == "contains-task-list"
149 227

  
......
151 229
          }
152 230

  
153 231
          # https://github.com/rgrove/sanitize/issues/209
154
          allowlist[:protocols].delete("a")
155
          allowlist[:transformers].push lambda{|env|
232
          allowlist[:transformers].push lambda {|env|
156 233
            node = env[:node]
157 234
            return if node.type != Nokogiri::XML::Node::ELEMENT_NODE
158 235

  
......
168 245
              end
169 246
            end
170 247
          }
248
        end
171 249

  
172
          # Allow `u` element to enable underline
173
          allowlist[:elements].push('u')
174

  
175
          allowlist
250
        # The allowlist to use when sanitizing. This can be passed in the context
251
        # hash to the filter but defaults to ALLOWLIST constant value above.
252
        def default_allowlist
253
          ALLOWLIST.deep_dup
176 254
        end
177 255
      end
178 256
    end
lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter.rb → lib/redmine/wiki_formatting/common_mark/syntax_highlight_scrubber.rb
22 22
    module CommonMark
23 23
      # Redmine Syntax highlighting for <pre><code class="language-foo">
24 24
      # blocks as generated by commonmarker
25
      class SyntaxHighlightFilter < HTML::Pipeline::Filter
26
        def call
27
          doc.search("pre > code").each do |node|
28
            next unless lang = node["class"].presence
29
            next unless lang =~ /\Alanguage-(\S+)\z/
25
      class SyntaxHighlightScrubber < Loofah::Scrubber
26
        def scrub(node)
27
          if node.matches?("pre > code")
28
            return unless lang = node["class"].presence
29
            return unless lang =~ /\Alanguage-(\S+)\z/
30 30

  
31 31
            lang = $1
32 32
            text = node.inner_text
......
36 36

  
37 37
            if Redmine::SyntaxHighlighting.language_supported?(lang)
38 38
              html = Redmine::SyntaxHighlighting.highlight_by_language(text, lang)
39
              next if html.nil?
39
              return if html.nil?
40 40

  
41 41
              node.inner_html = html
42 42
              node["class"] = "#{lang} syntaxhl"
......
45 45
              node.remove_attribute("class")
46 46
            end
47 47
          end
48
          doc
49 48
        end
50 49
      end
51 50
    end
lib/redmine/wiki_formatting/html_parser.rb
28 28
        'style' => ''
29 29
      }
30 30

  
31
      def self.parse(html)
32
        Loofah.html5_fragment(html)
33
      end
34

  
31 35
      def self.to_text(html)
32 36
        html = html.gsub(/[\n\r]/, ' ')
33 37

  
lib/redmine/wiki_formatting/html_sanitizer.rb
21 21
  module WikiFormatting
22 22
    # Combination of SanitizationFilter and ExternalLinksFilter
23 23
    class HtmlSanitizer
24
      Pipeline = HTML::Pipeline.new(
25
        [
26
          Redmine::WikiFormatting::CommonMark::SanitizationFilter,
27
          Redmine::WikiFormatting::CommonMark::ExternalLinksFilter,
28
        ], {})
24
      SANITIZER = Redmine::WikiFormatting::CommonMark::SanitizationFilter.new
25
      SCRUBBERS = [Redmine::WikiFormatting::CommonMark::ExternalLinksScrubber.new]
29 26

  
30 27
      def self.call(html)
31
        result = Pipeline.call html
32
        result[:output].to_s
28
        fragment = HtmlParser.parse(html)
29
        SANITIZER.call(fragment)
30
        SCRUBBERS.each do |scrubber|
31
          fragment.scrub!(scrubber)
32
        end
33
        fragment.to_s
33 34
      end
34 35
    end
35 36
  end
test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb → test/unit/lib/redmine/wiki_formatting/common_mark/external_links_scrubber_test.rb
20 20
require_relative '../../../../../test_helper'
21 21

  
22 22
if Object.const_defined?(:Commonmarker)
23
  require 'redmine/wiki_formatting/common_mark/external_links_filter'
24 23

  
25
  class Redmine::WikiFormatting::CommonMark::ExternalLinksFilterTest < ActiveSupport::TestCase
24
  class Redmine::WikiFormatting::CommonMark::ExternalScrubberFilterTest < ActiveSupport::TestCase
26 25
    def filter(html)
27
      Redmine::WikiFormatting::CommonMark::ExternalLinksFilter.to_html(html, @options)
28
    end
29

  
30
    def setup
31
      @options = { }
26
      fragment = Redmine::WikiFormatting::HtmlParser.parse(html)
27
      scrubber = Redmine::WikiFormatting::CommonMark::ExternalLinksScrubber.new
28
      fragment.scrub!(scrubber)
29
      fragment.to_s
32 30
    end
33 31

  
34 32
    def test_external_links_should_have_external_css_class
test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb → test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_scrubber_test.rb
20 20
require_relative '../../../../../test_helper'
21 21

  
22 22
if Object.const_defined?(:Commonmarker)
23
  require 'redmine/wiki_formatting/common_mark/fixup_auto_links_filter'
24 23

  
25
  class Redmine::WikiFormatting::CommonMark::FixupAutoLinksFilterTest < ActiveSupport::TestCase
24
  class Redmine::WikiFormatting::CommonMark::FixupAutoLinksScrubberTest < ActiveSupport::TestCase
26 25
    def filter(html)
27
      Redmine::WikiFormatting::CommonMark::FixupAutoLinksFilter.to_html(html, @options)
26
      fragment = Redmine::WikiFormatting::HtmlParser.parse(html)
27
      scrubber = Redmine::WikiFormatting::CommonMark::FixupAutoLinksScrubber.new
28
      fragment.scrub!(scrubber)
29
      fragment.to_s
28 30
    end
29 31

  
30 32
    def format(markdown)
31
      Redmine::WikiFormatting::CommonMark::MarkdownFilter.to_html(markdown, Redmine::WikiFormatting::CommonMark::PIPELINE_CONFIG)
32
    end
33

  
34
    def setup
35
      @options = { }
33
      Redmine::WikiFormatting::CommonMark::MarkdownFilter.new(markdown, Redmine::WikiFormatting::CommonMark::PIPELINE_CONFIG).call
36 34
    end
37 35

  
38 36
    def test_should_fixup_autolinked_user_references
test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
255 255

  
256 256
    def test_should_support_html_tables
257 257
      text = '<table style="background: red"><tr><td>Cell</td></tr></table>'
258
      assert_equal '<table><tr><td>Cell</td></tr></table>', to_html(text)
258
      assert_equal '<table><tbody><tr><td>Cell</td></tr></tbody></table>', to_html(text)
259 259
    end
260 260

  
261 261
    def test_should_remove_unsafe_uris
......
289 289
        <p>Task list:</p>
290 290
        <ul class="contains-task-list">
291 291
        <li class="task-list-item">
292
        <input type="checkbox" class="task-list-item-checkbox" disabled> Task 1
292
        <input type="checkbox" class="task-list-item-checkbox" disabled=""> Task 1
293 293
        </li>
294 294
        <li class="task-list-item">
295
        <input type="checkbox" class="task-list-item-checkbox" checked disabled> Task 2</li>
295
        <input type="checkbox" class="task-list-item-checkbox" checked="" disabled=""> Task 2</li>
296 296
        </ul>
297 297
      EXPECTED
298 298

  
test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb
24 24

  
25 25
  class Redmine::WikiFormatting::CommonMark::MarkdownFilterTest < ActiveSupport::TestCase
26 26
    def filter(markdown)
27
      Redmine::WikiFormatting::CommonMark::MarkdownFilter.to_html(markdown)
27
      filter = Redmine::WikiFormatting::CommonMark::MarkdownFilter.new(
28
        markdown,
29
        Redmine::WikiFormatting::CommonMark::PIPELINE_CONFIG)
30
      filter.call
28 31
    end
29 32

  
30 33
    # just a basic sanity test. more formatting tests in the formatter_test
test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb
20 20
require_relative '../../../../../test_helper'
21 21

  
22 22
if Object.const_defined?(:Commonmarker)
23
  require 'redmine/wiki_formatting/common_mark/sanitization_filter'
24 23

  
25 24
  class Redmine::WikiFormatting::CommonMark::SanitizationFilterTest < ActiveSupport::TestCase
26 25
    def filter(html)
27
      Redmine::WikiFormatting::CommonMark::SanitizationFilter.to_html(html, @options)
28
    end
29

  
30
    def setup
31
      @options = { }
26
      fragment = Redmine::WikiFormatting::HtmlParser.parse(html)
27
      sanitizer = Redmine::WikiFormatting::CommonMark::SanitizationFilter.new
28
      sanitizer.call(fragment)
29
      fragment.to_s
32 30
    end
33 31

  
34 32
    def test_should_filter_tags
......
137 135
      ],
138 136
      [
139 137
        'Lo<!-- comment -->rem</b> <a href=pants title="foo>ipsum <a href="http://foo.com/"><strong>dolor</a></strong> sit<br/>amet <script>alert("hello world");',
140
        'Lorem <a href="pants" title="foo&gt;ipsum &lt;a href="><strong>dolor</strong></a> sit<br>amet '
138
        'Lorem <a href="pants" title="foo>ipsum <a href="><strong>dolor</strong></a> sit<br>amet '
141 139
      ],
142 140
      [
143 141
        '<p>a</p><blockquote>b',
......
217 215

  
218 216
      'protocol-based JS injection: null char' => [
219 217
        "<img src=java\0script:alert(\"XSS\")>",
220
        '<img src="java">'
221
        # '<img>'
218
        '<img>'
222 219
      ],
223 220

  
224 221
      'protocol-based JS injection: invalid URL char' => [
......
228 225

  
229 226
      'protocol-based JS injection: spaces and entities' => [
230 227
        '<img src=" &#14;  javascript:alert(\'XSS\');">',
231
        '<img src="">'
232
        # '<img>'
228
        '<img>'
233 229
      ],
234 230

  
235 231
      'protocol whitespace' => [
test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb → test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_scrubber_test.rb
19 19

  
20 20
require_relative '../../../../../test_helper'
21 21
if Object.const_defined?(:Commonmarker)
22
  require 'redmine/wiki_formatting/common_mark/syntax_highlight_filter'
23 22

  
24
  class Redmine::WikiFormatting::CommonMark::SyntaxHighlightFilterTest < ActiveSupport::TestCase
23
  class Redmine::WikiFormatting::CommonMark::SyntaxHighlightScrubberTest < ActiveSupport::TestCase
25 24
    def filter(html)
26
      Redmine::WikiFormatting::CommonMark::SyntaxHighlightFilter.to_html(html, @options)
27
    end
28

  
29
    def setup
30
      @options = { }
25
      fragment = Redmine::WikiFormatting::HtmlParser.parse(html)
26
      scrubber = Redmine::WikiFormatting::CommonMark::SyntaxHighlightScrubber.new
27
      fragment.scrub!(scrubber)
28
      fragment.to_s
31 29
    end
32 30

  
33 31
    def test_should_highlight_supported_language
    (1-1/1)