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:

%h1 Here's some rendered Markdown
  :markdown
    = @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:

%h1 Here's some rendered Markdown
  != 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:

module MyApp
  module Filters
    module Markdown
      include Haml::Filters::Base
      lazy_require 'rdiscount'

      def render(text)
        ::RDiscount.new(text, :filter_html).to_html
      end
    end
  end
end

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

1 comment :