Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add noreferrer scrubber #277

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ doc.scrub!(:whitewash) # removes unknown/unsafe/namespaced tags and their chi
Loofah also comes with some common transformation tasks:

``` ruby
doc.scrub!(:nofollow) # adds rel="nofollow" attribute to links
doc.scrub!(:nofollow) # adds rel="nofollow" attribute to links
doc.scrub!(:noopener) # adds rel="noopener" attribute to links
doc.scrub!(:noreferrer) # adds rel="noreferrer" attribute to links
doc.scrub!(:unprintable) # removes unprintable characters from text nodes
doc.scrub!(:targetblank) # adds target="_blank" attribute to links
```
Expand Down
31 changes: 31 additions & 0 deletions lib/loofah/scrubbers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ module Loofah
# Loofah.html5_fragment(link_farmers_markup).scrub!(:noopener)
# => "ohai! <a href='http://www.myswarmysite.com/' rel="noopener">I like your blog post</a>"
#
# === Loofah::Scrubbers::NoReferrer / scrub!(:noreferrer)
#
# +:noreferrer+ adds a rel="noreferrer" attribute to all links
#
# link_farmers_markup = "ohai! <a href='http://www.myswarmysite.com/'>I like your blog post</a>"
# Loofah.html5_fragment(link_farmers_markup).scrub!(:noreferrer)
# => "ohai! <a href='http://www.myswarmysite.com/' rel="noreferrer">I like your blog post</a>"
#
#
# === Loofah::Scrubbers::Unprintable / scrub!(:unprintable)
#
Expand Down Expand Up @@ -271,6 +279,28 @@ def scrub(node)
end
end

#
# === scrub!(:noreferrer)
#
# +:noreferrer+ adds a rel="noreferrer" attribute to all links
#
# link_farmers_markup = "ohai! <a href='http://www.myswarmysite.com/'>I like your blog post</a>"
# Loofah.html5_fragment(link_farmers_markup).scrub!(:noreferrer)
# => "ohai! <a href='http://www.myswarmysite.com/' rel="noreferrer">I like your blog post</a>"
#
class NoReferrer < Scrubber
def initialize # rubocop:disable Lint/MissingSuper
@direction = :top_down
end

def scrub(node)
return CONTINUE unless (node.type == Nokogiri::XML::Node::ELEMENT_NODE) && (node.name == "a")

append_attribute(node, "rel", "noreferrer")
STOP
end
end

# This class probably isn't useful publicly, but is used for #to_text's current implemention
class NewlineBlockElements < Scrubber # :nodoc:
def initialize # rubocop:disable Lint/MissingSuper
Expand Down Expand Up @@ -328,6 +358,7 @@ def scrub(node)
strip: Strip,
nofollow: NoFollow,
noopener: NoOpener,
noreferrer: NoReferrer,
targetblank: TargetBlank,
newline_block_elements: NewlineBlockElements,
unprintable: Unprintable,
Expand Down
28 changes: 28 additions & 0 deletions test/integration/test_scrubbers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class IntegrationTestScrubbers < Loofah::TestCase
NOOPENER_WITH_REL_FRAGMENT = '<a href="http://www.example.com/" rel="nofollow">Click here</a>'
NOOPENER_WITH_REL_RESULT = '<a href="http://www.example.com/" rel="nofollow noopener">Click here</a>'

NOREFERRER_FRAGMENT = '<a href="http://www.example.com/">Click here</a>'
NOREFERRER_RESULT = '<a href="http://www.example.com/" rel="noreferrer">Click here</a>'

NOREFERRER_WITH_REL_FRAGMENT = '<a href="http://www.example.com/" rel="noopener">Click here</a>'
NOREFERRER_WITH_REL_RESULT = '<a href="http://www.example.com/" rel="noopener noreferrer">Click here</a>'

UNPRINTABLE_FRAGMENT = "<b>Lo\u2029ofah ro\u2028cks!</b><script>x\u2028y</script>"
UNPRINTABLE_RESULT = "<b>Loofah rocks!</b><script>xy</script>"

Expand Down Expand Up @@ -443,6 +449,28 @@ def html5?
end
end

context ":noreferrer" do
context "for a hyperlink without a 'rel' attribute" do
it "add a 'noreferrer' attribute to hyperlinks" do
doc = klass.parse("<div>#{NOREFERRER_FRAGMENT}</div>")
result = doc.scrub!(:noreferrer)

assert_equal NOREFERRER_RESULT, doc.xpath("./div").inner_html
assert_equal doc, result
end
end

context "for a hyperlink that does have a rel attribute" do
it "appends 'noreferrer' to 'rel' attribute" do
doc = klass.parse("<div>#{NOREFERRER_WITH_REL_FRAGMENT}</div>")
result = doc.scrub!(:noreferrer)

assert_equal NOREFERRER_WITH_REL_RESULT, doc.xpath("./div").inner_html
assert_equal doc, result
end
end
end

context ":unprintable" do
it "removes unprintable unicode characters" do
doc = klass.parse("<div>#{UNPRINTABLE_FRAGMENT}</div>")
Expand Down