From 83f6d9310656430104a2bdcf81b25d0063fd951d Mon Sep 17 00:00:00 2001 From: Fabian Winkler <> Date: Wed, 8 Nov 2023 14:09:01 +0100 Subject: [PATCH] Add noreferrer scrubber --- README.md | 4 +++- lib/loofah/scrubbers.rb | 31 ++++++++++++++++++++++++++++++ test/integration/test_scrubbers.rb | 28 +++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 69767b2..47256de 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,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 ``` diff --git a/lib/loofah/scrubbers.rb b/lib/loofah/scrubbers.rb index 6823018..8d2f27a 100644 --- a/lib/loofah/scrubbers.rb +++ b/lib/loofah/scrubbers.rb @@ -69,6 +69,14 @@ module Loofah # Loofah.html5_fragment(link_farmers_markup).scrub!(:noopener) # => "ohai! I like your blog post" # + # === Loofah::Scrubbers::NoReferrer / scrub!(:noreferrer) + # + # +:noreferrer+ adds a rel="noreferrer" attribute to all links + # + # link_farmers_markup = "ohai! I like your blog post" + # Loofah.html5_fragment(link_farmers_markup).scrub!(:noreferrer) + # => "ohai! I like your blog post" + # # # === Loofah::Scrubbers::Unprintable / scrub!(:unprintable) # @@ -235,6 +243,28 @@ def scrub(node) end end + # + # === scrub!(:noreferrer) + # + # +:noreferrer+ adds a rel="noreferrer" attribute to all links + # + # link_farmers_markup = "ohai! I like your blog post" + # Loofah.html5_fragment(link_farmers_markup).scrub!(:noreferrer) + # => "ohai! I like your blog post" + # + 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 @@ -292,6 +322,7 @@ def scrub(node) strip: Strip, nofollow: NoFollow, noopener: NoOpener, + noreferrer: NoReferrer, newline_block_elements: NewlineBlockElements, unprintable: Unprintable, } diff --git a/test/integration/test_scrubbers.rb b/test/integration/test_scrubbers.rb index b1dc67d..7285f17 100644 --- a/test/integration/test_scrubbers.rb +++ b/test/integration/test_scrubbers.rb @@ -25,6 +25,12 @@ class IntegrationTestScrubbers < Loofah::TestCase NOOPENER_WITH_REL_FRAGMENT = 'Click here' NOOPENER_WITH_REL_RESULT = 'Click here' + NOREFERRER_FRAGMENT = 'Click here' + NOREFERRER_RESULT = 'Click here' + + NOREFERRER_WITH_REL_FRAGMENT = 'Click here' + NOREFERRER_WITH_REL_RESULT = 'Click here' + UNPRINTABLE_FRAGMENT = "Lo\u2029ofah ro\u2028cks!" UNPRINTABLE_RESULT = "Loofah rocks!" @@ -415,6 +421,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("
#{NOREFERRER_FRAGMENT}
") + 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("
#{NOREFERRER_WITH_REL_FRAGMENT}
") + 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("
#{UNPRINTABLE_FRAGMENT}
")