summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile1
-rw-r--r--app/assets/stylesheets/application.css7
-rw-r--r--lib/redmine/wiki_formatting/common_mark/formatter.rb7
-rw-r--r--lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb48
-rw-r--r--test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb2
-rw-r--r--test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb21
6 files changed, 72 insertions, 14 deletions
diff --git a/Gemfile b/Gemfile
index d7ea765b5..d08b7661c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -49,7 +49,6 @@ end
# Optional CommonMark support, not for JRuby
group :common_mark do
gem "commonmarker", '~> 2.3.0'
- gem 'deckar01-task_list', '2.3.2'
end
# Include database gems for the adapters found in the database
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
index 088ebccbe..cfb7e168a 100644
--- a/app/assets/stylesheets/application.css
+++ b/app/assets/stylesheets/application.css
@@ -1611,10 +1611,11 @@ a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; }
h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor, h4:hover a.wiki-anchor, h5:hover a.wiki-anchor, h6:hover a.wiki-anchor { display: inline; color: #ddd; }
div.wiki img {vertical-align:middle; max-width:100%;}
-div.wiki>.task-list {
- padding-left: 0px;
+
+div.wiki>.contains-task-list {
+ padding-left: 0;
}
-div.wiki .task-list {
+div.wiki .contains-task-list {
list-style-type: none;
}
div.wiki .task-list input.task-list-item-checkbox {
diff --git a/lib/redmine/wiki_formatting/common_mark/formatter.rb b/lib/redmine/wiki_formatting/common_mark/formatter.rb
index eb765b6d6..b695fb854 100644
--- a/lib/redmine/wiki_formatting/common_mark/formatter.rb
+++ b/lib/redmine/wiki_formatting/common_mark/formatter.rb
@@ -18,7 +18,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'html/pipeline'
-require 'task_list/filter'
module Redmine
module WikiFormatting
@@ -33,7 +32,7 @@ module Redmine
autolink: true,
footnotes: true,
header_ids: nil,
- tasklist: false,
+ tasklist: true,
shortcodes: false,
}.freeze,
@@ -46,6 +45,7 @@ module Redmine
unsafe: true,
github_pre_lang: false,
hardbreaks: Redmine::Configuration['common_mark_enable_hardbreaks'] == true,
+ tasklist_classes: true,
}.freeze,
commonmarker_plugins: {
syntax_highlighter: nil
@@ -57,8 +57,7 @@ module Redmine
SanitizationFilter,
SyntaxHighlightFilter,
FixupAutoLinksFilter,
- ExternalLinksFilter,
- TaskList::Filter
+ ExternalLinksFilter
], PIPELINE_CONFIG
class Formatter
diff --git a/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb b/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
index cdefc372b..e603d9f7f 100644
--- a/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
+++ b/lib/redmine/wiki_formatting/common_mark/sanitization_filter.rb
@@ -78,20 +78,58 @@ module Redmine
# allowlist[:attributes]["td"] = %w(style)
# allowlist[:css] = { properties: ["text-align"] }
- # Allow `id` in a and li elements for footnotes
- # and remove any `id` properties not matching for footnotes
+ # Allow `id` in a elements for footnotes
allowlist[:attributes]["a"].push "id"
- allowlist[:attributes]["li"] = %w(id)
+ # Remove any `id` property not matching for footnotes
allowlist[:transformers].push lambda{|env|
node = env[:node]
- return unless node.name == "a" || node.name == "li"
+ return unless node.name == "a"
return unless node.has_attribute?("id")
return if node.name == "a" && node["id"] =~ /\Afnref-\d+\z/
- return if node.name == "li" && node["id"] =~ /\Afn-\d+\z/
node.remove_attribute("id")
}
+ # allow `id` in li element for footnotes
+ # allow `class` in li element for task list items
+ allowlist[:attributes]["li"] = %w(id class)
+ allowlist[:transformers].push lambda{|env|
+ node = env[:node]
+ return unless node.name == "li"
+
+ if node.has_attribute?("id") && !(node["id"] =~ /\Afn-\d+\z/)
+ node.remove_attribute("id")
+ end
+
+ if node.has_attribute?("class") && node["class"] != "task-list-item"
+ node.remove_attribute("class")
+ end
+ }
+
+ # allow input type = "checkbox" with class "task-list-item-checkbox"
+ # for task list items
+ allowlist[:elements].push('input')
+ allowlist[:attributes]["input"] = %w(class type)
+ allowlist[:transformers].push lambda{|env|
+ node = env[:node]
+
+ return unless node.name == "input"
+ return if node['type'] == "checkbox" && node['class'] == "task-list-item-checkbox"
+
+ node.replace(node.children)
+ }
+
+ # allow class "contains-task-list" on ul for task list items
+ allowlist[:attributes]["ul"] = %w(class)
+ allowlist[:transformers].push lambda{|env|
+ node = env[:node]
+
+ return unless node.name == "ul"
+ return if node["class"] == "contains-task-list"
+
+ node.remove_attribute("class")
+ }
+
# https://github.com/rgrove/sanitize/issues/209
allowlist[:protocols].delete("a")
allowlist[:transformers].push lambda{|env|
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
index 11d5913ce..79581a928 100644
--- a/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
+++ b/test/unit/lib/redmine/wiki_formatting/common_mark/formatter_test.rb
@@ -287,7 +287,7 @@ class Redmine::WikiFormatting::CommonMark::FormatterTest < ActionView::TestCase
expected = <<~EXPECTED
<p>Task list:</p>
- <ul class="task-list">
+ <ul class="contains-task-list">
<li class="task-list-item">
<input type="checkbox" class="task-list-item-checkbox" disabled> Task 1
</li>
diff --git a/test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb b/test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb
index 11dddb5f8..90e02640d 100644
--- a/test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb
+++ b/test/unit/lib/redmine/wiki_formatting/html_sanitizer_test.rb
@@ -35,4 +35,25 @@ class Redmine::WikiFormatting::HtmlSanitizerTest < ActiveSupport::TestCase
input = %(<a href="javascript:alert('hello');">foo</a>)
assert_equal "<a>foo</a>", @sanitizer.call(input)
end
+
+ def test_should_be_strict_with_task_list_items
+ to_test = {
+ %(<input type="checkbox" class="">) => "",
+ %(<input type="checkbox" class="task-list-item-checkbox other">) => "",
+ %(<input type="checkbox" class="task-list-item-checkbox" id="item1">) => %(<input type="checkbox" class="task-list-item-checkbox">),
+ %(<input type="text" class="">) => "",
+ %(<input />) => "",
+ %(<ul class="other"></ul) => "<ul></ul>",
+ %(<ul class="contains-task-list"></ul) => "<ul class=\"contains-task-list\"></ul>",
+ %(<ul class="contains-task-list" id="list1"></ul) => "<ul class=\"contains-task-list\"></ul>",
+ %(<li class="other"></li>) => "",
+ %(<li id="other"></li>) => "",
+ %(<li class="task-list-item"></li>) => "",
+ %(<li class="task-list-item">Item 1</li>) => "Item 1",
+ }
+ to_test.each do |input, result|
+ assert_equal result, @sanitizer.call(input)
+ end
+
+ end
end