ruby-on-railsruby-on-rails-3sanitize

Rails sanitize remove default allowed tags


How would I use sanitize, but tell it to disallow some enabled by default tags? The documentation states that I can put this in my application.rb

config.after_initialize do
  ActionView::Base.sanitized_allowed_tags.delete 'div'
end

Can I instead pass this as an argument to sanitize?


Solution

  • Yes you can specify which tags and attributes to allow on a per-call basis. From the fine manual:

    Custom Use (only the mentioned tags and attributes are allowed, nothing else)

    <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style) %>
    

    But the problem with that is that :tags has to include all the tags you want to allow.

    The sanitize documentation says to

    See ActionView::Base for full docs on the available options.

    but the documentation is a lie, ActionView::Base says nothing about the available options.

    So, as usual, we have to go digging through the source and hope they don't silently change the interface. Tracing through the code a bit yields this:

    def tokenize(text, options)
      options[:parent] = []
      options[:attributes] ||= allowed_attributes
      options[:tags]       ||= allowed_tags
      super
    end
    
    def process_node(node, result, options)
      result << case node
        when HTML::Tag
          if node.closing == :close
            options[:parent].shift
          else
            options[:parent].unshift node.name
          end
    
          process_attributes_for node, options
    
          options[:tags].include?(node.name) ? node : nil
        else
          bad_tags.include?(options[:parent].first) ? nil : node.to_s.gsub(/</, "&lt;")
      end
    end
    

    The default value for options[:tags] in tokenize and the way options[:tags] is used in process_node are of interest and tell us that if options[:tags] has anything then it has to include the entire set of allowed tags and there aren't any other options for controlling the tag set.

    Also, if we look at sanitize_helper.rb, we see that sanitized_allowed_tags is just a wrapper for the allowed_tags in the whitelist sanitizer:

    def sanitized_allowed_tags
      white_list_sanitizer.allowed_tags
    end
    

    You should be able to add your own helper that does something like this (untested off-the-top-of-my-head code):

    def sensible_sanitize(html, options)
      if options.include? :not_tags
        options[:tags] = ActionView::Base.sanitized_allowed_tags - options[:not_tags]
      end
      sanitize html, options
    end
    

    and then you could

    <%= sensible_sanitize @stuff, :not_tags => [ 'div' ] %>
    

    to use the standard default tags except for <div>.