module Rails module HTML class Scrubber CONTINUE = Object.new.freeze attr_accessor :tags, :attributes attr_reader :prune def initialize(**) end def scrub(node) = CONTINUE end PermitScrubber = Scrubber TargetScrubber = Scrubber TextOnlyScrubber = Scrubber class Sanitizer class << self def html5_support? = true def best_supported_vendor = NullSanitizer end end module Concern module SafeList # The default safe list for tags DEFAULT_ALLOWED_TAGS = Set.new([ "a", "abbr", "acronym", "address", "b", "big", "blockquote", "br", "cite", "code", "dd", "del", "dfn", "div", "dl", "dt", "em", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "i", "img", "ins", "kbd", "li", "mark", "ol", "p", "pre", "samp", "small", "span", "strong", "sub", "sup", "time", "tt", "ul", "var", ]).freeze # The default safe list for attributes DEFAULT_ALLOWED_ATTRIBUTES = Set.new([ "abbr", "alt", "cite", "class", "datetime", "height", "href", "lang", "name", "src", "title", "width", "xml:lang", ]).freeze def self.included(klass) class << klass attr_accessor :allowed_tags attr_accessor :allowed_attributes end klass.allowed_tags = DEFAULT_ALLOWED_TAGS.dup klass.allowed_attributes = DEFAULT_ALLOWED_ATTRIBUTES.dup end def initialize(prune: false) @permit_scrubber = PermitScrubber.new(prune: prune) end def scrub(fragment, options = {}) if scrubber = options[:scrubber] # No duck typing, Loofah ensures subclass of Loofah::Scrubber fragment.scrub!(scrubber) elsif allowed_tags(options) || allowed_attributes(options) @permit_scrubber.tags = allowed_tags(options) @permit_scrubber.attributes = allowed_attributes(options) fragment.scrub!(@permit_scrubber) else fragment.scrub!(:strip) end end def sanitize_css(style_string) Loofah::HTML5::Scrub.scrub_css(style_string) end private def allowed_tags(options) options[:tags] || self.class.allowed_tags end def allowed_attributes(options) options[:attributes] || self.class.allowed_attributes end end end # TODO: That should be a real sanitizer (backed by JS or another external interface) class NullSanitizer class << self def safe_list_sanitizer = self end def sanitize(html, ...) = html def sanitize_css(style) = style end end module HTML4 Sanitizer = HTML::NullSanitizer FullSanitizer = Sanitizer LinkSanitizer = Sanitizer class SafeListSanitizer < Sanitizer include HTML::Concern::SafeList end end Html = HTML module HTML FullSanitizer = HTML4::FullSanitizer LinkSanitizer = HTML4::LinkSanitizer SafeListSanitizer = HTML4::SafeListSanitizer WhiteListSanitizer = SafeListSanitizer end end