Skip to content

Commit

Permalink
Merge pull request rails#8523 from reednj77/remove-mail-to-encoding
Browse files Browse the repository at this point in the history
Remove obfuscation support from mail_to helper
  • Loading branch information
dhh committed Dec 19, 2012
2 parents 88e9157 + cf9d945 commit 153f0cb
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 110 deletions.
5 changes: 5 additions & 0 deletions actionpack/CHANGELOG.md
Expand Up @@ -4,6 +4,11 @@

*Vasiliy Ermolovich*

* Extract support for email address obfuscation via `:encode`, `:replace_at`, and `replace_dot` options
from the `mail_to` helper into the `actionview-encoded_mail_to` gem.

*Nick Reed + DHH*

* Clear url helper methods when routes are reloaded. *Andrew White*

* Fix a bug in `ActionDispatch::Request#raw_post` that caused `env['rack.input']`
Expand Down
66 changes: 12 additions & 54 deletions actionpack/lib/action_view/helpers/url_helper.rb
Expand Up @@ -415,84 +415,42 @@ def link_to_if(condition, name, options = {}, html_options = {}, &block)
# also used as the name of the link unless +name+ is specified. Additional
# HTML attributes for the link can be passed in +html_options+.
#
# +mail_to+ has several methods for hindering email harvesters and customizing
# the email itself by passing special keys to +html_options+.
# +mail_to+ has several methods for customizing the email itself by
# passing special keys to +html_options+.
#
# ==== Options
# * <tt>:encode</tt> - This key will accept the strings "javascript" or "hex".
# Passing "javascript" will dynamically create and encode the mailto link then
# eval it into the DOM of the page. This method will not show the link on
# the page if the user has JavaScript disabled. Passing "hex" will hex
# encode the +email_address+ before outputting the mailto link.
# * <tt>:replace_at</tt> - When the link +name+ isn't provided, the
# +email_address+ is used for the link label. You can use this option to
# obfuscate the +email_address+ by substituting the @ sign with the string
# given as the value.
# * <tt>:replace_dot</tt> - When the link +name+ isn't provided, the
# +email_address+ is used for the link label. You can use this option to
# obfuscate the +email_address+ by substituting the . in the email with the
# string given as the value.
# * <tt>:subject</tt> - Preset the subject line of the email.
# * <tt>:body</tt> - Preset the body of the email.
# * <tt>:cc</tt> - Carbon Copy additional recipients on the email.
# * <tt>:bcc</tt> - Blind Carbon Copy additional recipients on the email.
#
# ==== Obfuscation
# Prior to Rails 4.0, +mail_to+ provided options for encoding the address
# in order to hinder email harvesters. To take advantage of these options,
# install the +actionview-encoded_mail_to+ gem.
#
# ==== Examples
# mail_to "me@domain.com"
# # => <a href="mailto:me@domain.com">me@domain.com</a>
#
# mail_to "me@domain.com", "My email", encode: "javascript"
# # => <script>eval(decodeURIComponent('%64%6f%63...%27%29%3b'))</script>
#
# mail_to "me@domain.com", "My email", encode: "hex"
# # => <a href="mailto:%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>
#
# mail_to "me@domain.com", nil, replace_at: "_at_", replace_dot: "_dot_", class: "email"
# # => <a href="mailto:me@domain.com" class="email">me_at_domain_dot_com</a>
# mail_to "me@domain.com", "My email"
# # => <a href="mailto:me@domain.com">My email</a>
#
# mail_to "me@domain.com", "My email", cc: "ccaddress@domain.com",
# subject: "This is an example email"
# # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
def mail_to(email_address, name = nil, html_options = {})
email_address = ERB::Util.html_escape(email_address)

html_options = html_options.stringify_keys
encode = html_options.delete("encode").to_s
html_options.stringify_keys!

extras = %w{ cc bcc body subject }.map { |item|
option = html_options.delete(item) || next
"#{item}=#{Rack::Utils.escape_path(option)}"
}.compact
extras = extras.empty? ? '' : '?' + ERB::Util.html_escape(extras.join('&'))

email_address_obfuscated = email_address.to_str
email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.key?("replace_at")
email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.key?("replace_dot")
case encode
when "javascript"
string = ''
html = content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe))
html = escape_javascript(html.to_str)
"document.write('#{html}');".each_byte do |c|
string << sprintf("%%%x", c)
end
"<script>eval(decodeURIComponent('#{string}'))</script>".html_safe
when "hex"
email_address_encoded = email_address_obfuscated.unpack('C*').map {|c|
sprintf("&#%d;", c)
}.join

