Tuesday, April 12, 2016

Ruby on Rails: Allow less than sign '<' inside code block with sanitize helper

Leave a Comment

I'm trying to escape user generated content in Rails. I have used raw with sanitize and raw helpers to filter content like this:

raw(sanitize(code, :tags =>   ['<', 'h2','h3','p','br','ul','ol','li','code','pre','a'] )) 

The list of tags mentioned are allowed in the content.

The problem is when I try to test it with a sql query like this:

mysql -u sat -p -h localhost database <  data.sql 

inside pre and code blocks it removes everything after the less than (<) sign.

Please help me figure out a way to do this.

4 Answers

Answers 1

I don't believe this is possible using the default sanitize method within Rails.

Instead try using the Sanitize gem (https://github.com/rgrove/sanitize)

require 'sanitize'  allowed_elements = ['h2','h3','p','br','ul','ol','li','code','pre','a'] code             = "<pre>mysql -u sat -p -h localhost database < data.sql</pre>"  Sanitize.fragment(code, elements: allowed_elements) # => <pre>mysql -u sat -p -h localhost database &lt; data.sql</pre> 

To use this to save sanitized content to the database add a before_save filter to you model that runs sanitize on the user generated content and stores the result, e.g.

class MyModel < ActiveRecord::Base    ALLOWED_ELEMENTS = ['h2','h3','p','br','ul','ol','li','code','pre','a']    before_save :sanitize_code    private    def sanitize_code     self.code = Sanitize.fragment(code, elements: ALLOWED_ELEMENTS)   end end 

When you output the content you just need to use the raw view helper e.g.

<%= raw @instance.code %> 

Answers 2

This might help, sanitizer has options to provide white list of tags and attributes needs to ignored during sanitization

ActionView::Base.full_sanitizer.sanitize(html_string) #Basic Syntax 

White list of tags and attributes can be specified as bellow

ActionView::Base.full_sanitizer.sanitize(html_string, :tags => %w(img br p), :attributes => %w(src style)) 

Above statement allows tags: img, br and p and attributes : src and style.

Answers 3

Rails 3 added the html_safe property for every String instance. Every string that is printed or inserted to the database will be escaped unless html_safe is set to true (simplified). What raw does, is actually set html_safe to true. So you should only pass a string that is already safe/escaped.

A possible solution could look something like this:

strip_tags(code).html_safe

You might have to add additional checks / string replacements depending on your use case.

According to your comment, you probably need a little more complex version. You could try to replace all chars that you would like to allow, sanitize the string, and then reverse the replacement in order to avoid that the sanitize method sanitizes more than you actually want. Try something like this:

code = "mysql -u sat -p -h localhost database < data.sql"  ALLOWED_SIGNS = {   :lower_than => "<".html_safe }  s = code.dup ALLOWED_SIGNS.each { |k, v| s.sub!(v, "%{#{k}}") } sanitize(s) % ALLOWED_SIGNS 

Answers 4

It seems like the whole issue was with the way data being stored in the database. Previously, a less than sign '<' was being saved as it is but now it is being escaped so a '<' would be saved as &lt; which seems to have solved the problem.

I was able to understand that accidentally while using tinymce-rails WYSIWYG editor which was escaping the '<' automatically.

@kieran-johnson's answer might have done the same but tinymce-rails solved it without installing an extra gem.

Thank you all of you who took out time to help.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment