PandyZhao
PandyZhao

Reputation: 137

Rails HTML Permit Sanitizer Not Working As I Expected

I’ve been stuck trying to figure out how to use the Rails sanitizer. It doesn’t seem to be working as I expected. Think I’m misunderstanding something.

Basically, I'm trying to sanitize all divs except divs that have an attribute that have a value of highlight. But for example's sake, I tried to use PermitScrubber on it's own.

I set my tags and attributes and am inheriting from PermitScrubber, but it scrubs my permitted tags and attributes anyway:

class ExampleScrubber < Rails::Html::PermitScrubber
  def initialize
    super
    self.tags = %w(img),
    self.attributes = %w(src alt)
  end

  # commented out for the example, but what I'm trying to ultimately do
  # def allowed_node?(node)
    # node.name == "div" && node.attributes.values.first.value = "highlight"
  # end
end

@comment.body = "<ul>\n<li>yes</li>\n<li>tests</li>\n</ul>\n\n<p><img src=\"something.jpeg\" alt=\"something\"></p>\n"
ActionController::Base.helpers.sanitize(
  @comment.body,
  scrubber: ExampleScrubber.new
)
#=> "\nyes\ntests\n\n\n\n"

So two things: 1. Why is scrubbing the img tag and src and alt attributes? 2. I know I could refactor the allowed_node? method, but I want to figure out number one first.

Thanks for reading ✌️

Upvotes: 0

Views: 722

Answers (1)

Simple Lime
Simple Lime

Reputation: 11035

The first problem ("Why is [this] scrubbing the img tag and src and alt attributes?") is caused by the stray comma after the array.

#             Here v
self.tags = %w(img),

TIL Ruby doesn't require the square brackets for arrays:

a = "b", "c" # => ["b", "c"]

So, that comma is turning your tags into an array of arrays:

ExampleScrubber.new.tags # => [["img"], ["src", "alt"]]

Which is causing issues and allowing the tag to be scrubbed. Removing the comma causes things to work correctly:

class ExampleScrubber < Rails::Html::PermitScrubber
  def initialize
    super
    self.tags = %w(img)
    self.attributes = %w(src alt)
  end

  # commented out for the example, but what I'm trying to ultimately do
  # def allowed_node?(node)
    # node.name == "div" && node.attributes.values.first.value = "highlight"
  # end
end

body = "<ul>\n<li>yes</li>\n<li>tests</li>\n</ul>\n\n<p><img src=\"something.jpeg\" alt=\"something\"></p>\n"
ActionController::Base.helpers.sanitize(body, scrubber: ExampleScrubber.new)
# => "\nyes\ntests\n\n\n<img src=\"something.jpeg\" alt=\"something\">\n"

So to accomplish your goal, to only keep divs and only if they have an attribute (any attribute) including the word 'highlight' you might try something like:

class ExampleScrubber < Rails::Html::PermitScrubber
  def initialize
    super
    self.tags = %w( div )
  end

  def allowed_node?(node)
    @tags.include?(node.name) && node.attributes.values.any? do |attribute_value|
      attribute_value.value.include?('highlight')
    end
  end
end

body = "<ul>\n<li class='highlight'>yes</li>\n<li>tests</li>\n</ul>\n\n<p><img src=\"something.jpeg\" alt=\"something\"></p>\n<div class='highlight'>Something</div><div>Else</div>"
results = ActionController::Base.helpers.sanitize(body, scrubber: ExampleScrubber.new)
# => "\nyes\ntests\n\n\n\n<div class=\"highlight\">Something</div>Else"

Upvotes: 2

Related Questions