Rails is saving a title with 'Hello &' as 'Hello &' why? - ruby-on-rails

I have a model with a title field. When I post to the server I see:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"3Le7aLitPd6MzWFeB0ofI9wk1IuhybNswjG9N+KgJJc=", "poll"=>{"title"=>"Hello &"}}
Problem is the DB is then saving as:
Hello &
So later when I output the field on the site it shows up as Hello &
What is the right way to handle this? I want entering & to be supported but at the same time not allow users to submit html or js tags.
Thanks

Sanitize.clean outputs HTML, not plain text so of course your ampersands are converted to their HTML entity form (i.e. &). For example, straight from the the fine manual:
Sanitize.clean(html, Sanitize::Config::RESTRICTED) # => '<b>foo</b>'
So you are, in fact, store HTML snippets rather than pieces of plain text. You should be using
<%= raw #thing.title %>
to display your titles as they have already been rendered HTML-safe by Sanitize.

Related

Capybara - assert against string containing HTML entities?

In a page on my Rails 6 app, I have table cells rendered from the database, and sometimes the text in them is rendered with converted fancy quotes or other HTML entities encoded by our own t method, which does this:
def t(sanitize = true)
Textile.textilize_without_paragraph_safe(self, false, sanitize)
end
It's used like this:
<span class="current_notes"><%= key.notes.t %></span>
So a stored string like Doesn't, pulled from the db, is converted by Textile to Doesn’t and rendered in the page as Doesn’t. Of course, testing the db value against the output of the page fails, because the quote has been converted.
expected to find visible css "#key_notes_135836989 span.current_notes" with text
"Doesn't get used very often." within #<Capybara::Node::Element> but there were no matches.
Also found "Doesn’t get used very often.", which matched the selector but not all filters.
It also fails if I test against the db value, encoded with t, because that contains the HTML entity, not the special character:
expected to find visible css "#key_notes_135836989 span.current_notes" with text
"Doesn’t get used very often." within #<Capybara::Node::Element> but there were no matches.
Also found "Doesn’t get used very often.", which matched the selector but not all filters.
If I assert against CGI.unescapeHTML(string.t), Capybara finds them equivalent.
assert_selector("#key_notes_#{marys_key.id} span.current_notes",
text: CGI.unescapeHTML(marys_key.notes.t))
My question is, since Capybara is always testing against rendered HTML, it seems like there must be an easier way to do this? I can't imagine using CGI.unescapeHTML every time i have some fancy text on the page (it's everywhere in this app).

Displaying user input html with newlines

I have comments section in my application where users enter input in a text area. I want to prevent the line breaks they enter but also display html as a string. For example, if comment.body is
Hello, this is the code: <a href='foo'>foo</a>
Bye
I want it to be displayed just as above. The same with anything else, including iframe tags.
The closest I got is:
= simple_format(comment.body)
but it sanitizes html code and it's not displayed. Example: foo <iframe>biz</iframe> bar is displayed as:
foo biz bar
What should I do to achieve what I want?
Just use it without any method, it will be rendered as plain text:
= comment.body
Using your second example, the output will be:
foo <iframe>biz</iframe> bar
To make \n behave as <br>, you can use CSS:
.add-line {
white-space: pre-wrap;
}
And use it in your view:
.add-line = comment.body
Using your first example:
comment.body = "Hello, this is the code: <a href='foo'>foo</a>\n\nBye"
The output will be:
Hello, this is the code: <a href='foo'>foo</a>
Bye
Having done something similar in the past, I think you must first understand why HTML is sanitized from user input.
Imagine I wrote the following into a field that accepted HTML and displays this to the front page.
<script>alert('Hello')</script>
The code would execute for anyone visiting the front-page and annoyingly trigger a JS alert for every visitor.
Maybe not much of an issue yet, but imagine I wrote some AJAX request that sent user session IDs to my own server. Now this is an issue... because people's sessions are being hijacked.
Furthermore, there is a full JavaScript based exploitation framework called BeEF that relies on this type of website exploit called Cross-site Scripting (XSS).
BeEF does extremely scary stuff and is worth taking a look at when considering user generated HTML.
http://guides.rubyonrails.org/security.html#cross-site-scripting-xss
So what to do? Well if you checked in your DB you'd see that the tags are actually being stored, but like you pointed out aren't displayed.
You could .html_safe the content, but again I strongly advise against this.
Maybe instead you should write an alternative .html_safe method yourself, something like html_safe_whitelisted_tags.
As for removing newlines, you say you want to display as is. So replacing /n with <br>, as pointed out by Michael, would be the solution for you.
comment.body.gsub('\n', '<br />').html_safe_whitelisted_tags
HTML safe allows the html in the comment to be used as html, but would skip the newlines, so doing a quick replace of \n with <br /> would cover the new lines
comment.body.gsub("\n", "<br />").html_safe
If you want the html to be displayed instead of rendered then checkout CGI::escapeHTML(), then do the gsub so that the <br /> does not get escaped.
CGI::escapeHTML(comment.body).gsub("\n", "<br />")

Showing html data from database to front end in mvc

I have upgraded my application from asp.net to mvc4. I am using html5 and displaying data in an html table. My database column contains html tags, but it is getting rendered as a plain text. Please help.
**
> Removable hard drive carrier only (DataPort)<html><br><b><font color
> ="red"> Part 444873-001 is no longer supplied. Please order the replacement, 580620-001</font></b></br></html>
**
Above line is a sample of how my data gets displayed in the column. I want to make the html tags to be rendered as html itself.
When you render your model data, use the Html.Raw() helper to render the HTML data unencoded. Razor automatically encodes HTML inputs in order to help prevent XSS attacks on websites.
<td>#Html.Raw(Model.MyProperty)</td>

Prevent HTML escaping in a text area

Realized that if I put HTML code in a rails text area, it will output the html.
For instance:
<b> Hello </b>
outputs as:
Hello
I thought rails 3 text inputs automatically escape HTML but whenever I output #variable.textarea, it still shows the bold text. Is it being selective about what HTML to input? And how do I make sure all HTML is always escape when I output the content of my textarea?
Thanks!
If <b>hello</b> comes out as hello, that means HTML escaping is already prevented.
Since you don't want users to be able to use HTML in their inputs, you want HTML to be escaped, so that <b>hello</b> comes out as <b>hello</b>.
In a Rails 3 app, html automatically gets escaped - but you can explicitly escape it using the h method:
<%= h my_string %>

Rendering a partial within "<code" or "<pre>" tags with jQuery and Rails

I am working on a simple Rails/jQuery HTML templater app which stores a series of pre-designed templates in a database (at the moment I've just saved these as partials to get the basic concept working) and on clicking 'Show code' alongside any one of these template records, a js.erb script should place the corresponding partial within 'pre' tags dynamically via JS on that page so the user can see the raw html code.
At the moment it's working but I get the rendered html coming back and not the raw HTML that I'm looking for. Here's the js:
$("div#template-view").html("<pre><code><%= escape_javascript( render :partial => "core_template") %></code></pre>");
So pray tell, what obvious thing am I missing!? :-)
Thanks
Allan
Use
$("div#template-view").text("...")
instead. This will not parse the code
The pre tag will show source code (or any text) in a reasonable approximation to it's original state, but it won't escape html for you. Unescaped html will always be rendered as html regardless of what tag it happens to be in. By escaped i mean that all the special characters are converted to their escaped versions. The rails method h will do this for you, so if you call h with the results of calling escape_javascript then it should work fine.
$("div#template-view").html("<pre><code><%= h(escape_javascript(render :partial => "core_template")) %></code></pre>");

Resources