Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of github.com:tenderlove/rails_autolink

* 'master' of github.com:tenderlove/rails_autolink:
  shall I build a gem?
  make it work with 3.1.0.beta1
  ensure the whole freedom patching to be loaded AFTER intializing AV
  Readme
  return sanitized strings
  remove local tenderloving-paths from gemfile

Conflicts:
	Manifest.txt
  • Loading branch information...
commit 9d17e2cfba6e2f19348ac64b6b1aa19759bce976 2 parents 3683d21 + 1895cec
@tenderlove authored
View
6 Gemfile
@@ -1,8 +1,8 @@
source 'http://rubygems.org'
-gem 'rails', :path => '/Users/aaron/git/rails'
-gem 'arel', :path => '/Users/aaron/git/arel'
-gem 'rack', :path => '/Users/aaron/git/rack'
+gem 'rails'
+gem 'arel'
+gem 'rack'
gem 'hoe'
gem 'minitest'
View
16 README.rdoc
@@ -8,9 +8,11 @@ This is an extraction of the `auto_link` method from rails. The `auto_link`
method was removed from Rails in version Rails 3.1. This gem is meant to
bridge the gap for people migrating.
-== FEATURES/PROBLEMS:
+== FEATURES:
-* May not be safe!
+By default auto_link returns sanitized html_safe strings.
+This behaviour can be overriden setting the <tt>:sanitize</tt> option to false
+(thus making it insecure if you don't have the content under control).
== SYNOPSIS:
@@ -27,6 +29,12 @@ bridge the gap for people migrating.
auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
# => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
+ auto_link("Go to http://www.rubyonrails.org <script>Malicious code!</script>")
+ # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> "
+
+ auto_link("Go to http://www.rubyonrails.org <script>alert('Script!')</script>", :sanitize => false)
+ # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> <script>alert('Script!')</script>"
+
post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
auto_link(post_body, :html => { :target => '_blank' }) do |text|
truncate(text, :length => 15)
@@ -35,11 +43,11 @@ bridge the gap for people migrating.
== REQUIREMENTS:
-* rails
+* rails >= 3.1
== INSTALL:
-* gem install rails
+* gem install rails_autolink
== LICENSE:
View
2  Rakefile
@@ -13,7 +13,7 @@ Hoe.spec 'rails_autolink' do
self.readme_file = 'README.rdoc'
self.history_file = 'CHANGELOG.rdoc'
self.extra_rdoc_files = FileList['*.rdoc']
- self.extra_deps << ['rails', '~> 3.1.0']
+ self.extra_deps << ['rails', '~> 3.1.0.a']
end
# vim: syntax=ruby
View
266 lib/rails_autolink.rb
@@ -1,141 +1,149 @@
-require 'active_support/core_ext/object/blank'
-require 'active_support/core_ext/array/extract_options'
-require 'active_support/core_ext/hash/reverse_merge'
-require 'active_support/core_ext/hash/keys'
-
module RailsAutolink
- VERSION = '1.0.0'
-end
-
-module ActionView
- module Helpers # :nodoc:
- module TextHelper
- # Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
- # will limit what should be linked. You can add HTML attributes to the links using
- # <tt>:html</tt>. Possible values for <tt>:link</tt> are <tt>:all</tt> (default),
- # <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
- # e-mail address is yielded and the result is used as the link text.
- #
- # ==== Examples
- # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
- # # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
- # # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
- #
- # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls)
- # # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
- # # or e-mail david@loudthinking.com"
- #
- # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
- # # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
- #
- # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
- # auto_link(post_body, :html => { :target => '_blank' }) do |text|
- # truncate(text, :length => 15)
- # end
- # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
- # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
- #
- #
- # You can still use <tt>auto_link</tt> with the old API that accepts the
- # +link+ as its optional second parameter and the +html_options+ hash
- # as its optional third parameter:
- # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
- # auto_link(post_body, :urls)
- # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>.
- # Please e-mail me at me@email.com."
- #
- # auto_link(post_body, :all, :target => "_blank")
- # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
- # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
- def auto_link(text, *args, &block)#link = :all, html = {}, &block)
- return '' if text.blank?
-
- options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
- unless args.empty?
- options[:link] = args[0] || :all
- options[:html] = args[1] || {}
- end
- options.reverse_merge!(:link => :all, :html => {})
-
- case options[:link].to_sym
- when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block)
- when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
- when :urls then auto_link_urls(text, options[:html], options, &block)
- end
- end
-
- private
-
- AUTO_LINK_RE = %r{
- (?: ([0-9A-Za-z+.:-]+:)// | www\. )
- [^\s<]+
- }x
-
- # regexps for determining context, used high-volume
- AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
-
- AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
-
- BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
-
- # Turns all urls into clickable links. If a block is given, each url
- # is yielded and the result is used as the link text.
- def auto_link_urls(text, html_options = {}, options = {})
- link_attributes = html_options.stringify_keys
- text.gsub(AUTO_LINK_RE) do
- scheme, href = $1, $&
- punctuation = []
-
- if auto_linked?($`, $')
- # do not change string; URL is already linked
- href
- else
- # don't include trailing punctuation character as part of the URL
- while href.sub!(/[^\w\/-]$/, '')
- punctuation.push $&
- if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
- href << punctuation.pop
- break
+ VERSION = '1.0.1'
+
+ class Railtie < ::Rails::Railtie
+ initializer 'nested_form' do |app|
+ ActiveSupport.on_load(:action_view) do
+ require 'active_support/core_ext/object/blank'
+ require 'active_support/core_ext/array/extract_options'
+ require 'active_support/core_ext/hash/reverse_merge'
+ require 'active_support/core_ext/hash/keys'
+
+ module ::ActionView
+ module Helpers # :nodoc:
+ module TextHelper
+ # Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
+ # will limit what should be linked. You can add HTML attributes to the links using
+ # <tt>:html</tt>. Possible values for <tt>:link</tt> are <tt>:all</tt> (default),
+ # <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
+ # e-mail address is yielded and the result is used as the link text. By default the
+ # text given is sanitized, you can override this behaviour setting the
+ # <tt>:sanitize</tt> option to false.
+ #
+ # ==== Examples
+ # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
+ # # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
+ # # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
+ #
+ # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls)
+ # # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
+ # # or e-mail david@loudthinking.com"
+ #
+ # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
+ # # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
+ #
+ # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
+ # auto_link(post_body, :html => { :target => '_blank' }) do |text|
+ # truncate(text, :length => 15)
+ # end
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
+ # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
+ #
+ #
+ # You can still use <tt>auto_link</tt> with the old API that accepts the
+ # +link+ as its optional second parameter and the +html_options+ hash
+ # as its optional third parameter:
+ # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
+ # auto_link(post_body, :urls)
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>.
+ # Please e-mail me at me@email.com."
+ #
+ # auto_link(post_body, :all, :target => "_blank")
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
+ # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
+ def auto_link(text, *args, &block)#link = :all, html = {}, &block)
+ return ''.html_safe if text.blank?
+
+ options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
+ unless args.empty?
+ options[:link] = args[0] || :all
+ options[:html] = args[1] || {}
+ end
+ options.reverse_merge!(:link => :all, :html => {})
+ text = sanitize(text) unless options[:sanitize] == false
+ case options[:link].to_sym
+ when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block)
+ when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
+ when :urls then auto_link_urls(text, options[:html], options, &block)
end
end
- link_text = block_given?? yield(href) : href
- href = 'http://' + href unless scheme
-
- unless options[:sanitize] == false
- link_text = sanitize(link_text)
- href = sanitize(href)
- end
- content_tag(:a, link_text, link_attributes.merge('href' => href), !!options[:sanitize]) + punctuation.reverse.join('')
- end
- end
- end
-
- # Turns all email addresses into clickable links. If a block is given,
- # each email is yielded and the result is used as the link text.
- def auto_link_email_addresses(text, html_options = {}, options = {})
- text.gsub(AUTO_EMAIL_RE) do
- text = $&
+ private
+
+ AUTO_LINK_RE = %r{
+ (?: ([0-9A-Za-z+.:-]+:)// | www\. )
+ [^\s<]+
+ }x
+
+ # regexps for determining context, used high-volume
+ AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
+
+ AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
+
+ BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
+
+ # Turns all urls into clickable links. If a block is given, each url
+ # is yielded and the result is used as the link text.
+ def auto_link_urls(text, html_options = {}, options = {})
+ link_attributes = html_options.stringify_keys
+ text.gsub(AUTO_LINK_RE) do
+ scheme, href = $1, $&
+ punctuation = []
+
+ if auto_linked?($`, $')
+ # do not change string; URL is already linked
+ href
+ else
+ # don't include trailing punctuation character as part of the URL
+ while href.sub!(/[^\w\/-]$/, '')
+ punctuation.push $&
+ if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
+ href << punctuation.pop
+ break
+ end
+ end
+
+ link_text = block_given?? yield(href) : href
+ href = 'http://' + href unless scheme
+
+ unless options[:sanitize] == false
+ link_text = sanitize(link_text)
+ href = sanitize(href)
+ end
+ content_tag(:a, link_text, link_attributes.merge('href' => href), !!options[:sanitize]) + punctuation.reverse.join('')
+ end
+ end
+ end
- if auto_linked?($`, $')
- text.html_safe
- else
- display_text = (block_given?) ? yield(text) : text
+ # Turns all email addresses into clickable links. If a block is given,
+ # each email is yielded and the result is used as the link text.
+ def auto_link_email_addresses(text, html_options = {}, options = {})
+ text.gsub(AUTO_EMAIL_RE) do
+ text = $&
+
+ if auto_linked?($`, $')
+ text.html_safe
+ else
+ display_text = (block_given?) ? yield(text) : text
+
+ unless options[:sanitize] == false
+ text = sanitize(text)
+ display_text = sanitize(display_text) unless text == display_text
+ end
+ mail_to text, display_text, html_options
+ end
+ end
+ end
- unless options[:sanitize] == false
- text = sanitize(text)
- display_text = sanitize(display_text) unless text == display_text
- end
- mail_to text, display_text, html_options
+ # Detects already linked context or position in the middle of a tag
+ def auto_linked?(left, right)
+ (left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
+ (left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
+ end
end
end
end
-
- # Detects already linked context or position in the middle of a tag
- def auto_linked?(left, right)
- (left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
- (left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
- end
+ end
end
end
end
View
38 test/test_rails_autolink.rb
@@ -84,12 +84,17 @@ def test_auto_link_with_block_with_html
def test_auto_link_should_sanitize_input_when_sanitize_option_is_not_false
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
- assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw)
+ malicious_script = '<script>alert("malicious!")</script>'
+ assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link("#{link_raw}#{malicious_script}")
+ assert auto_link("#{link_raw}#{malicious_script}").html_safe?
end
def test_auto_link_should_not_sanitize_input_when_sanitize_option_is_false
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
- assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link(link_raw, :sanitize => false)
+ malicious_script = '<script>alert("malicious!")</script>'
+
+ assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a><script>alert("malicious!")</script>}, auto_link("#{link_raw}#{malicious_script}", :sanitize => false)
+ assert !auto_link("#{link_raw}#{malicious_script}", :sanitize => false).html_safe?
end
def test_auto_link_other_protocols
@@ -114,7 +119,7 @@ def test_auto_link_already_linked
linked5 = %('<a href="#close">close</a> <a href="http://www.example.com"><b>www.example.com</b></a>')
assert_equal linked1, auto_link(linked1)
assert_equal linked2, auto_link(linked2)
- assert_equal linked3, auto_link(linked3)
+ assert_equal linked3, auto_link(linked3, :sanitize => false)
assert_equal linked4, auto_link(linked4)
assert_equal linked5, auto_link(linked5)
@@ -130,14 +135,25 @@ def test_auto_link_at_eol
assert_equal %(<p><a href="#{url1}">#{url1}</a><br /><a href="#{url2}">#{url2}</a><br /></p>), auto_link("<p>#{url1}<br />#{url2}<br /></p>")
end
- def test_auto_link_should_not_be_html_safe
- email_raw = 'santiago@wyeworks.com'
- link_raw = 'http://www.rubyonrails.org'
-
- assert !auto_link(nil).html_safe?, 'should not be html safe'
- assert !auto_link('').html_safe?, 'should not be html safe'
- assert !auto_link("#{link_raw} #{link_raw} #{link_raw}").html_safe?, 'should not be html safe'
- assert !auto_link("hello #{email_raw}").html_safe?, 'should not be html safe'
+ def test_auto_link_should_be_html_safe
+ email_raw = 'santiago@wyeworks.com'
+ link_raw = 'http://www.rubyonrails.org'
+ malicious_script = '<script>alert("malicious!")</script>'
+
+ assert auto_link(nil).html_safe?, 'should be html safe'
+ assert auto_link('').html_safe?, 'should be html safe'
+ assert auto_link("#{link_raw} #{link_raw} #{link_raw}").html_safe?, 'should be html safe'
+ assert auto_link("hello #{email_raw}").html_safe?, 'should be html safe'
+ assert auto_link("hello #{email_raw} #{malicious_script}").html_safe?, 'should be html safe'
+ end
+
+ def test_auto_link_should_not_be_html_safe_when_sanitize_option_false
+ email_raw = 'santiago@wyeworks.com'
+ link_raw = 'http://www.rubyonrails.org'
+
+ assert !auto_link("hello", :sanitize => false).html_safe?, 'should not be html safe'
+ assert !auto_link("#{link_raw} #{link_raw} #{link_raw}", :sanitize => false).html_safe?, 'should not be html safe'
+ assert !auto_link("hello #{email_raw}", :sanitize => false).html_safe?, 'should not be html safe'
end
def test_auto_link_email_address
Please sign in to comment.
Something went wrong with that request. Please try again.