Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/actionpack/lib/action_view/helpers/sanitize_helper.rb

Revision 8213, 8.6 kB (checked in by rick, 1 year ago)

Refactor sanitizer helpers into HTML classes and make it easy to swap them out with custom implementations. Closes #10129. [rick]

Line 
1 require 'action_view/helpers/tag_helper'
2 require 'html/document'
3
4 module ActionView
5   module Helpers #:nodoc:
6     # The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements.
7     # These helper methods extend ActionView making them callable within your template files.
8     module SanitizeHelper
9       def self.included(base)
10         base.extend(ClassMethods)
11       end
12      
13       # This #sanitize helper will html encode all tags and strip all attributes that aren't specifically allowed. 
14       # It also strips href/src tags with invalid protocols, like javascript: especially.  It does its best to counter any
15       # tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters.  Check out
16       # the extensive test suite.
17       #
18       #   <%= sanitize @article.body %>
19       #
20       # You can add or remove tags/attributes if you want to customize it a bit.  See ActionView::Base for full docs on the
21       # available options.  You can add tags/attributes for single uses of #sanitize by passing either the :attributes or :tags options:
22       #
23       # Normal Use
24       #
25       #   <%= sanitize @article.body %>
26       #
27       # Custom Use (only the mentioned tags and attributes are allowed, nothing else)
28       #
29       #   <%= sanitize @article.body, :tags => %w(table tr td), :attributes => %w(id class style)
30       #
31       # Add table tags to the default allowed tags
32       #   
33       #   Rails::Initializer.run do |config|
34       #     config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
35       #   end
36       #
37       # Remove tags to the default allowed tags
38       #   
39       #   Rails::Initializer.run do |config|
40       #     config.after_initialize do
41       #       ActionView::Base.sanitized_allowed_tags.delete 'div'
42       #     end
43       #   end
44       #
45       # Change allowed default attributes
46       #
47       #   Rails::Initializer.run do |config|
48       #     config.action_view.sanitized_allowed_attributes = 'id', 'class', 'style'
49       #   end
50       #
51       def sanitize(html, options = {})
52         self.class.white_list_sanitizer.sanitize(html, options)
53       end
54
55       # Sanitizes a block of css code.  Used by #sanitize when it comes across a style attribute
56       def sanitize_css(style)
57         self.class.white_list_sanitizer.sanitize_css(style)
58       end
59
60       # Strips all HTML tags from the +html+, including comments.  This uses the
61       # html-scanner tokenizer and so its HTML parsing ability is limited by
62       # that of html-scanner.
63       #
64       # ==== Examples
65       #
66       #   strip_tags("Strip <i>these</i> tags!")
67       #   # => Strip these tags!
68       #
69       #   strip_tags("<b>Bold</b> no more!  <a href='more.html'>See more here</a>...")
70       #   # => Bold no more!  See more here...
71       #
72       #   strip_tags("<div id='top-bar'>Welcome to my website!</div>")
73       #   # => Welcome to my website!
74       def strip_tags(html)     
75         self.class.full_sanitizer.sanitize(html)
76       end
77
78       # Strips all link tags from +text+ leaving just the link text.
79       #
80       # ==== Examples
81       #   strip_links('<a href="Ruby">http://www.rubyonrails.org">Ruby on Rails</a>')
82       #   # => Ruby on Rails
83       #
84       #   strip_links('Please e-mail me at <a href="mailto:me@email.com">me@email.com</a>.')
85       #   # => Please e-mail me at me@email.com.
86       #
87       #   strip_links('Blog: <a href="http://www.myblog.com/" class="nav" target=\"_blank\">Visit</a>.')
88       #   # => Blog: Visit
89       def strip_links(html)
90         self.class.link_sanitizer.sanitize(html)
91       end
92
93       module ClassMethods #:nodoc:
94         def self.extended(base)
95           class << base
96             attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
97
98             # we want these to be class methods on ActionView::Base, they'll get mattr_readers for these below.
99             helper_def = [:sanitized_protocol_separator, :sanitized_uri_attributes, :sanitized_bad_tags, :sanitized_allowed_tags,
100                 :sanitized_allowed_attributes, :sanitized_allowed_css_properties, :sanitized_allowed_css_keywords,
101                 :sanitized_shorthand_css_properties, :sanitized_allowed_protocols, :sanitized_protocol_separator=].collect! do |prop|
102               prop = prop.to_s
103               "def #{prop}(#{:value if prop =~ /=$/}) white_list_sanitizer.#{prop.sub /sanitized_/, ''} #{:value if prop =~ /=$/} end"
104             end.join("\n")
105             eval helper_def
106           end
107         end
108        
109         # Gets the HTML::FullSanitizer instance used by strip_tags.  Replace with
110         # any object that responds to #sanitize
111         #
112         #   Rails::Initializer.run do |config|
113         #     config.action_view.full_sanitizer = MySpecialSanitizer.new
114         #   end
115         #
116         def full_sanitizer
117           @full_sanitizer ||= HTML::FullSanitizer.new
118         end
119
120         # Gets the HTML::LinkSanitizer instance used by strip_links.  Replace with
121         # any object that responds to #sanitize
122         #
123         #   Rails::Initializer.run do |config|
124         #     config.action_view.link_sanitizer = MySpecialSanitizer.new
125         #   end
126         #
127         def link_sanitizer
128           @link_sanitizer ||= HTML::LinkSanitizer.new
129         end
130
131         # Gets the HTML::WhiteListSanitizer instance used by sanitize and sanitize_css.
132         # Replace with any object that responds to #sanitize
133         #
134         #   Rails::Initializer.run do |config|
135         #     config.action_view.white_list_sanitizer = MySpecialSanitizer.new
136         #   end
137         #
138         def white_list_sanitizer
139           @white_list_sanitizer ||= HTML::WhiteListSanitizer.new
140         end
141
142         # Adds valid HTML attributes that the #sanitize helper checks for URIs.
143         #
144         #   Rails::Initializer.run do |config|
145         #     config.action_view.sanitized_uri_attributes = 'lowsrc', 'target'
146         #   end
147         #
148         def sanitized_uri_attributes=(attributes)
149           HTML::WhiteListSanitizer.uri_attributes.merge(attributes)
150         end
151
152         # Adds to the Set of 'bad' tags for the #sanitize helper.
153         #
154         #   Rails::Initializer.run do |config|
155         #     config.action_view.sanitized_bad_tags = 'embed', 'object'
156         #   end
157         #
158         def sanitized_bad_tags=(attributes)
159           HTML::WhiteListSanitizer.bad_tags.merge(attributes)
160         end
161         # Adds to the Set of allowed tags for the #sanitize helper.
162         #
163         #   Rails::Initializer.run do |config|
164         #     config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
165         #   end
166         #
167         def sanitized_allowed_tags=(attributes)
168           HTML::WhiteListSanitizer.allowed_tags.merge(attributes)
169         end
170
171         # Adds to the Set of allowed html attributes for the #sanitize helper.
172         #
173         #   Rails::Initializer.run do |config|
174         #     config.action_view.sanitized_allowed_attributes = 'onclick', 'longdesc'
175         #   end
176         #
177         def sanitized_allowed_attributes=(attributes)
178           HTML::WhiteListSanitizer.allowed_attributes.merge(attributes)
179         end
180
181         # Adds to the Set of allowed css properties for the #sanitize and #sanitize_css heleprs.
182         #
183         #   Rails::Initializer.run do |config|
184         #     config.action_view.sanitized_allowed_css_properties = 'expression'
185         #   end
186         #
187         def sanitized_allowed_css_properties=(attributes)
188           HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes)
189         end
190
191         # Adds to the Set of allowed css keywords for the #sanitize and #sanitize_css helpers.
192         #
193         #   Rails::Initializer.run do |config|
194         #     config.action_view.sanitized_allowed_css_keywords = 'expression'
195         #   end
196         #
197         def sanitized_allowed_css_keywords=(attributes)
198           HTML::WhiteListSanitizer.allowed_css_keywords.merge(attributes)
199         end
200
201         # Adds to the Set of allowed shorthand css properties for the #sanitize and #sanitize_css helpers.
202         #
203         #   Rails::Initializer.run do |config|
204         #     config.action_view.sanitized_shorthand_css_properties = 'expression'
205         #   end
206         #
207         def sanitized_shorthand_css_properties=(attributes)
208           HTML::WhiteListSanitizer.shorthand_css_properties.merge(attributes)
209         end
210
211         # Adds to the Set of allowed protocols for the #sanitize helper.
212         #
213         #   Rails::Initializer.run do |config|
214         #     config.action_view.sanitized_allowed_protocols = 'ssh', 'feed'
215         #   end
216         #
217         def sanitized_allowed_protocols=(attributes)
218           HTML::WhiteListSanitizer.allowed_protocols.merge(attributes)
219         end
220       end
221     end
222   end
223 end
Note: See TracBrowser for help on using the browser.