diff --git a/CHANGELOG.md b/CHANGELOG.md
index d6399fb..593b4e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+## next / unreleased
+
+* `SafeListSanitizer`, `PermitScrubber`, and `TargetScrubber` now all support pruning of unsafe tags.
+
+ By default, unsafe tags are still stripped, but this behavior can be changed to prune the element
+ and its children from the document by passing `prune: true` to any of these classes' constructors.
+
+ *seyrian*
+
## 1.4.2 / 2021-08-23
* Slightly improve performance.
diff --git a/README.md b/README.md
index af42d58..b6d368c 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,9 @@ safe_list_sanitizer.sanitize(@article.body, scrubber: ArticleScrubber.new)
# safe list sanitizer can also sanitize css
safe_list_sanitizer.sanitize_css('background-color: #000;')
+
+# fully prune nodes from the tree instead of stripping tags and leaving inner content
+safe_list_sanitizer = Rails::Html::SafeListSanitizer.new(prune: true)
```
### Scrubbers
@@ -107,6 +110,24 @@ html_fragment.scrub!(scrubber)
html_fragment.to_s # => ""
```
+By default, inner content is left, but it can be removed as well.
+
+```ruby
+scrubber = Rails::Html::PermitScrubber.new
+scrubber.tags = ['a']
+
+html_fragment = Loofah.fragment('text')
+html_fragment.scrub!(scrubber)
+html_fragment.to_s # => "text"
+
+scrubber = Rails::Html::PermitScrubber.new(prune: true)
+scrubber.tags = ['a']
+
+html_fragment = Loofah.fragment('text')
+html_fragment.scrub!(scrubber)
+html_fragment.to_s # => ""
+```
+
#### `Rails::Html::TargetScrubber`
Where `PermitScrubber` picks out tags and attributes to permit in sanitization,
@@ -124,6 +145,23 @@ html_fragment.scrub!(scrubber)
html_fragment.to_s # => ""
```
+Similarly to `PermitScrubber`, nodes can be fully pruned.
+
+```ruby
+scrubber = Rails::Html::TargetScrubber.new
+scrubber.tags = ['span']
+
+html_fragment = Loofah.fragment('text')
+html_fragment.scrub!(scrubber)
+html_fragment.to_s # => "text"
+
+scrubber = Rails::Html::TargetScrubber.new(prune: true)
+scrubber.tags = ['span']
+
+html_fragment = Loofah.fragment('text')
+html_fragment.scrub!(scrubber)
+html_fragment.to_s # => ""
+```
#### Custom Scrubbers
You can also create custom scrubbers in your application if you want to.
diff --git a/lib/rails/html/sanitizer.rb b/lib/rails/html/sanitizer.rb
index 5633ca1..ffd6764 100644
--- a/lib/rails/html/sanitizer.rb
+++ b/lib/rails/html/sanitizer.rb
@@ -110,8 +110,8 @@ class << self
acronym a img blockquote del ins))
self.allowed_attributes = Set.new(%w(href src width height alt cite datetime title class name xml:lang abbr))
- def initialize
- @permit_scrubber = PermitScrubber.new
+ def initialize(prune: false)
+ @permit_scrubber = PermitScrubber.new(prune: prune)
end
def sanitize(html, options = {})
diff --git a/lib/rails/html/scrubbers.rb b/lib/rails/html/scrubbers.rb
index 09cfe95..13b6d6f 100644
--- a/lib/rails/html/scrubbers.rb
+++ b/lib/rails/html/scrubbers.rb
@@ -45,10 +45,11 @@ module Html
# See the documentation for +Nokogiri::XML::Node+ to understand what's possible
# with nodes: https://nokogiri.org/rdoc/Nokogiri/XML/Node.html
class PermitScrubber < Loofah::Scrubber
- attr_reader :tags, :attributes
+ attr_reader :tags, :attributes, :prune
- def initialize
- @direction = :bottom_up
+ def initialize(prune: false)
+ @prune = prune
+ @direction = @prune ? :top_down : :bottom_up
@tags, @attributes = nil, nil
end
@@ -98,7 +99,7 @@ def keep_node?(node)
end
def scrub_node(node)
- node.before(node.children) # strip
+ node.before(node.children) unless prune # strip
node.remove
end
diff --git a/test/sanitizer_test.rb b/test/sanitizer_test.rb
index 8b0b7ab..23f41e1 100644
--- a/test/sanitizer_test.rb
+++ b/test/sanitizer_test.rb
@@ -258,6 +258,12 @@ def test_custom_attributes_overrides_allowed_attributes
end
end
+ def test_should_allow_prune
+ sanitizer = Rails::Html::SafeListSanitizer.new(prune: true)
+ text = 'leave me now'
+ assert_equal "leave me ", sanitizer.sanitize(text, tags: %w(u))
+ end
+
def test_should_allow_custom_tags
text = "foo"
assert_equal text, safe_list_sanitize(text, tags: %w(u))
diff --git a/test/scrubbers_test.rb b/test/scrubbers_test.rb
index a825404..a86536e 100644
--- a/test/scrubbers_test.rb
+++ b/test/scrubbers_test.rb
@@ -66,6 +66,13 @@ def test_leaves_only_supplied_tags
assert_scrubbed html, '