Sunday, December 5, 2010

Providing markdown engine options in HAML

I've started looking into using Markdown in Rails. I use HAML for rendering views, so markdown is handled by a HAML filter:

  1. %h1 Here's some rendered Markdown  
  2.   :markdown  
  3.     = @model.markdown  

This worked great, but I was concerned about javascript injection since the markdown would be provided by a user using a WMD editor. I found that I could explicitly call RDiscount, with the :filter_html option, to render the markdown myself:

  1. %h1 Here's some rendered Markdown  
  2.   != RDiscount.new(@model.markdown, :filter_html).to_html  

This worked great, but I didn't want to have to remember this incantation every time I want to render some Markdown. After some discussion with Nathan Weizenbaum the current maintainer of Haml, I realized that the answer is actually presented (somewhat indirectly) through the documentation. The section on Custom Filters says "You can also define your own filters. See Haml::Filters for details.". You have to then follow on to Haml::Filters::Base for the full story.

In my Rails app, I created a custom Haml filter that overrides the original :markdown (so I don't accidentally forget and use an unsafe :markdown) config/initializers/haml.rb:

  1. module MyApp  
  2.   module Filters  
  3.     module Markdown  
  4.       include Haml::Filters::Base  
  5.       lazy_require 'rdiscount'  
  6.   
  7.       def render(text)  
  8.         ::RDiscount.new(text, :filter_html).to_html  
  9.       end  
  10.     end  
  11.   end  
  12. end  

Now, whenever HAML renders a :markdown filter, it will filter the HTML and protect me against javascript injection attacks.

1 comment :