rails_autolink 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -3
- data/README.rdoc +12 -4
- data/Rakefile +1 -1
- data/lib/rails_autolink.rb +137 -129
- data/test/test_rails_autolink.rb +27 -11
- metadata +7 -6
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -8,9 +8,11 @@ This is an extraction of the `auto_link` method from rails. The `auto_link`
|
|
8
8
|
method was removed from Rails in version Rails 3.1. This gem is meant to
|
9
9
|
bridge the gap for people migrating.
|
10
10
|
|
11
|
-
== FEATURES
|
11
|
+
== FEATURES:
|
12
12
|
|
13
|
-
|
13
|
+
By default auto_link returns sanitized html_safe strings.
|
14
|
+
This behaviour can be overriden setting the <tt>:sanitize</tt> option to false
|
15
|
+
(thus making it insecure if you don't have the content under control).
|
14
16
|
|
15
17
|
== SYNOPSIS:
|
16
18
|
|
@@ -27,6 +29,12 @@ bridge the gap for people migrating.
|
|
27
29
|
auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
|
28
30
|
# => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
29
31
|
|
32
|
+
auto_link("Go to http://www.rubyonrails.org <script>Malicious code!</script>")
|
33
|
+
# => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> "
|
34
|
+
|
35
|
+
auto_link("Go to http://www.rubyonrails.org <script>alert('Script!')</script>", :sanitize => false)
|
36
|
+
# => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> <script>alert('Script!')</script>"
|
37
|
+
|
30
38
|
post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
|
31
39
|
auto_link(post_body, :html => { :target => '_blank' }) do |text|
|
32
40
|
truncate(text, :length => 15)
|
@@ -35,11 +43,11 @@ bridge the gap for people migrating.
|
|
35
43
|
|
36
44
|
== REQUIREMENTS:
|
37
45
|
|
38
|
-
* rails
|
46
|
+
* rails >= 3.1
|
39
47
|
|
40
48
|
== INSTALL:
|
41
49
|
|
42
|
-
* gem install
|
50
|
+
* gem install rails_autolink
|
43
51
|
|
44
52
|
== LICENSE:
|
45
53
|
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ Hoe.spec 'rails_autolink' do
|
|
13
13
|
self.readme_file = 'README.rdoc'
|
14
14
|
self.history_file = 'CHANGELOG.rdoc'
|
15
15
|
self.extra_rdoc_files = FileList['*.rdoc']
|
16
|
-
self.extra_deps << ['rails', '~> 3.1.0']
|
16
|
+
self.extra_deps << ['rails', '~> 3.1.0.a']
|
17
17
|
end
|
18
18
|
|
19
19
|
# vim: syntax=ruby
|
data/lib/rails_autolink.rb
CHANGED
@@ -1,141 +1,149 @@
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
2
|
-
require 'active_support/core_ext/array/extract_options'
|
3
|
-
require 'active_support/core_ext/hash/reverse_merge'
|
4
|
-
require 'active_support/core_ext/hash/keys'
|
5
|
-
|
6
1
|
module RailsAutolink
|
7
|
-
VERSION = '1.0.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
# regexps for determining context, used high-volume
|
75
|
-
AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
|
76
|
-
|
77
|
-
AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
|
78
|
-
|
79
|
-
BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
|
80
|
-
|
81
|
-
# Turns all urls into clickable links. If a block is given, each url
|
82
|
-
# is yielded and the result is used as the link text.
|
83
|
-
def auto_link_urls(text, html_options = {}, options = {})
|
84
|
-
link_attributes = html_options.stringify_keys
|
85
|
-
text.gsub(AUTO_LINK_RE) do
|
86
|
-
scheme, href = $1, $&
|
87
|
-
punctuation = []
|
88
|
-
|
89
|
-
if auto_linked?($`, $')
|
90
|
-
# do not change string; URL is already linked
|
91
|
-
href
|
92
|
-
else
|
93
|
-
# don't include trailing punctuation character as part of the URL
|
94
|
-
while href.sub!(/[^\w\/-]$/, '')
|
95
|
-
punctuation.push $&
|
96
|
-
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
|
97
|
-
href << punctuation.pop
|
98
|
-
break
|
2
|
+
VERSION = '1.0.1'
|
3
|
+
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
initializer 'nested_form' do |app|
|
6
|
+
ActiveSupport.on_load(:action_view) do
|
7
|
+
require 'active_support/core_ext/object/blank'
|
8
|
+
require 'active_support/core_ext/array/extract_options'
|
9
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
10
|
+
require 'active_support/core_ext/hash/keys'
|
11
|
+
|
12
|
+
module ::ActionView
|
13
|
+
module Helpers # :nodoc:
|
14
|
+
module TextHelper
|
15
|
+
# Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
|
16
|
+
# will limit what should be linked. You can add HTML attributes to the links using
|
17
|
+
# <tt>:html</tt>. Possible values for <tt>:link</tt> are <tt>:all</tt> (default),
|
18
|
+
# <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
|
19
|
+
# e-mail address is yielded and the result is used as the link text. By default the
|
20
|
+
# text given is sanitized, you can override this behaviour setting the
|
21
|
+
# <tt>:sanitize</tt> option to false.
|
22
|
+
#
|
23
|
+
# ==== Examples
|
24
|
+
# auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
|
25
|
+
# # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
|
26
|
+
# # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
27
|
+
#
|
28
|
+
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls)
|
29
|
+
# # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
|
30
|
+
# # or e-mail david@loudthinking.com"
|
31
|
+
#
|
32
|
+
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
|
33
|
+
# # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
34
|
+
#
|
35
|
+
# post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
|
36
|
+
# auto_link(post_body, :html => { :target => '_blank' }) do |text|
|
37
|
+
# truncate(text, :length => 15)
|
38
|
+
# end
|
39
|
+
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
|
40
|
+
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
41
|
+
#
|
42
|
+
#
|
43
|
+
# You can still use <tt>auto_link</tt> with the old API that accepts the
|
44
|
+
# +link+ as its optional second parameter and the +html_options+ hash
|
45
|
+
# as its optional third parameter:
|
46
|
+
# post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
|
47
|
+
# auto_link(post_body, :urls)
|
48
|
+
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>.
|
49
|
+
# Please e-mail me at me@email.com."
|
50
|
+
#
|
51
|
+
# auto_link(post_body, :all, :target => "_blank")
|
52
|
+
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
|
53
|
+
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
54
|
+
def auto_link(text, *args, &block)#link = :all, html = {}, &block)
|
55
|
+
return ''.html_safe if text.blank?
|
56
|
+
|
57
|
+
options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
|
58
|
+
unless args.empty?
|
59
|
+
options[:link] = args[0] || :all
|
60
|
+
options[:html] = args[1] || {}
|
61
|
+
end
|
62
|
+
options.reverse_merge!(:link => :all, :html => {})
|
63
|
+
text = sanitize(text) unless options[:sanitize] == false
|
64
|
+
case options[:link].to_sym
|
65
|
+
when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block)
|
66
|
+
when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
|
67
|
+
when :urls then auto_link_urls(text, options[:html], options, &block)
|
99
68
|
end
|
100
69
|
end
|
101
70
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
71
|
+
private
|
72
|
+
|
73
|
+
AUTO_LINK_RE = %r{
|
74
|
+
(?: ([0-9A-Za-z+.:-]+:)// | www\. )
|
75
|
+
[^\s<]+
|
76
|
+
}x
|
77
|
+
|
78
|
+
# regexps for determining context, used high-volume
|
79
|
+
AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
|
80
|
+
|
81
|
+
AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
|
82
|
+
|
83
|
+
BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
|
84
|
+
|
85
|
+
# Turns all urls into clickable links. If a block is given, each url
|
86
|
+
# is yielded and the result is used as the link text.
|
87
|
+
def auto_link_urls(text, html_options = {}, options = {})
|
88
|
+
link_attributes = html_options.stringify_keys
|
89
|
+
text.gsub(AUTO_LINK_RE) do
|
90
|
+
scheme, href = $1, $&
|
91
|
+
punctuation = []
|
92
|
+
|
93
|
+
if auto_linked?($`, $')
|
94
|
+
# do not change string; URL is already linked
|
95
|
+
href
|
96
|
+
else
|
97
|
+
# don't include trailing punctuation character as part of the URL
|
98
|
+
while href.sub!(/[^\w\/-]$/, '')
|
99
|
+
punctuation.push $&
|
100
|
+
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
|
101
|
+
href << punctuation.pop
|
102
|
+
break
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
link_text = block_given?? yield(href) : href
|
107
|
+
href = 'http://' + href unless scheme
|
108
|
+
|
109
|
+
unless options[:sanitize] == false
|
110
|
+
link_text = sanitize(link_text)
|
111
|
+
href = sanitize(href)
|
112
|
+
end
|
113
|
+
content_tag(:a, link_text, link_attributes.merge('href' => href), !!options[:sanitize]) + punctuation.reverse.join('')
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
119
117
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
118
|
+
# Turns all email addresses into clickable links. If a block is given,
|
119
|
+
# each email is yielded and the result is used as the link text.
|
120
|
+
def auto_link_email_addresses(text, html_options = {}, options = {})
|
121
|
+
text.gsub(AUTO_EMAIL_RE) do
|
122
|
+
text = $&
|
123
|
+
|
124
|
+
if auto_linked?($`, $')
|
125
|
+
text.html_safe
|
126
|
+
else
|
127
|
+
display_text = (block_given?) ? yield(text) : text
|
128
|
+
|
129
|
+
unless options[:sanitize] == false
|
130
|
+
text = sanitize(text)
|
131
|
+
display_text = sanitize(display_text) unless text == display_text
|
132
|
+
end
|
133
|
+
mail_to text, display_text, html_options
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
124
137
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
138
|
+
# Detects already linked context or position in the middle of a tag
|
139
|
+
def auto_linked?(left, right)
|
140
|
+
(left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
|
141
|
+
(left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
|
142
|
+
end
|
130
143
|
end
|
131
144
|
end
|
132
145
|
end
|
133
|
-
|
134
|
-
# Detects already linked context or position in the middle of a tag
|
135
|
-
def auto_linked?(left, right)
|
136
|
-
(left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
|
137
|
-
(left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
|
138
|
-
end
|
146
|
+
end
|
139
147
|
end
|
140
148
|
end
|
141
149
|
end
|
data/test/test_rails_autolink.rb
CHANGED
@@ -84,12 +84,17 @@ class TestRailsAutolink < MiniTest::Unit::TestCase
|
|
84
84
|
|
85
85
|
def test_auto_link_should_sanitize_input_when_sanitize_option_is_not_false
|
86
86
|
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
|
87
|
-
|
87
|
+
malicious_script = '<script>alert("malicious!")</script>'
|
88
|
+
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}")
|
89
|
+
assert auto_link("#{link_raw}#{malicious_script}").html_safe?
|
88
90
|
end
|
89
91
|
|
90
92
|
def test_auto_link_should_not_sanitize_input_when_sanitize_option_is_false
|
91
93
|
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
|
92
|
-
|
94
|
+
malicious_script = '<script>alert("malicious!")</script>'
|
95
|
+
|
96
|
+
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)
|
97
|
+
assert !auto_link("#{link_raw}#{malicious_script}", :sanitize => false).html_safe?
|
93
98
|
end
|
94
99
|
|
95
100
|
def test_auto_link_other_protocols
|
@@ -114,7 +119,7 @@ class TestRailsAutolink < MiniTest::Unit::TestCase
|
|
114
119
|
linked5 = %('<a href="#close">close</a> <a href="http://www.example.com"><b>www.example.com</b></a>')
|
115
120
|
assert_equal linked1, auto_link(linked1)
|
116
121
|
assert_equal linked2, auto_link(linked2)
|
117
|
-
assert_equal linked3, auto_link(linked3)
|
122
|
+
assert_equal linked3, auto_link(linked3, :sanitize => false)
|
118
123
|
assert_equal linked4, auto_link(linked4)
|
119
124
|
assert_equal linked5, auto_link(linked5)
|
120
125
|
|
@@ -130,14 +135,25 @@ class TestRailsAutolink < MiniTest::Unit::TestCase
|
|
130
135
|
assert_equal %(<p><a href="#{url1}">#{url1}</a><br /><a href="#{url2}">#{url2}</a><br /></p>), auto_link("<p>#{url1}<br />#{url2}<br /></p>")
|
131
136
|
end
|
132
137
|
|
133
|
-
def
|
134
|
-
email_raw
|
135
|
-
link_raw
|
136
|
-
|
137
|
-
|
138
|
-
assert
|
139
|
-
assert
|
140
|
-
assert
|
138
|
+
def test_auto_link_should_be_html_safe
|
139
|
+
email_raw = 'santiago@wyeworks.com'
|
140
|
+
link_raw = 'http://www.rubyonrails.org'
|
141
|
+
malicious_script = '<script>alert("malicious!")</script>'
|
142
|
+
|
143
|
+
assert auto_link(nil).html_safe?, 'should be html safe'
|
144
|
+
assert auto_link('').html_safe?, 'should be html safe'
|
145
|
+
assert auto_link("#{link_raw} #{link_raw} #{link_raw}").html_safe?, 'should be html safe'
|
146
|
+
assert auto_link("hello #{email_raw}").html_safe?, 'should be html safe'
|
147
|
+
assert auto_link("hello #{email_raw} #{malicious_script}").html_safe?, 'should be html safe'
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_auto_link_should_not_be_html_safe_when_sanitize_option_false
|
151
|
+
email_raw = 'santiago@wyeworks.com'
|
152
|
+
link_raw = 'http://www.rubyonrails.org'
|
153
|
+
|
154
|
+
assert !auto_link("hello", :sanitize => false).html_safe?, 'should not be html safe'
|
155
|
+
assert !auto_link("#{link_raw} #{link_raw} #{link_raw}", :sanitize => false).html_safe?, 'should not be html safe'
|
156
|
+
assert !auto_link("hello #{email_raw}", :sanitize => false).html_safe?, 'should not be html safe'
|
141
157
|
end
|
142
158
|
|
143
159
|
def test_auto_link_email_address
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_autolink
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
9
|
+
- 1
|
10
|
+
version: 1.0.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Aaron Patterson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-06 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rails
|
@@ -25,12 +25,13 @@ dependencies:
|
|
25
25
|
requirements:
|
26
26
|
- - ~>
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
28
|
+
hash: 18
|
29
29
|
segments:
|
30
30
|
- 3
|
31
31
|
- 1
|
32
32
|
- 0
|
33
|
-
|
33
|
+
- a
|
34
|
+
version: 3.1.0.a
|
34
35
|
type: :runtime
|
35
36
|
version_requirements: *id001
|
36
37
|
- !ruby/object:Gem::Dependency
|