summaryrefslogtreecommitdiff
path: root/app/models/concerns/taskable.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/concerns/taskable.rb')
-rw-r--r--app/models/concerns/taskable.rb36
1 files changed, 24 insertions, 12 deletions
diff --git a/app/models/concerns/taskable.rb b/app/models/concerns/taskable.rb
index f9eba4cc2fe..dee1c820f23 100644
--- a/app/models/concerns/taskable.rb
+++ b/app/models/concerns/taskable.rb
@@ -24,25 +24,37 @@ module Taskable
(\s.+) # followed by whitespace and some text.
}x.freeze
+ ITEM_PATTERN_UNTRUSTED =
+ '^' \
+ '(?:(?:>\s{0,4})*)' \
+ '(?P<prefix>(?:\s*(?:[-+*]|(?:\d+\.)))+)' \
+ '\s+' \
+ '(?P<checkbox>' \
+ "#{COMPLETE_PATTERN.source}|#{INCOMPLETE_PATTERN.source}" \
+ ')' \
+ '(?P<label>\s.+)'.freeze
+
# ignore tasks in code or html comment blocks. HTML blocks
# are ok as we allow tasks inside <detail> blocks
- REGEX = %r{
- #{::Gitlab::Regex.markdown_code_or_html_comments}
- |
- (?<task_item>
- #{ITEM_PATTERN}
- )
- }mx.freeze
+ REGEX =
+ "#{::Gitlab::Regex.markdown_code_or_html_comments_untrusted}" \
+ "|" \
+ "(?P<task_item>" \
+ "#{ITEM_PATTERN_UNTRUSTED}" \
+ ")".freeze
def self.get_tasks(content)
items = []
- content.to_s.scan(REGEX) do
- next unless $~[:task_item]
+ regex = Gitlab::UntrustedRegexp.new(REGEX, multiline: true)
+ regex.scan(content.to_s).each do |match|
+ next unless regex.extract_named_group(:task_item, match)
+
+ prefix = regex.extract_named_group(:prefix, match)
+ checkbox = regex.extract_named_group(:checkbox, match)
+ label = regex.extract_named_group(:label, match)
- $~[:task_item].scan(ITEM_PATTERN) do |prefix, checkbox, label|
- items << TaskList::Item.new("#{prefix.strip} #{checkbox}", label.strip)
- end
+ items << TaskList::Item.new("#{prefix.strip} #{checkbox}", label.strip)
end
items