diff options
author | Marius Balteanu <marius.balteanu@zitec.com> | 2021-08-11 21:40:56 +0000 |
---|---|---|
committer | Marius Balteanu <marius.balteanu@zitec.com> | 2021-08-11 21:40:56 +0000 |
commit | 9af2ba2c13d2dc706bdf1387110c13b82175a0cf (patch) | |
tree | eab705cebf67e7daaa30532a62dbdb1c8dfba205 /test | |
parent | fe4d0d93da6f95408582e53b425e89fc40751f6f (diff) | |
download | redmine-9af2ba2c13d2dc706bdf1387110c13b82175a0cf.tar.gz redmine-9af2ba2c13d2dc706bdf1387110c13b82175a0cf.zip |
Adds CommonMark Markdown (GitHub Flavored) as third text formatting option (#32424).
Patch by Jens Krämer.
git-svn-id: http://svn.redmine.org/redmine/trunk@21156 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'test')
7 files changed, 755 insertions, 0 deletions
diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb new file mode 100644 index 000000000..fecafd660 --- /dev/null +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/application_helper_test.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2021 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../../../test_helper', __FILE__) + +class Redmine::WikiFormatting::CommonMark::ApplicationHelperTest < Redmine::HelperTest + if Object.const_defined?(:CommonMarker) + + include ERB::Util + include Rails.application.routes.url_helpers + + fixtures :projects, :enabled_modules, + :users, :email_addresses, + :members, :member_roles, :roles, + :repositories, :changesets, + :projects_trackers, + :trackers, :issue_statuses, :issues, :versions, :documents, :journals, + :wikis, :wiki_pages, :wiki_contents, + :boards, :messages, :news, + :attachments, :enumerations, + :custom_values, :custom_fields, :custom_fields_projects + + def setup + super + set_tmp_attachments_directory + end + + def test_attached_images_with_markdown_and_non_ascii_filename + to_test = { + 'CAFÉ.JPG' => 'CAF%C3%89.JPG', + 'crème.jpg' => 'cr%C3%A8me.jpg', + } + with_settings :text_formatting => 'common_mark' do + to_test.each do |filename, result| + attachment = Attachment.generate!(:filename => filename) + assert_include %(<img src="/attachments/download/#{attachment.id}/#{result}" alt="">), textilizable("![](#{filename})", :attachments => [attachment]) + end + end + end + + def test_toc_with_markdown_formatting_should_be_parsed + with_settings :text_formatting => 'common_mark' do + assert_select_in textilizable("{{toc}}\n\n# Heading"), 'ul.toc li', :text => 'Heading' + assert_select_in textilizable("{{<toc}}\n\n# Heading"), 'ul.toc.left li', :text => 'Heading' + assert_select_in textilizable("{{>toc}}\n\n# Heading"), 'ul.toc.right li', :text => 'Heading' + end + end + + end +end diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb new file mode 100644 index 000000000..d4e8fa0df --- /dev/null +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/external_links_filter_test.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2021 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../../../test_helper', __FILE__) + +if Object.const_defined?(:CommonMarker) + require 'redmine/wiki_formatting/common_mark/external_links_filter' + + class Redmine::WikiFormatting::CommonMark::ExternalLinksFilterTest < ActiveSupport::TestCase + def filter(html) + Redmine::WikiFormatting::CommonMark::ExternalLinksFilter.to_html(html, @options) + end + + def setup + @options = { } + end + + def test_external_links_should_have_external_css_class + assert_equal %(<a href="http://example.net/" class="external">link</a>), filter(%(<a href="http://example.net/">link</a>)) + end + + def test_locals_links_should_not_have_external_css_class + assert_equal %(<a href="/">home</a>), filter(%(<a href="/">home</a>)) + assert_equal %(<a href="relative">relative</a>), filter(%(<a href="relative">relative</a>)) + assert_equal %(<a href="#anchor">anchor</a>), filter(%(<a href="#anchor">anchor</a>)) + end + + def test_mailto_links_should_have_email_class + assert_equal %(<a href="mailto:user@example.org" class="email">user</a>), filter(%(<a href="mailto:user@example.org">user</a>)) + end + end +end diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb new file mode 100644 index 000000000..92b324151 --- /dev/null +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/fixup_auto_links_filter_test.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2021 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../../../test_helper', __FILE__) + +if Object.const_defined?(:CommonMarker) + require 'redmine/wiki_formatting/common_mark/fixup_auto_links_filter' + + class Redmine::WikiFormatting::CommonMark::FixupAutoLinksFilterTest < ActiveSupport::TestCase + def filter(html) + Redmine::WikiFormatting::CommonMark::FixupAutoLinksFilter.to_html(html, @options) + end + + def format(markdown) + Redmine::WikiFormatting::CommonMark::MarkdownFilter.to_html(markdown, Redmine::WikiFormatting::CommonMark::PIPELINE_CONFIG) + end + + def setup + @options = { } + end + + def test_should_fixup_autolinked_user_references + text = "user:user@example.org" + assert_equal "<p>#{text}</p>", filter(format(text)) + text = "@user@example.org" + assert_equal "<p>#{text}</p>", filter(format(text)) + end + + def test_should_fixup_autolinked_hires_files + text = "printscreen@2x.png" + assert_equal "<p>#{text}</p>", filter(format(text)) + end + end +end diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb new file mode 100644 index 000000000..9f23dba30 --- /dev/null +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb @@ -0,0 +1,270 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2021 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../../../test_helper', __FILE__) + +class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase + if Object.const_defined?(:CommonMarker) + + def setup + @formatter = Redmine::WikiFormatting::CommonMark::Formatter + end + + def format(text) + @formatter.new(text).to_html + end + + def test_should_render_hard_breaks + html ="<p>foo<br>\nbar</p>" + assert_equal html, format("foo\\\nbar") + assert_equal html, format("foo \nbar") + end + + def test_should_ignore_soft_breaks + assert_equal "<p>foo\nbar</p>", format("foo\nbar") + end + + def test_syntax_error_in_image_reference_should_not_raise_exception + assert format("!>[](foo.png)") + end + + def test_empty_image_should_not_raise_exception + assert format("![]()") + end + + def test_inline_style + assert_equal "<p><strong>foo</strong></p>", format("**foo**") + end + + def test_not_set_intra_emphasis + assert_equal "<p>foo_bar_baz</p>", format("foo_bar_baz") + end + + def test_wiki_links_should_be_preserved + text = 'This is a wiki link: [[Foo]]' + assert_include '[[Foo]]', format(text) + end + + def test_redmine_links_with_double_quotes_should_be_preserved + text = 'This is a redmine link: version:"1.0"' + assert_include 'version:"1.0"', format(text) + end + + def test_links_by_id_should_be_preserved + text = "[project#3]" + assert_equal "<p>#{text}</p>", format(text) + end + + def test_links_to_users_should_be_preserved + text = "[@login]" + assert_equal "<p>#{text}</p>", format(text) + text = "[user:login]" + assert_equal "<p>#{text}</p>", format(text) + text = "user:user@example.org" + assert_equal "<p>#{text}</p>", format(text) + text = "[user:user@example.org]" + assert_equal "<p>#{text}</p>", format(text) + text = "@user@example.org" + assert_equal "<p>#{text}</p>", format(text) + text = "[@user@example.org]" + assert_equal "<p>#{text}</p>", format(text) + end + + def test_files_with_at_should_not_end_up_as_mailto_links + text = "printscreen@2x.png" + assert_equal "<p>#{text}</p>", format(text) + text = "[printscreen@2x.png]" + assert_equal "<p>#{text}</p>", format(text) + end + + def test_should_support_syntax_highlight + text = <<-STR + ~~~ruby + def foo + end + ~~~ + STR + assert_select_in format(text), 'pre code.ruby.syntaxhl' do + assert_select 'span.k', :text => 'def' + end + end + + def test_should_not_allow_invalid_language_for_code_blocks + text = <<-STR + ~~~foo + test + ~~~ + STR + assert_equal "<pre>test\n</pre>", format(text) + end + + def test_external_links_should_have_external_css_class + text = 'This is a [link](http://example.net/)' + assert_equal '<p>This is a <a href="http://example.net/" class="external">link</a></p>', format(text) + end + + def test_locals_links_should_not_have_external_css_class + text = 'This is a [link](/issues)' + assert_equal '<p>This is a <a href="/issues">link</a></p>', format(text) + end + + def test_markdown_should_not_require_surrounded_empty_line + text = <<-STR + This is a list: + * One + * Two + STR + assert_equal "<p>This is a list:</p>\n<ul>\n<li>One</li>\n<li>Two</li>\n</ul>", format(text) + end + + def test_footnotes + text = <<-STR + This is some text[^1]. + + [^1]: This is the foot note + STR + + expected = <<-EXPECTED + <p>This is some text<sup><a href="#fn1" id="fnref1">1</a></sup>.</p> + <ol> + <li id="fn1"> + <p>This is the foot note <a href="#fnref1">↩</a></p> + </li> + </ol> + EXPECTED + + assert_equal expected.gsub(%r{[\r\n\t]}, ''), format(text).gsub(%r{[\r\n\t]}, '') + end + + STR_WITH_PRE = [ + # 0 + <<~STR.chomp, + # Title + + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. + STR + # 1 + <<~STR.chomp, + ## Heading 2 + + ~~~ruby + def foo + end + ~~~ + + Morbi facilisis accumsan orci non pharetra. + + ~~~ ruby + def foo + end + ~~~ + + ``` + Pre Content: + + ## Inside pre + + <tag> inside pre block + + Morbi facilisis accumsan orci non pharetra. + ``` + STR + # 2 + <<~STR.chomp, + ### Heading 3 + + Nulla nunc nisi, egestas in ornare vel, posuere ac libero. + STR + ] + + def test_get_section_should_ignore_pre_content + text = STR_WITH_PRE.join("\n\n") + + assert_section_with_hash STR_WITH_PRE[1..2].join("\n\n"), text, 2 + assert_section_with_hash STR_WITH_PRE[2], text, 3 + end + + def test_update_section_should_not_escape_pre_content_outside_section + text = STR_WITH_PRE.join("\n\n") + replacement = "New text" + + assert_equal [STR_WITH_PRE[0..1], "New text"].flatten.join("\n\n"), + @formatter.new(text).update_section(3, replacement) + end + + def test_should_emphasize_text + text = 'This _text_ should be emphasized' + assert_equal '<p>This <em>text</em> should be emphasized</p>', format(text) + end + + def test_should_strike_through_text + text = 'This ~~text~~ should be striked through' + assert_equal '<p>This <del>text</del> should be striked through</p>', format(text) + end + + def test_should_autolink_urls_and_emails + [ + ["http://example.org", '<p><a href="http://example.org" class="external">http://example.org</a></p>'], + ["http://www.redmine.org/projects/redmine/issues?utf8=✓", + '<p><a href="http://www.redmine.org/projects/redmine/issues?utf8=%E2%9C%93" class="external">http://www.redmine.org/projects/redmine/issues?utf8=✓</a></p>'], + ['[Letters](https://yandex.ru/search/?text=кол-во)', '<p><a href="https://yandex.ru/search/?text=%D0%BA%D0%BE%D0%BB-%D0%B2%D0%BE" class="external">Letters</a></p>'], + ["www.example.org", '<p><a href="http://www.example.org" class="external">www.example.org</a></p>'], + ["user@example.org", '<p><a href="mailto:user@example.org" class="email">user@example.org</a></p>'] + ].each do |text, html| + assert_equal html, format(text) + end + end + + def test_should_support_html_tables + text = '<table style="background: red"><tr><td>Cell</td></tr></table>' + assert_equal '<table><tr><td>Cell</td></tr></table>', format(text) + end + + def test_should_remove_unsafe_uris + [ + ['<img src="data:foobar">', '<img>'], + ['<a href="javascript:bla">click me</a>', '<p><a>click me</a></p>'], + ].each do |text, html| + assert_equal html, format(text) + end + end + + def test_should_escape_unwanted_tags + [ + [ + %[<p>sit<br>amet <style>.foo { color: #fff; }</style> <script>alert("hello world");</script></p>], + %[sit<br/>amet <style>.foo { color: #fff; }</style> <script>alert("hello world");</script>] + ] + ].each do |expected, input| + assert_equal expected, format(input) + end + end + + private + + def assert_section_with_hash(expected, text, index) + result = @formatter.new(text).get_section(index) + + assert_kind_of Array, result + assert_equal 2, result.size + assert_equal expected, result.first, "section content did not match" + assert_equal Digest::MD5.hexdigest(expected), result.last, "section hash did not match" + end + end +end diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb new file mode 100644 index 000000000..195c3e11e --- /dev/null +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/markdown_filter_test.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2021 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../../../test_helper', __FILE__) + +if Object.const_defined?(:CommonMarker) + require 'redmine/wiki_formatting/common_mark/markdown_filter' + + class Redmine::WikiFormatting::CommonMark::MarkdownFilterTest < ActiveSupport::TestCase + def filter(markdown) + Redmine::WikiFormatting::CommonMark::MarkdownFilter.to_html(markdown) + end + + # just a basic sanity test. more formatting tests in the formatter_test + def test_should_render_markdown + assert_equal "<p><strong>bold</strong></p>", filter("**bold**") + end + end +end diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb new file mode 100644 index 000000000..72ef52a63 --- /dev/null +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/sanitization_filter_test.rb @@ -0,0 +1,211 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2021 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../../../test_helper', __FILE__) + +if Object.const_defined?(:CommonMarker) + require 'redmine/wiki_formatting/common_mark/sanitization_filter' + + class Redmine::WikiFormatting::CommonMark::SanitizationFilterTest < ActiveSupport::TestCase + def filter(html) + Redmine::WikiFormatting::CommonMark::SanitizationFilter.to_html(html, @options) + end + + def setup + @options = { } + end + + def test_should_filter_tags + input = %(<textarea>foo</textarea> <blink>dont blink</blink>) + assert_equal %(foo dont blink), filter(input) + end + + def test_should_sanitize_attributes + input = %(<a href="foo" onclick="bar" baz="foo">link</a>) + assert_equal %(<a href="foo">link</a>), filter(input) + end + + def test_should_allow_relative_links + input = %(<a href="foo/bar">foo/bar</a>) + assert_equal input, filter(input) + end + + def test_should_support_footnotes + input = %(<a href="#fn1" id="fnref1">foo</a>) + assert_equal input, filter(input) + input = %(<ol><li id="fn1">footnote</li></ol>) + assert_equal input, filter(input) + end + + def test_should_remove_invalid_ids + input = %(<a href="#fn1" id="foo">foo</a>) + assert_equal %(<a href="#fn1">foo</a>), filter(input) + input = %(<ol><li id="foo">footnote</li></ol>) + assert_equal %(<ol><li>footnote</li></ol>), filter(input) + end + + def test_should_allow_class_on_code_only + input = %(<p class="foo">bar</p>) + assert_equal %(<p>bar</p>), filter(input) + + input = %(<code class="language-ruby">foo</code>) + assert_equal input, filter(input) + + input = %(<code class="foo">foo</code>) + assert_equal %(<code>foo</code>), filter(input) + end + + # samples taken from the Sanitize test suite + # rubocop:disable Layout/LineLength + STRINGS = [ + [ + '<b>Lo<!-- comment -->rem</b> <a href="pants" title="foo" style="text-decoration: underline;">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <style>.foo { color: #fff; }</style> <script>alert("hello world");</script>', + '<b>Lorem</b> <a href="pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br>amet .foo { color: #fff; } ' + ], + [ + '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");', + 'Lorem <a href="pants" title="foo>ipsum <a href="><strong>dolor</strong></a> sit<br>amet ' + ], + [ + '<p>a</p><blockquote>b', + '<p>a</p><blockquote>b</blockquote>' + ], + [ + '<b>Lo<!-- comment -->rem</b> <a href="javascript:pants" title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br/>amet <<foo>script>alert("hello world");</script>', + '<b>Lorem</b> <a title="foo">ipsum</a> <a href="http://foo.com/"><strong>dolor</strong></a> sit<br>amet <script>alert("hello world");' + ] + ] + # rubocop:enable Layout/LineLength + + def test_should_sanitize_html_strings + STRINGS.each do |input, expected| + assert_equal expected, filter(input) + end + end + + # samples taken from the Sanitize test suite + PROTOCOLS = { + 'protocol-based JS injection: simple, no spaces' => [ + '<a href="javascript:alert(\'XSS\');">foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: simple, spaces before' => [ + '<a href="javascript :alert(\'XSS\');">foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: simple, spaces after' => [ + '<a href="javascript: alert(\'XSS\');">foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: simple, spaces before and after' => [ + '<a href="javascript : alert(\'XSS\');">foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: preceding colon' => [ + '<a href=":javascript:alert(\'XSS\');">foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: UTF-8 encoding' => [ + '<a href="javascript:">foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: long UTF-8 encoding' => [ + '<a href="javascript:">foo</a>', + '<a>foo</a>' + ], + + # rubocop:disable Layout/LineLength + 'protocol-based JS injection: long UTF-8 encoding without semicolons' => [ + '<a href=javascript:alert('XSS')>foo</a>', + '<a>foo</a>' + ], + # rubocop:enable Layout/LineLength + + 'protocol-based JS injection: hex encoding' => [ + '<a href="javascript:">foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: long hex encoding' => [ + '<a href="javascript:">foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: hex encoding without semicolons' => [ + '<a href=javascript:alert('XSS')>foo</a>', + '<a>foo</a>' + ], + + 'protocol-based JS injection: null char' => [ + "<img src=java\0script:alert(\"XSS\")>", + '<img src="java">' + # '<img>' + ], + + 'protocol-based JS injection: invalid URL char' => [ + '<img src=java\script:alert("XSS")>', + '<img>' + ], + + 'protocol-based JS injection: spaces and entities' => [ + '<img src="  javascript:alert(\'XSS\');">', + '<img src="">' + # '<img>' + ], + + 'protocol whitespace' => [ + '<a href=" http://example.com/"></a>', + '<a href="http://example.com/"></a>' + ], + + 'data images sources' => [ + '<img src="data:image/png;base64,foobar">', + '<img>' + ], + + 'data URIs' => [ + '<a href="data:text/html;base64,foobar">XSS</a>', + '<a>XSS</a>' + ], + + 'vbscript URIs' => [ + '<a href="vbscript:foobar">XSS</a>', + '<a>XSS</a>' + ], + + 'invalid URIs' => [ + '<a href="foo://example.org">link</a>', + '<a>link</a>' + ], + } + + PROTOCOLS.each do |name, strings| + test "should not allow #{name}" do + input, expected = *strings + assert_equal expected, filter(input) + end + end + end +end diff --git a/test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb b/test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb new file mode 100644 index 000000000..e7e782d53 --- /dev/null +++ b/test/unit/lib/redmine/wiki_formatting/common_mark/syntax_highlight_filter_test.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2021 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../../../test_helper', __FILE__) +if Object.const_defined?(:CommonMarker) + require 'redmine/wiki_formatting/common_mark/syntax_highlight_filter' + + class Redmine::WikiFormatting::CommonMark::SyntaxHighlightFilterTest < ActiveSupport::TestCase + def filter(html) + Redmine::WikiFormatting::CommonMark::SyntaxHighlightFilter.to_html(html, @options) + end + + def setup + @options = { } + end + + def test_should_highlight_supported_language + input = <<~HTML + <pre><code class="language-ruby"> + def foo + end + </code></pre> + HTML + expected = <<~HTML + <pre><code class="ruby syntaxhl"> + <span class="k">def</span> <span class="nf">foo</span> + <span class="k">end</span> + </code></pre> + HTML + assert_equal expected, filter(input) + end + + def test_should_strip_code_for_unknown_lang + input = <<~HTML + <pre><code class="language-foobar"> + def foo + end + </code></pre> + HTML + expected = <<~HTML + <pre> + def foo + end + </pre> + HTML + assert_equal expected, filter(input) + end + + def test_should_ignore_code_without_class + input = <<~HTML + <pre><code> + def foo + end + </code></pre> + HTML + assert_equal input, filter(input) + end + end +end |