Skip to content

Commit

Permalink
Add noreferrer scrubber
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabian Winkler authored and flavorjones committed Nov 13, 2023
1 parent 5345bb7 commit 4ad2e13
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 1 deletion.
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

0 comments on commit 4ad2e13

Please sign in to comment.