aboutsummaryrefslogtreecommitdiffstats
path: root/actionview/lib/action_view/helpers/sanitize_helper.rb
blob: a4d796d13884dc193374b9d9ce3d688e16d38f18 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# frozen_string_literal: true

require "rails-html-sanitizer"

module ActionView
  # = Action View Sanitize Helpers
  module Helpers #:nodoc:
    # The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements.
    # These helper methods extend Action View making them callable within your template files.
    module SanitizeHelper
      extend ActiveSupport::Concern
      # Sanitizes HTML input, stripping all but known-safe tags and attributes.
      #
      # It also strips href/src attributes with unsafe protocols like
      # <tt>javascript:</tt>, while also protecting against attempts to use Unicode,
      # ASCII, and hex character references to work around these protocol filters.
      # All special characters will be escaped.
      #
      # The default sanitizer is Rails::Html::SafeListSanitizer. See {Rails HTML
      # Sanitizers}[https://github.com/rails/rails-html-sanitizer] for more information.
      #
      # Custom sanitization rules can also be provided.
      #
      # Please note that sanitizing user-provided text does not guarantee that the
      # resulting markup is valid or even well-formed.
      #
      # ==== Options
      #
      # * <tt>:tags</tt> - An array of allowed tags.
      # * <tt>:attributes</tt> - An array of allowed attributes.
      # * <tt>:scrubber</tt> - A {Rails::Html scrubber}[https://github.com/rails/rails-html-sanitizer]
      #   or {Loofah::Scrubber}[https://github.com/flavorjones/loofah] object that
      #   defines custom sanitization rules. A custom scrubber takes precedence over
      #   custom tags and attributes.
      #
      # ==== Examples
      #
      # Normal use:
      #
      #   <%= sanitize @comment.body %>
      #
      # Providing custom lists of permitted tags and attributes:
      #
      #   <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
      #
      # Providing a custom Rails::Html scrubber:
      #
      #   class CommentScrubber < Rails::Html::PermitScrubber
      #     def initialize
      #       super
      #       self.tags = %w( form script comment blockquote )
      #       self.attributes = %w( style )
      #     end
      #
      #     def skip_node?(node)
      #       node.text?
      #     end
      #   end
      #
      #   <%= sanitize @comment.body, scrubber: CommentScrubber.new %>
      #
      # See {Rails HTML Sanitizer}[https://github.com/rails/rails-html-sanitizer] for
      # documentation about Rails::Html scrubbers.
      #
      # Providing a custom Loofah::Scrubber:
      #
      #   scrubber = Loofah::Scrubber.new do |node|
      #     node.remove if node.name == 'script'
      #   end
      #
      #   <%= sanitize @comment.body, scrubber: scrubber %>
      #
      # See {Loofah's documentation}[https://github.com/flavorjones/loofah] for more
      # information about defining custom Loofah::Scrubber objects.
      #
      # To set the default allowed tags or attributes across your application:
      #
      #   # In config/application.rb
      #   config.action_view.sanitized_allowed_tags = ['strong', 'em', 'a']
      #   config.action_view.sanitized_allowed_attributes = ['href', 'title']
      def sanitize(html, options = {})
        self.class.safe_list_sanitizer.sanitize(html, options)&.html_safe
      end

      # Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
      def sanitize_css(style)
        self.class.safe_list_sanitizer.sanitize_css(style)
      end

      # Strips all HTML tags from +html+, including comments and special characters.
      #
      #   strip_tags("Strip <i>these</i> tags!")
      #   # => Strip these tags!
      #
      #   strip_tags("<b>Bold</b> no more!  <a href='more.html'>See more here</a>...")
      #   # => Bold no more!  See more here...
      #
      #   strip_tags("<div id='top-bar'>Welcome to my website!</div>")
      #   # => Welcome to my website!
      #
      #   strip_tags("> A quote from Smith & Wesson")
      #   # => &gt; A quote from Smith &amp; Wesson
      def strip_tags(html)
        self.class.full_sanitizer.sanitize(html)
      end

      # Strips all link tags from +html+ leaving just the link text.
      #
      #   strip_links('<a href="http://www.rubyonrails.org">Ruby on Rails</a>')
      #   # => Ruby on Rails
      #
      #   strip_links('Please e-mail me at <a href="mailto:me@email.com">me@email.com</a>.')
      #   # => Please e-mail me at me@email.com.
      #
      #   strip_links('Blog: <a href="http://www.myblog.com/" class="nav" target=\"_blank\">Visit</a>.')
      #   # => Blog: Visit.
      #
      #   strip_links('<<a href="https://example.org">malformed & link</a>')
      #   # => &lt;malformed &amp; link
      def strip_links(html)
        self.class.link_sanitizer.sanitize(html)
      end

      module ClassMethods #:nodoc:
        attr_writer :full_sanitizer, :link_sanitizer, :safe_list_sanitizer

        def sanitized_allowed_tags
          safe_list_sanitizer.allowed_tags
        end

        def sanitized_allowed_attributes
          safe_list_sanitizer.allowed_attributes
        end

        # Gets the Rails::Html::FullSanitizer instance used by +strip_tags+. Replace with
        # any object that responds to +sanitize+.
        #
        #   class Application < Rails::Application
        #     config.action_view.full_sanitizer = MySpecialSanitizer.new
        #   end
        def full_sanitizer
          @full_sanitizer ||= Rails::Html::Sanitizer.full_sanitizer.new
        end

        # Gets the Rails::Html::LinkSanitizer instance used by +strip_links+.
        # Replace with any object that responds to +sanitize+.
        #
        #   class Application < Rails::Application
        #     config.action_view.link_sanitizer = MySpecialSanitizer.new
        #   end
        def link_sanitizer
          @link_sanitizer ||= Rails::Html::Sanitizer.link_sanitizer.new
        end

        # Gets the Rails::Html::SafeListSanitizer instance used by sanitize and +sanitize_css+.
        # Replace with any object that responds to +sanitize+.
        #
        #   class Application < Rails::Application
        #     config.action_view.safe_list_sanitizer = MySpecialSanitizer.new
        #   end
        def safe_list_sanitizer
          @safe_list_sanitizer ||= Rails::Html::Sanitizer.safe_list_sanitizer.new
        end
      end
    end
  end
end