string = 'mailto:'.unpack('C*').map { |c|
sprintf("&#%d;", c)
}.join + email_address.unpack('C*').map { |c|
char = c.chr
char =~ /\w/ ? sprintf("%%%x", c) : char
}.join

content_tag "a", name || email_address_encoded.html_safe, html_options.merge("href" => "#{string}#{extras}".html_safe)
else
content_tag "a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe)
end

content_tag "a", name || email_address.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe)
end

# True if the current request URI was generated by the given +options+.
Expand Down
56 changes: 0 additions & 56 deletions actionpack/test/template/url_helper_test.rb
Expand Up @@ -517,16 +517,6 @@ def test_mail_to
mail_to("david@loudthinking.com", "David Heinemeier Hansson", class: "admin")
end

def test_mail_to_with_javascript
snippet = mail_to("me@domain.com", "My email", encode: "javascript")
assert_dom_equal "<script>eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%5c%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%5c%22%3e%4d%79%20%65%6d%61%69%6c%3c%5c%2f%61%3e%27%29%3b'))</script>", snippet
end

def test_mail_to_with_javascript_unicode
snippet = mail_to("unicode@example.com", "únicode", encode: "javascript")
assert_dom_equal "<script>eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%5c%22%6d%61%69%6c%74%6f%3a%75%6e%69%63%6f%64%65%40%65%78%61%6d%70%6c%65%2e%63%6f%6d%5c%22%3e%c3%ba%6e%69%63%6f%64%65%3c%5c%2f%61%3e%27%29%3b'))</script>", snippet
end

def test_mail_with_options
assert_dom_equal(
%{<a href="mailto:me@example.com?cc=ccaddress%40example.com&amp;bcc=bccaddress%40example.com&amp;body=This%20is%20the%20body%20of%20the%20message.&amp;subject=This%20is%20an%20example%20email">My email</a>},
Expand All @@ -539,54 +529,8 @@ def test_mail_to_with_img
mail_to('feedback@example.com', '<img src="/feedback.png" />'.html_safe)
end

def test_mail_to_with_hex
assert_dom_equal(
%{<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>},
mail_to("me@domain.com", "My email", encode: "hex")
)

assert_dom_equal(
%{<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">&#109;&#101;&#64;&#100;&#111;&#109;&#97;&#105;&#110;&#46;&#99;&#111;&#109;</a>},
mail_to("me@domain.com", nil, encode: "hex")
)
end

def test_mail_to_with_replace_options
assert_dom_equal(
%{<a href="mailto:wolfgang@stufenlos.net">wolfgang(at)stufenlos(dot)net</a>},
mail_to("wolfgang@stufenlos.net", nil, replace_at: "(at)", replace_dot: "(dot)")
)

assert_dom_equal(
%{<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">&#109;&#101;&#40;&#97;&#116;&#41;&#100;&#111;&#109;&#97;&#105;&#110;&#46;&#99;&#111;&#109;</a>},
mail_to("me@domain.com", nil, encode: "hex", replace_at: "(at)")
)

assert_dom_equal(
%{<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">My email</a>},
mail_to("me@domain.com", "My email", encode: "hex", replace_at: "(at)")
)

assert_dom_equal(
%{<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;%6d%65@%64%6f%6d%61%69%6e.%63%6f%6d">&#109;&#101;&#40;&#97;&#116;&#41;&#100;&#111;&#109;&#97;&#105;&#110;&#40;&#100;&#111;&#116;&#41;&#99;&#111;&#109;</a>},
mail_to("me@domain.com", nil, encode: "hex", replace_at: "(at)", replace_dot: "(dot)")
)

assert_dom_equal(
%{<script>eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%5c%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%5c%22%3e%4d%79%20%65%6d%61%69%6c%3c%5c%2f%61%3e%27%29%3b'))</script>},
mail_to("me@domain.com", "My email", encode: "javascript", replace_at: "(at)", replace_dot: "(dot)")
)

assert_dom_equal(
%{<script>eval(decodeURIComponent('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%5c%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%5c%22%3e%6d%65%28%61%74%29%64%6f%6d%61%69%6e%28%64%6f%74%29%63%6f%6d%3c%5c%2f%61%3e%27%29%3b'))</script>},
mail_to("me@domain.com", nil, encode: "javascript", replace_at: "(at)", replace_dot: "(dot)")
)
end

def test_mail_to_returns_html_safe_string
assert mail_to("david@loudthinking.com").html_safe?
assert mail_to("me@domain.com", "My email", encode: "javascript").html_safe?
assert mail_to("me@domain.com", "My email", encode: "hex").html_safe?
end

def protect_against_forgery?
Expand Down

0 comments on commit 153f0cb

Please sign in to comment.