aboutsummaryrefslogtreecommitdiffstats
path: root/actionview/lib/action_view/helpers/sanitize_helper/sanitizers.rb
blob: 99d4e64346bf4b9c670f5a01fabcf13213fae7c2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
require 'active_support/core_ext/class/attribute'
require 'active_support/deprecation'
require 'action_view/helpers/sanitize_helper/permit_scrubber'

module ActionView
  class Sanitizer
    # :nodoc:
    def sanitize(html, options = {})
      raise NotImplementedError, "subclasses must implement"
    end

    def remove_xpaths(html, xpaths)
      html = Loofah.fragment(html) unless html.is_a? Nokogiri::XML::DocumentFragment
      xpaths.each do |xpath|
        html.xpath(xpath).each { |subtree| subtree.remove }
      end
      html.to_s
    end
  end

  class FullSanitizer < Sanitizer
    def sanitize(html, options = {})
      return nil unless html
      return html if html.empty?

      fragment = Loofah.fragment(html)
      remove_xpaths(fragment, %w{.//script .//form comment()})
      fragment.text
    end
  end

  class LinkSanitizer < Sanitizer
    def initialize
      @strip_tags = %w(a href)
      @link_scrubber = Loofah::Scrubber.new do |node|
        if @strip_tags.include?(node.name)
          node.before node.children
          node.remove
        else
          Loofah::HTML5::Scrub.scrub_attributes(node)
        end
      end
    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, %w{.//script .//form comment()})
        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