require 'active_support/core_ext/class/attribute'
require 'active_support/deprecation'
require 'action_view/helpers/sanitize_helper/scrubbers'
module ActionView
XPATHS_TO_REMOVE = %w{.//script .//form comment()}
class Sanitizer
# :nodoc:
def sanitize(html, options = {})
raise NotImplementedError, "subclasses must implement"
end
def remove_xpaths(html, xpaths)
if html.respond_to?(:xpath)
xpaths.each { |xpath| html.xpath(xpath).remove }
html.to_s
else
remove_xpaths(Loofah.fragment(html), xpaths)
end
end
end
class FullSanitizer < Sanitizer
def sanitize(html, options = {})
return nil unless html
return html if html.empty?
Loofah.fragment(html).tap do |fragment|
remove_xpaths(fragment, XPATHS_TO_REMOVE)
end.text
end
end
class LinkSanitizer < Sanitizer
def initialize
@link_scrubber = TargetScrubber.new
@link_scrubber.tags = %w(a href)
end
def sanitize(html, options = {})
Loofah.scrub_fragment(html, @link_scrubber).to_s
end
end
class WhiteListSanitizer < Sanitizer
def initialize
@permit_scrubber = PermitScrubber.new
end
def sanitize(html, options = {})
return nil unless html
loofah_fragment = Loofah.fragment(html)
if scrubber = options[:scrubber]
# No duck typing, Loofah ensures subclass of Loofah::Scrubber
loofah_fragment.scrub!(scrubber)
elsif options[:tags] || options[:attributes]
@permit_scrubber.tags = options[:tags]
@permit_scrubber.attributes = options[:attributes]
loofah_fragment.scrub!(@permit_scrubber)
else
remove_xpaths(loofah_fragment, XPATHS_TO_REMOVE)
loofah_fragment.scrub!(:strip)
end
loofah_fragment.to_s
end
def sanitize_css(style_string)
Loofah::HTML5::Scrub.scrub_css style_string
end
def protocol_separator
self.class.protocol_separator
end
def protocol_separator=(value)
self.class.protocol_separator
end
def bad_tags
self.class.bad_tags
end
class << self
def protocol_separator
ActiveSupport::Deprecation.warn('protocol_separator has been deprecated and has no effect.')
end
def protocol_separator=(value)
protocol_separator
end
def bad_tags
ActiveSupport::Deprecation.warn('bad_tags has been deprecated and has no effect. You can still affect the tags being sanitized using ActionView::WhiteListSanitizer.bad_tags= which changes the allowed_tags.')
end
def bad_tags=(tags)
allowed_tags.replace(allowed_tags - tags)
end
end
[:uri_attributes, :allowed_attributes,
:allowed_tags, :allowed_protocols, :allowed_css_properties,
:allowed_css_keywords, :shorthand_css_properties].each do |attr|
class_attribute attr, :instance_writer => false
define_method "#{self}.update_#{attr}" do |arg|
attr.merge arg
end
end
# Constants are from Loofahs source at lib/loofah/html5/whitelist.rb
self.uri_attributes = Loofah::HTML5::WhiteList::ATTR_VAL_IS_URI
self.allowed_tags = Loofah::HTML5::WhiteList::ALLOWED_ELEMENTS
self.bad_tags = Set.new %w(script form)
self.allowed_attributes = Loofah::HTML5::WhiteList::ALLOWED_ATTRIBUTES
self.allowed_css_properties = Loofah::HTML5::WhiteList::ALLOWED_CSS_PROPERTIES
self.allowed_css_keywords = Loofah::HTML5::WhiteList::ALLOWED_CSS_KEYWORDS
self.shorthand_css_properties = Loofah::HTML5::WhiteList::SHORTHAND_CSS_PROPERTIES
self.allowed_protocols = Loofah::HTML5::WhiteList::ALLOWED_PROTOCOLS
end
end