From 4ad2e135dbbe359b1311953838eb1ee171eb0d04 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 9774e77..e3129fd 100644 --- a/README.md +++ b/README.md @@ -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 ``` diff --git a/lib/loofah/scrubbers.rb b/lib/loofah/scrubbers.rb index c6cc0a7..9dd8869 100644 --- a/lib/loofah/scrubbers.rb +++ b/lib/loofah/scrubbers.rb @@ -78,6 +78,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) # @@ -271,6 +279,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 @@ -328,6 +358,7 @@ def scrub(node) strip: Strip, nofollow: NoFollow, noopener: NoOpener, + noreferrer: NoReferrer, targetblank: TargetBlank, newline_block_elements: NewlineBlockElements, unprintable: Unprintable, diff --git a/test/integration/test_scrubbers.rb b/test/integration/test_scrubbers.rb index 6480ac4..b9401b6 100644 --- a/test/integration/test_scrubbers.rb +++ b/test/integration/test_scrubbers.rb @@ -31,6 +31,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!" @@ -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("
#{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}
")