From c2bc7272fb3146c79ea0381c3eef4227b11a8315 Mon Sep 17 00:00:00 2001 From: Steven Hancock Date: Mon, 28 May 2012 21:31:27 -0700 Subject: [PATCH] Escape hashtags in emails Custom Redcarpet renderer to escape hashtags (but not legitimate headers) in emails before Markdown processing. Prevents hashtags from being rendered as H1 headers. This also leaves open the possibility of parsing hashtags into clickable links in the future. fixes #3325 --- Gemfile | 2 +- Gemfile.lock | 11 +++++-- config/initializers/markerb.rb | 3 ++ lib/diaspora/markdownify_email.rb | 25 ++++++++++++++ spec/lib/diaspora/markdownify_email_spec.rb | 36 +++++++++++++++++++++ spec/mailers/notifier_spec.rb | 9 ++++++ 6 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 config/initializers/markerb.rb create mode 100644 lib/diaspora/markdownify_email.rb create mode 100644 spec/lib/diaspora/markdownify_email_spec.rb diff --git a/Gemfile b/Gemfile index abd96c37b..18d43ef97 100644 --- a/Gemfile +++ b/Gemfile @@ -29,7 +29,7 @@ gem 'twitter', '2.0.2' # mail -gem 'markerb', '~> 1.0.0' +gem 'markerb', :git => 'git://github.com/plataformatec/markerb.git' gem 'messagebus_ruby_api', '1.0.3' gem 'airbrake' gem 'newrelic_rpm' diff --git a/Gemfile.lock b/Gemfile.lock index 8ee187bfa..deace8cd9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -30,6 +30,13 @@ GIT rspec (>= 1.3.1) selenium-webdriver (>= 0.1.3) +GIT + remote: git://github.com/plataformatec/markerb.git + revision: 93b1e8bea9b8fa89ef930f78ba562f596c022198 + specs: + markerb (1.0.0) + redcarpet (>= 2.0) + GEM remote: http://rubygems.org/ specs: @@ -243,8 +250,6 @@ GEM i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) - markerb (1.0.0) - redcarpet (>= 2.0) messagebus_ruby_api (1.0.3) mime-types (1.18) mini_magick (3.4) @@ -490,7 +495,7 @@ DEPENDENCIES jquery-rails json linecache (= 0.46) - markerb (~> 1.0.0) + markerb! messagebus_ruby_api (= 1.0.3) mini_magick (= 3.4) mobile-fu diff --git a/config/initializers/markerb.rb b/config/initializers/markerb.rb new file mode 100644 index 000000000..3d7351b6b --- /dev/null +++ b/config/initializers/markerb.rb @@ -0,0 +1,3 @@ +require Rails.root.join("lib", "diaspora", "markdownify_email") + +Rails.application.config.markerb.renderer = Diaspora::Markdownify::Email \ No newline at end of file diff --git a/lib/diaspora/markdownify_email.rb b/lib/diaspora/markdownify_email.rb new file mode 100644 index 000000000..c2eba16ce --- /dev/null +++ b/lib/diaspora/markdownify_email.rb @@ -0,0 +1,25 @@ +require Rails.root.join("app", "models", "acts_as_taggable_on", "tag") + +module Diaspora + module Markdownify + class Email < Redcarpet::Render::HTML + TAG_REGEX = /(?:^|\s)#([#{ActsAsTaggableOn::Tag.tag_text_regexp}]+)/u + def preprocess(text) + process_tags(text) + end + + private + def tags(text) + text.scan(TAG_REGEX).map { |match| match[0] } + end + + def process_tags(text) + return text unless text.match(TAG_REGEX) + tags(text).each do |tag| + text.gsub!(/##{tag}/i, "\\##{tag}") + end + text + end + end + end +end \ No newline at end of file diff --git a/spec/lib/diaspora/markdownify_email_spec.rb b/spec/lib/diaspora/markdownify_email_spec.rb new file mode 100644 index 000000000..bcc744b72 --- /dev/null +++ b/spec/lib/diaspora/markdownify_email_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe Diaspora::Markdownify::Email do + describe '#preprocess' do + before do + @html = Diaspora::Markdownify::Email.new + end + + it 'should escape a hashtag' do + markdownified = @html.preprocess("#tag") + markdownified.should == "\\#tag" + end + + it 'should escape multiple hashtags' do + markdownified = @html.preprocess("There are #two #tags") + markdownified.should == "There are \\#two \\#tags" + end + + it 'should not escape headers' do + markdownified = @html.preprocess("# header") + markdownified.should == "# header" + end + end + + describe "Markdown rendering" do + before do + @markdown = Redcarpet::Markdown.new(Diaspora::Markdownify::Email) + @sample_text = "# Header\n\n#messages containing #hashtags should render properly" + end + + it 'should render the message' do + rendered = @markdown.render(@sample_text).strip + rendered.should == "

Header

\n\n

#messages containing #hashtags should render properly

" + end + end +end \ No newline at end of file diff --git a/spec/mailers/notifier_spec.rb b/spec/mailers/notifier_spec.rb index b0ca06b9e..d9aeace5f 100644 --- a/spec/mailers/notifier_spec.rb +++ b/spec/mailers/notifier_spec.rb @@ -325,4 +325,13 @@ describe Notifier do end end end + + describe 'hashtags' do + it 'escapes hashtags' do + mails = Notifier.admin("#Welcome to bureaucracy!", [bob]) + mails.length.should == 1 + mail = mails.first + mail.body.encoded.should match /#Welcome to bureaucracy!/ + end + end end