rel nofollow, on by default to protect forums from spam etc. we should consider lifting it at high trust by default.

This commit is contained in:
Sam Saffron 2013-02-11 11:43:07 +11:00
parent 004d4bf4e1
commit 543845c673
4 changed files with 48 additions and 1 deletions

View file

@ -91,6 +91,7 @@ class SiteSetting < ActiveRecord::Base
setting(:allow_duplicate_topic_titles, false) setting(:allow_duplicate_topic_titles, false)
setting(:add_rel_nofollow_to_user_content, true)
setting(:post_excerpt_maxlength, 300) setting(:post_excerpt_maxlength, 300)
setting(:post_onebox_maxlength, 500) setting(:post_onebox_maxlength, 500)
setting(:best_of_score_threshold, 15) setting(:best_of_score_threshold, 15)

View file

@ -219,6 +219,7 @@ en:
max_image_width: "maximum width for an image in a post" max_image_width: "maximum width for an image in a post"
category_featured_topics: "number of topics displayed in the category list" category_featured_topics: "number of topics displayed in the category list"
popup_delay: "Length of time in ms before popups appear on the screen" popup_delay: "Length of time in ms before popups appear on the screen"
add_rel_nofollow_to_user_content: "Add rel nofollow to all submitted user content, except for internal links (including parent domains) changing this requires you update all your baked markdown"
post_excerpt_maxlength: "Maximum length in chars of a post's excerpt." post_excerpt_maxlength: "Maximum length in chars of a post's excerpt."
post_onebox_maxlength: "Maximum length of a oneboxed discourse post." post_onebox_maxlength: "Maximum length of a oneboxed discourse post."
category_post_template: "The post template that appears once you create a category" category_post_template: "The post template that appears once you create a category"

View file

@ -172,7 +172,33 @@ module PrettyText
cloned = opts.dup cloned = opts.dup
# we have a minor inconsistency # we have a minor inconsistency
cloned[:topicId] = opts[:topic_id] cloned[:topicId] = opts[:topic_id]
Sanitize.clean(markdown(text.dup, cloned), PrettyText.whitelist) sanitized = Sanitize.clean(markdown(text.dup, cloned), PrettyText.whitelist)
if SiteSetting.add_rel_nofollow_to_user_content
sanitized = add_rel_nofollow_to_user_content(sanitized)
end
sanitized
end
def self.add_rel_nofollow_to_user_content(html)
site_uri = nil
doc = Nokogiri::HTML.fragment(html)
doc.css("a").each do |l|
href = l["href"].to_s
begin
uri = URI(href)
site_uri ||= URI(Discourse.base_url)
if !uri.host.present? || uri.host.ends_with?(site_uri.host)
# we are good no need for nofollow
else
l["rel"] = "nofollow"
end
rescue URI::InvalidURIError
# add a nofollow anyway
l["rel"] = "nofollow"
end
end
doc.to_html
end end
def self.extract_links(html) def self.extract_links(html)

View file

@ -75,6 +75,24 @@ test
.should == "<pre><code>```\nhello\n```\n</code></pre>" .should == "<pre><code>```\nhello\n```\n</code></pre>"
end end
end end
describe "rel nofollow" do
before do
SiteSetting.stubs(:add_rel_nofollow_to_user_content).returns(true)
end
it "should inject nofollow in all user provided links" do
PrettyText.cook('<a href="http://cnn.com">cnn</a>').should =~ /nofollow/
end
it "should not inject nofollow in all local links" do
(PrettyText.cook("<a href='#{Discourse.base_url}/test.html'>cnn</a>") !~ /nofollow/).should be_true
end
it "should not inject nofollow in all subdomain links" do
(PrettyText.cook("<a href='#{Discourse.base_url.sub('http://', 'http://bla.')}/test.html'>cnn</a>") !~ /nofollow/).should be_true
end
end
describe "Excerpt" do describe "Excerpt" do
it "should preserve links" do it "should preserve links" do
@ -130,6 +148,7 @@ test
end end
end end
describe "apply cdn" do describe "apply cdn" do
it "should detect bare links to images and apply a CDN" do it "should detect bare links to images and apply a CDN" do
PrettyText.apply_cdn("<a href='/hello.png'>hello</a><img src='/a.jpeg'>","http://a.com").should == PrettyText.apply_cdn("<a href='/hello.png'>hello</a><img src='/a.jpeg'>","http://a.com").should ==