Commit ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba

Authored by Dmitriy Zaporozhets
2 parents 01974185 345c4d2a

Merge pull request #1512 from tsigo/escape_gfm

Better escaping of text passed into GFM
app/helpers/gitlab_markdown_helper.rb
@@ -12,8 +12,8 @@ module GitlabMarkdownHelper @@ -12,8 +12,8 @@ module GitlabMarkdownHelper
12 # "<a>outer text </a><a>gfm ref</a><a> more outer text</a>"). 12 # "<a>outer text </a><a>gfm ref</a><a> more outer text</a>").
13 def link_to_gfm(body, url, html_options = {}) 13 def link_to_gfm(body, url, html_options = {})
14 return "" if body.blank? 14 return "" if body.blank?
15 -  
16 - gfm_body = gfm(body, html_options) 15 +
  16 + gfm_body = gfm(escape_once(body), html_options)
17 17
18 gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match| 18 gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match|
19 "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1 19 "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1
app/views/commits/_commit_box.html.haml
@@ -11,10 +11,10 @@ @@ -11,10 +11,10 @@
11 = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do 11 = link_to tree_project_ref_path(@project, @commit.id), class: "browse-button primary grouped" do
12 %strong Browse Code » 12 %strong Browse Code »
13 %h3.commit-title.page_title 13 %h3.commit-title.page_title
14 - = gfm @commit.title 14 + = gfm escape_once(@commit.title)
15 - if @commit.description.present? 15 - if @commit.description.present?
16 %pre.commit-description 16 %pre.commit-description
17 - = gfm @commit.description 17 + = gfm escape_once(@commit.description)
18 .commit-info 18 .commit-info
19 .row 19 .row
20 .span4 20 .span4
app/views/events/_commit.html.haml
@@ -5,4 +5,4 @@ @@ -5,4 +5,4 @@
5 %strong.cdark= commit.author_name 5 %strong.cdark= commit.author_name
6 &ndash; 6 &ndash;
7 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16 7 = image_tag gravatar_icon(commit.author_email), class: "avatar", width: 16
8 - = gfm truncate(commit.title, length: 50) rescue "--broken encoding" 8 + = gfm escape_once(truncate(commit.title, length: 50)) rescue "--broken encoding"
app/views/issues/show.html.haml
@@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
31 .alert-message.error.status_info Closed 31 .alert-message.error.status_info Closed
32 - else 32 - else
33 .alert-message.success.status_info Open 33 .alert-message.success.status_info Open
34 - = gfm @issue.title 34 + = gfm escape_once(@issue.title)
35 35
36 .middle_box_content 36 .middle_box_content
37 %cite.cgray Created by 37 %cite.cgray Created by
app/views/merge_requests/show/_mr_box.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 .alert-message.error.status_info Closed 5 .alert-message.error.status_info Closed
6 - else 6 - else
7 .alert-message.success.status_info Open 7 .alert-message.success.status_info Open
8 - = gfm @merge_request.title 8 + = gfm escape_once(@merge_request.title)
9 9
10 .middle_box_content 10 .middle_box_content
11 %div 11 %div
app/views/milestones/show.html.haml
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 .alert-message.error.status_info Closed 21 .alert-message.error.status_info Closed
22 - else 22 - else
23 .alert-message.success.status_info Open 23 .alert-message.success.status_info Open
24 - = gfm @milestone.title 24 + = gfm escape_once(@milestone.title)
25 %small.right= @milestone.expires_at 25 %small.right= @milestone.expires_at
26 26
27 .middle_box_content 27 .middle_box_content
app/views/repositories/_branch.html.haml
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 %code= commit.short_id 11 %code= commit.short_id
12 12
13 = image_tag gravatar_icon(commit.author_email), class: "", width: 16 13 = image_tag gravatar_icon(commit.author_email), class: "", width: 16
14 - = gfm truncate(commit.title, length: 40) 14 + = gfm escape_once(truncate(commit.title, length: 40))
15 %span.update-author.right 15 %span.update-author.right
16 = time_ago_in_words(commit.committed_date) 16 = time_ago_in_words(commit.committed_date)
17 ago 17 ago
app/views/repositories/_feed.html.haml
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 = link_to project_commits_path(@project, commit.id) do 13 = link_to project_commits_path(@project, commit.id) do
14 %code= commit.short_id 14 %code= commit.short_id
15 = image_tag gravatar_icon(commit.author_email), class: "", width: 16 15 = image_tag gravatar_icon(commit.author_email), class: "", width: 16
16 - = gfm truncate(commit.title, length: 40) 16 + = gfm escape_once(truncate(commit.title, length: 40))
17 %td 17 %td
18 %span.right.cgray 18 %span.right.cgray
19 = time_ago_in_words(commit.committed_date) 19 = time_ago_in_words(commit.committed_date)
app/views/repositories/tags.html.haml
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 = link_to project_commit_path(@project, commit.id) do 17 = link_to project_commit_path(@project, commit.id) do
18 %code= commit.short_id 18 %code= commit.short_id
19 = image_tag gravatar_icon(commit.author_email), class: "", width: 16 19 = image_tag gravatar_icon(commit.author_email), class: "", width: 16
20 - = gfm truncate(commit.title, length: 40) 20 + = gfm escape_once(truncate(commit.title, length: 40))
21 %td 21 %td
22 %span.update-author.right 22 %span.update-author.right
23 = time_ago_in_words(commit.committed_date) 23 = time_ago_in_words(commit.committed_date)
lib/gitlab/markdown.rb
@@ -48,8 +48,10 @@ module Gitlab @@ -48,8 +48,10 @@ module Gitlab
48 def gfm(text, html_options = {}) 48 def gfm(text, html_options = {})
49 return text if text.nil? 49 return text if text.nil?
50 50
51 - # prevents the string supplied through the _text_ argument to be altered  
52 - text = text.dup 51 + # Duplicate the string so we don't alter the original, then call to_str
  52 + # to cast it back to a String instead of a SafeBuffer. This is required
  53 + # for gsub calls to work as we need them to.
  54 + text = text.dup.to_str
53 55
54 @html_options = html_options 56 @html_options = html_options
55 57
spec/helpers/gitlab_markdown_helper_spec.rb
@@ -292,11 +292,18 @@ describe GitlabMarkdownHelper do @@ -292,11 +292,18 @@ describe GitlabMarkdownHelper do
292 actual = link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo') 292 actual = link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo')
293 actual.should have_selector 'a.gfm.gfm-commit.foo' 293 actual.should have_selector 'a.gfm.gfm-commit.foo'
294 end 294 end
  295 +
  296 + it "escapes HTML passed in as the body" do
  297 + actual = "This is a <h1>test</h1> - see ##{issues[0].id}"
  298 + link_to_gfm(actual, commit_path).should match('&lt;h1&gt;test&lt;/h1&gt;')
  299 + end
295 end 300 end
296 301
297 describe "#markdown" do 302 describe "#markdown" do
298 it "should handle references in paragraphs" do 303 it "should handle references in paragraphs" do
299 - markdown("\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. #{commit.id} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.\n").should == "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. #{link_to commit.id, project_commit_path(project, commit), title: commit.link_title, class: "gfm gfm-commit "} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.</p>\n" 304 + actual = "\n\nLorem ipsum dolor sit amet. #{commit.id} Nam pulvinar sapien eget.\n"
  305 + expected = project_commit_path(project, commit)
  306 + markdown(actual).should match(expected)
300 end 307 end
301 308
302 it "should handle references in headers" do 309 it "should handle references in headers" do