sanitize_email 1.0.0.alpha2 → 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +14 -2
- data/VERSION.yml +1 -1
- data/lib/sanitize_email.rb +20 -6
- data/lib/sanitize_email/bleach.rb +156 -0
- data/lib/sanitize_email/config.rb +17 -2
- data/lib/sanitize_email/deprecation.rb +36 -0
- data/lib/sanitize_email/engine.rb +1 -1
- data/lib/sanitize_email/railtie.rb +1 -1
- data/lib/sanitize_email/version.rb +1 -1
- data/sanitize_email.gemspec +5 -6
- data/spec/sanitize_email_spec.rb +112 -44
- data/spec/spec_helper.rb +37 -6
- metadata +5 -6
- data/lib/sanitize_email/hook.rb +0 -30
- data/lib/sanitize_email/sanitizer.rb +0 -73
- data/spec/tmp/mail_dump/1343461037_3f3edd7/plain.html +0 -76
data/CHANGELOG
CHANGED
@@ -1,6 +1,18 @@
|
|
1
|
-
Version 1.0.0.
|
2
|
-
-
|
1
|
+
Version 1.0.0.rc1
|
2
|
+
- Added a good_list and a bad_list (whitelist and blacklist)
|
3
|
+
- Added Deprecation library
|
4
|
+
- Refactored Sanitization module into Hook class
|
5
|
+
- Renamed Hook Class to Bleach Class
|
6
|
+
- Improve support for non-rails implementations
|
7
|
+
- Deprecated local_environments in favor of local_environment_proc
|
8
|
+
- Deprecated sanitized_recipients in favor of sanitized_to
|
9
|
+
- More specs
|
10
|
+
|
11
|
+
Version 1.0.0.alpha2
|
12
|
+
- Complete refactor! Implementing initial support for Rails >= 3.0 (new ActionMailer API)
|
3
13
|
- Support for Rails <= 2.X remains in version 0.X.X releases.
|
14
|
+
- NinthBit namespace is now SanitizeEmail namespace
|
15
|
+
- Now has a first class Config class
|
4
16
|
|
5
17
|
XXXXXXXXXXXXXXXXXXXXXXX Rail 3.0+ Only Form here on up! XXXXXXXXXXXXXXXXXXXXXXX
|
6
18
|
|
data/VERSION.yml
CHANGED
data/lib/sanitize_email.rb
CHANGED
@@ -4,18 +4,19 @@ require 'rails'
|
|
4
4
|
require 'action_mailer'
|
5
5
|
|
6
6
|
module SanitizeEmail
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
require 'sanitize_email/hook'
|
7
|
+
require 'sanitize_email/version'
|
8
|
+
require 'sanitize_email/config'
|
9
|
+
require 'sanitize_email/bleach'
|
10
|
+
require 'sanitize_email/deprecation'
|
12
11
|
|
12
|
+
# Allow non-rails implementations to use this gem
|
13
|
+
if @rails = defined?(Rails) && ::Rails::VERSION::MAJOR >= 3
|
13
14
|
if ::Rails::VERSION::MINOR >= 1
|
14
15
|
require 'sanitize_email/engine'
|
15
16
|
elsif ::Rails::VERSION::MINOR == 0
|
16
17
|
require 'sanitize_email/railtie'
|
17
18
|
end
|
18
|
-
|
19
|
+
elsif @rails = defined?(Rails)
|
19
20
|
raise "Please use the 0.X.X versions of sanitize_email for Rails 2.X and below."
|
20
21
|
end
|
21
22
|
|
@@ -28,4 +29,17 @@ module SanitizeEmail
|
|
28
29
|
SanitizeEmail[name]
|
29
30
|
end
|
30
31
|
|
32
|
+
def self.sanitized_recipients
|
33
|
+
SanitizeEmail[:sanitized_recipients]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.local_environments
|
37
|
+
SanitizeEmail[:local_environments]
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
extend SanitizeEmail::Deprecation
|
42
|
+
deprecated_alias :sanitized_recipients, :sanitized_to
|
43
|
+
deprecated :local_environments, :local_environment_proc
|
44
|
+
end
|
31
45
|
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
#Copyright (c) 2008-12 Peter H. Boling of 9thBit LLC
|
2
|
+
#Released under the MIT license
|
3
|
+
|
4
|
+
module SanitizeEmail
|
5
|
+
class Bleach
|
6
|
+
|
7
|
+
class MissingTo < StandardError; end
|
8
|
+
class UnknownOverride < StandardError; end
|
9
|
+
|
10
|
+
# Can override global configs at the instance level.
|
11
|
+
attr_accessor :engage, # Turn sanitization on or off just for this instance
|
12
|
+
:sanitized_to, :sanitized_cc, :sanitized_bcc, # Replace non-white-listed addresses with these sanitized addresses.
|
13
|
+
:good_list, # White-listed addresses will not be molested as to, cc, or bcc
|
14
|
+
:bad_list, # Black-listed addresses will be removed from to, cc and bcc when sanitization is engaged
|
15
|
+
:injected # Track whether or not the subject has been injected with usernames
|
16
|
+
|
17
|
+
def initialize(args = {})
|
18
|
+
# Not using extract_options! because no-rails compatibility is a goal
|
19
|
+
@sanitized_to = args[:sanitized_to] || SanitizeEmail[:sanitized_to]
|
20
|
+
@sanitized_cc = args[:sanitized_cc] || SanitizeEmail[:sanitized_cc]
|
21
|
+
@sanitized_bcc = args[:sanitized_bcc] || SanitizeEmail[:sanitized_bcc]
|
22
|
+
@good_list = args[:good_list] || SanitizeEmail[:good_list] || []
|
23
|
+
@bad_list = args[:bad_list] || SanitizeEmail[:bad_list] || []
|
24
|
+
@engage = args[:engage] || SanitizeEmail[:engage]
|
25
|
+
@injected = false
|
26
|
+
end
|
27
|
+
|
28
|
+
# If all recipient addresses are white-listed the field is left alone.
|
29
|
+
def delivering_email(message)
|
30
|
+
if self.sanitize_engaged?
|
31
|
+
message.subject = self.subject_override(message.subject, message.to) if SanitizeEmail.use_actual_email_prepended_to_subject
|
32
|
+
message.to = self.to_override(message.to)
|
33
|
+
message.cc = self.cc_override(message.cc)
|
34
|
+
message.bcc = self.bcc_override(message.bcc)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Only relevant
|
39
|
+
def consider_local?
|
40
|
+
SanitizeEmail.local_environment_proc.call if SanitizeEmail.local_environment_proc.respond_to?(:call)
|
41
|
+
end
|
42
|
+
|
43
|
+
# This method will be called by the Hook to determine if an override should occur
|
44
|
+
def sanitize_engaged?
|
45
|
+
!SanitizeEmail.force_sanitize.nil? ? SanitizeEmail.force_sanitize : self.consider_local?
|
46
|
+
end
|
47
|
+
|
48
|
+
def subject_override(real_subject, actual_addresses)
|
49
|
+
if !actual_addresses.respond_to?(:join)
|
50
|
+
real_subject
|
51
|
+
else
|
52
|
+
"(#{actual_addresses.join(',').gsub(/@/,' at ').gsub(/[<>]/,'~')}) #{real_subject}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_override(actual_addresses)
|
57
|
+
to = override_email(:to, actual_addresses)
|
58
|
+
raise MissingTo, 'after overriding :to there are no addresses to send in To: header.' if to.empty?
|
59
|
+
to.join(',')
|
60
|
+
end
|
61
|
+
|
62
|
+
def cc_override(actual_addresses)
|
63
|
+
override_email(:cc, actual_addresses).join(',')
|
64
|
+
end
|
65
|
+
|
66
|
+
def bcc_override(actual_addresses)
|
67
|
+
override_email(:bcc, actual_addresses).join(',')
|
68
|
+
end
|
69
|
+
|
70
|
+
#######
|
71
|
+
protected
|
72
|
+
#######
|
73
|
+
|
74
|
+
def address_list_filter(list_type, address)
|
75
|
+
# TODO: How does this handle email addresses with user names like "Foo Example <foo@example.org>"
|
76
|
+
has_address = self.send(list_type).include?(address)
|
77
|
+
case list_type
|
78
|
+
when :good_list then has_address ? address : nil
|
79
|
+
when :bad_list then has_address ? nil : address
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def inject_user_names(real_addresses, sanitized_addresses)
|
84
|
+
real_addresses.inject([]) do |result, real_recipient|
|
85
|
+
if real_recipient.nil?
|
86
|
+
new_recipient = sanitized_addresses
|
87
|
+
else
|
88
|
+
new_recipient = sanitized_addresses.map{|sanitized| "#{real_recipient.gsub(/@/,' at ').gsub(/[<>]/,'~')} <#{sanitized}>"}
|
89
|
+
end
|
90
|
+
result << new_recipient
|
91
|
+
result
|
92
|
+
end.flatten
|
93
|
+
end
|
94
|
+
|
95
|
+
def clean_addresses(addresses, list_type)
|
96
|
+
# Normalize addresses just in case it isn't an array yet
|
97
|
+
addresses.map { |address|
|
98
|
+
# If this address is on the good list then let it pass
|
99
|
+
self.address_list_filter(list_type, address)
|
100
|
+
}.compact
|
101
|
+
end
|
102
|
+
|
103
|
+
def sanitize_addresses(type)
|
104
|
+
case type
|
105
|
+
when :to then Array(self.sanitized_to)
|
106
|
+
when :cc then Array(self.sanitized_cc)
|
107
|
+
when :bcc then Array(self.sanitized_bcc)
|
108
|
+
else raise UnknownOverride, "unknown email override"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Allow good listed email addresses, and then remove the bad listed addresses
|
113
|
+
def good_listize(real_addresses)
|
114
|
+
good_listed = self.clean_addresses(real_addresses, :good_list)
|
115
|
+
good_listed = self.clean_addresses(good_listed, :bad_list) unless good_listed.empty?
|
116
|
+
good_listed
|
117
|
+
end
|
118
|
+
|
119
|
+
def override_email(type, actual_addresses)
|
120
|
+
# Normalized to an arrays
|
121
|
+
#puts "override_email 1: #{type} - #{actual_addresses}"
|
122
|
+
real_addresses = Array(actual_addresses)
|
123
|
+
|
124
|
+
#puts "override_email 2: #{type} - #{real_addresses}"
|
125
|
+
# If there were no original recipients, then we DO NOT override the nil with the sanitized recipients
|
126
|
+
return [] if real_addresses.empty?
|
127
|
+
|
128
|
+
good_listed = good_listize(real_addresses)
|
129
|
+
#puts "override_email 3: #{type} - #{good_listed}"
|
130
|
+
# If there are good_list addresses to send to then use them as is, no mods needed
|
131
|
+
return good_listed unless good_listed.empty?
|
132
|
+
|
133
|
+
# If there are no sanitized addresses we can't override!
|
134
|
+
sanitized_addresses = sanitize_addresses(type)
|
135
|
+
#puts "override_email 3: #{type} - #{sanitized_addresses}"
|
136
|
+
return [] if sanitized_addresses.empty?
|
137
|
+
|
138
|
+
# At this point it is assured that the address list will need to be sanitized
|
139
|
+
# One more check to ensure none of the configured sanitized email addresses are on the bad_list
|
140
|
+
sanitized_addresses = self.clean_addresses(sanitized_addresses, :bad_list)
|
141
|
+
#puts "override_email 4: #{type} - #{sanitized_addresses}"
|
142
|
+
|
143
|
+
# If we don't want to inject the 'email' in the 'user name' section of the sanitized recipients,
|
144
|
+
# then just return the default sanitized recipients
|
145
|
+
return sanitized_addresses unless SanitizeEmail.use_actual_email_as_sanitized_user_name
|
146
|
+
|
147
|
+
with_user_names = self.inject_user_names(real_addresses, sanitized_addresses)
|
148
|
+
#puts "override_email 5: #{type} - #{with_user_names}"
|
149
|
+
# Otherwise inject the email as the 'user name'
|
150
|
+
return with_user_names
|
151
|
+
end
|
152
|
+
|
153
|
+
end # end Class Hook
|
154
|
+
end # end Module SanitizeEmail
|
155
|
+
|
156
|
+
|
@@ -13,7 +13,13 @@ module SanitizeEmail
|
|
13
13
|
|
14
14
|
# The recipient addresses for the messages, either as a string (for a single
|
15
15
|
# address) or an array (for multiple addresses) that go out in 'local' environments
|
16
|
-
:
|
16
|
+
:sanitized_to => nil,
|
17
|
+
|
18
|
+
# a white list
|
19
|
+
:good_list => nil,
|
20
|
+
|
21
|
+
# a black list
|
22
|
+
:bad_list => nil,
|
17
23
|
|
18
24
|
# Use the 'real' email address as the username for the sanitized email address
|
19
25
|
# e.g. "real@example.com <sanitized@example.com>"
|
@@ -23,11 +29,20 @@ module SanitizeEmail
|
|
23
29
|
# e.g. "real@example.com rest of subject"
|
24
30
|
:use_actual_email_prepended_to_subject => false,
|
25
31
|
|
26
|
-
:
|
32
|
+
:local_environment_proc => Proc.new { true }
|
27
33
|
}
|
28
34
|
|
29
35
|
def self.configure &block
|
30
36
|
yield self.config
|
37
|
+
|
38
|
+
# Gracefully handle deprecated config values.
|
39
|
+
# Actual deprecation warnings are thrown in the top SanitizeEmail module thanks to our use of dynamic methods.
|
40
|
+
if config[:local_environments] && defined?(Rails)
|
41
|
+
config[:local_environment_proc] = Proc.new { SanitizeEmail.local_environments.include?(Rails.env) }
|
42
|
+
end
|
43
|
+
if config[:sanitize_recipients]
|
44
|
+
config[:sanitize_to] = SanitizeEmail.sanitized_recipients
|
45
|
+
end
|
31
46
|
end
|
32
47
|
|
33
48
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# See http://www.seejohncode.com/2012/01/09/deprecating-methods-in-ruby/
|
2
|
+
|
3
|
+
module SanitizeEmail
|
4
|
+
module Deprecation
|
5
|
+
|
6
|
+
# Define a deprecated alias for a method
|
7
|
+
# @param [Symbol] name - name of method to define
|
8
|
+
# @param [Symbol] replacement - name of method to (alias)
|
9
|
+
def deprecated_alias(name, replacement)
|
10
|
+
# Create a wrapped version
|
11
|
+
define_method(name) do |*args, &block|
|
12
|
+
warn "SanitizeEmail: ##{name} deprecated (please use ##{replacement})"
|
13
|
+
send replacement, *args, &block
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Deprecate a defined method
|
18
|
+
# @param [Symbol] name - name of deprecated method
|
19
|
+
# @param [Symbol] replacement - name of the desired replacement
|
20
|
+
def deprecated(name, replacement = nil)
|
21
|
+
# Replace old method
|
22
|
+
old_name = :"#{name}_without_deprecation"
|
23
|
+
alias_method old_name, name
|
24
|
+
# And replace it with a wrapped version
|
25
|
+
define_method(name) do |*args, &block|
|
26
|
+
if replacement
|
27
|
+
warn "SanitizeEmail: ##{name} deprecated (please use ##{replacement})"
|
28
|
+
else
|
29
|
+
warn "SanitizeEmail: ##{name} deprecated"
|
30
|
+
end
|
31
|
+
send old_name, *args, &block
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/sanitize_email.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "sanitize_email"
|
8
|
-
s.version = "1.0.0.
|
8
|
+
s.version = "1.0.0.rc1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Peter Boling", "John Trupiano", "George Anderson"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-08-04"
|
13
13
|
s.description = "Tool to aid in development, testing, qa, and production troubleshooting of email issues without worrying that emails will get sent to actual live addresses."
|
14
14
|
s.email = ["peter.boling@gmail.com", "jtrupiano@gmail.com", "george@benevolentcode.com"]
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,16 +26,15 @@ Gem::Specification.new do |s|
|
|
26
26
|
"VERSION.yml",
|
27
27
|
"init.rb",
|
28
28
|
"lib/sanitize_email.rb",
|
29
|
+
"lib/sanitize_email/bleach.rb",
|
29
30
|
"lib/sanitize_email/config.rb",
|
31
|
+
"lib/sanitize_email/deprecation.rb",
|
30
32
|
"lib/sanitize_email/engine.rb",
|
31
|
-
"lib/sanitize_email/hook.rb",
|
32
33
|
"lib/sanitize_email/railtie.rb",
|
33
|
-
"lib/sanitize_email/sanitizer.rb",
|
34
34
|
"lib/sanitize_email/version.rb",
|
35
35
|
"sanitize_email.gemspec",
|
36
36
|
"spec/sanitize_email_spec.rb",
|
37
|
-
"spec/spec_helper.rb"
|
38
|
-
"spec/tmp/mail_dump/1343461037_3f3edd7/plain.html"
|
37
|
+
"spec/spec_helper.rb"
|
39
38
|
]
|
40
39
|
s.homepage = "http://github.com/pboling/sanitize_email"
|
41
40
|
s.licenses = ["MIT"]
|
data/spec/sanitize_email_spec.rb
CHANGED
@@ -1,68 +1,136 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
#
|
4
|
+
# TODO: Letter Opener should *not* be required, but setting the delivery method to :file was causing connection errors... WTF?
|
5
|
+
#
|
6
|
+
# Letter Opener won't let us test the to when the to has a 'user name'
|
7
|
+
# @email_file.should have_to("~to at example.org~ <to@sanitize_email.org>")
|
8
|
+
# TODO: Also not sure how to test the user name part of the To: header via the mail object
|
9
|
+
#
|
10
|
+
# Letter Opener won't let us test the bcc
|
11
|
+
# @email_file.should have_cc("cc@sanitize_email.org")
|
12
|
+
# Fortunately we can still test the mail object returned by the deliver call
|
13
|
+
#
|
14
|
+
|
3
15
|
describe SanitizeEmail do
|
4
16
|
|
5
|
-
|
6
|
-
config
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
17
|
+
after(:each) do
|
18
|
+
SanitizeEmail::Config.config = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def sanitize_spec_dryer(rails_env = 'test')
|
22
|
+
Launchy.stub(:open)
|
23
|
+
location = File.expand_path('../tmp/mail_dump', __FILE__)
|
24
|
+
FileUtils.rm_rf(location)
|
25
|
+
Mail.defaults do
|
26
|
+
delivery_method LetterOpener::DeliveryMethod, :location => location
|
27
|
+
end
|
28
|
+
Rails.stub(:env).and_return(rails_env)
|
29
|
+
@location = location
|
30
|
+
end
|
31
|
+
|
32
|
+
def configure_sanitize_email(sanitize_hash = {})
|
33
|
+
sanitize_hash.reverse_merge!({
|
34
|
+
:sanitized_to => 'to@sanitize_email.org',
|
35
|
+
:sanitized_cc => 'cc@sanitize_email.org',
|
36
|
+
:sanitized_bcc => 'bcc@sanitize_email.org',
|
37
|
+
:use_actual_email_prepended_to_subject => true,
|
38
|
+
:use_actual_email_as_sanitized_user_name => true
|
39
|
+
})
|
40
|
+
SanitizeEmail::Config.configure do |config|
|
41
|
+
config[:sanitized_to] = sanitize_hash[:sanitized_to]
|
42
|
+
config[:sanitized_cc] = sanitize_hash[:sanitized_cc]
|
43
|
+
config[:sanitized_bcc] = sanitize_hash[:sanitized_bcc]
|
44
|
+
config[:use_actual_email_prepended_to_subject] = sanitize_hash[:use_actual_email_prepended_to_subject]
|
45
|
+
config[:use_actual_email_as_sanitized_user_name] = sanitize_hash[:use_actual_email_as_sanitized_user_name]
|
46
|
+
# For testing deprecated configuration options:
|
47
|
+
config[:local_environments] = sanitize_hash[:local_environments] if sanitize_hash[:local_environments]
|
48
|
+
config[:sanitized_to] ||= sanitize_hash[:sanitized_recipients] if sanitize_hash[:sanitized_recipients]
|
49
|
+
end
|
50
|
+
Mail.register_interceptor(SanitizeEmail::Bleach.new)
|
12
51
|
end
|
13
52
|
|
14
|
-
def
|
15
|
-
# Ensure that localish? will
|
53
|
+
def sanitized_mail_delivery(sanitization_switch = false)
|
54
|
+
# Ensure that localish? will return sanitization_switch if true or false, and use proc when nil
|
16
55
|
SanitizeEmail::Config.config[:force_sanitize] = sanitization_switch
|
17
56
|
Launchy.should_receive(:open)
|
18
|
-
|
57
|
+
@mail_message = Mail.deliver do
|
19
58
|
from 'from@example.org'
|
20
59
|
to 'to@example.org'
|
21
60
|
cc 'cc@example.org'
|
61
|
+
bcc 'bcc@example.org'
|
22
62
|
reply_to 'reply_to@example.org'
|
23
63
|
subject 'original subject'
|
24
64
|
end
|
65
|
+
# All the email gets dumped to file once for each type of recipient (:to, :cc, :bcc)
|
66
|
+
# Each file is identical, so we only need to check one of them:
|
67
|
+
@email_file = File.read(Dir["#{@location}/*/plain.html"].first)
|
25
68
|
end
|
26
69
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
Mail.defaults do
|
32
|
-
delivery_method LetterOpener::DeliveryMethod, :location => location
|
70
|
+
context "localish?" do
|
71
|
+
before(:each) do
|
72
|
+
sanitize_spec_dryer
|
73
|
+
configure_sanitize_email
|
33
74
|
end
|
34
|
-
Mail.register_interceptor(SanitizeEmail::Hook)
|
35
|
-
@location = location
|
36
|
-
end
|
37
75
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
76
|
+
context "false" do
|
77
|
+
it "alters nothing" do
|
78
|
+
sanitized_mail_delivery(false)
|
79
|
+
@email_file.should have_from("from@example.org")
|
80
|
+
@email_file.should have_to("to@example.org")
|
81
|
+
@mail_message.header.fields[3].value.should_not have_to("to at example.org")
|
82
|
+
@mail_message.should have_cc("cc@example.org")
|
83
|
+
@mail_message.should have_bcc("bcc@example.org")
|
84
|
+
@email_file.should have_subject("original subject")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "true" do
|
89
|
+
it "should override" do
|
90
|
+
sanitized_mail_delivery(true)
|
91
|
+
@email_file.should have_from("from@example.org")
|
92
|
+
#puts "@mail_message.header.fields[3]: #{@mail_message.header.fields[3]}"
|
93
|
+
#@mail_message.header.fields[3].value.should have_to("to at example.org")
|
94
|
+
@mail_message.should have_cc("cc@sanitize_email.org")
|
95
|
+
@mail_message.should have_bcc("bcc@sanitize_email.org")
|
96
|
+
@email_file.should have_subject("(to at example.org) original subject")
|
97
|
+
end
|
51
98
|
end
|
52
99
|
end
|
53
100
|
|
54
|
-
context "
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
101
|
+
context "deprecated config options" do
|
102
|
+
context "local_environments" do
|
103
|
+
it "should use local_environment_proc for matching environment" do
|
104
|
+
sanitize_spec_dryer('test')
|
105
|
+
configure_sanitize_email({:local_environments => ['test']})
|
106
|
+
SanitizeEmail[:local_environment_proc].call.should == true
|
107
|
+
sanitized_mail_delivery(nil)
|
108
|
+
@email_file.should have_to("to@sanitize_email.org")
|
109
|
+
@email_file.should have_subject("(to at example.org) original subject")
|
110
|
+
end
|
111
|
+
it "should use local_environment_proc for non-matching environment" do
|
112
|
+
sanitize_spec_dryer('production')
|
113
|
+
configure_sanitize_email({:local_environments => ['development']}) # Won't match!
|
114
|
+
SanitizeEmail[:local_environment_proc].call.should == false
|
115
|
+
sanitized_mail_delivery(nil)
|
116
|
+
@mail_message.should_not have_subject("to at example.org")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "sanitized_recipients is set" do
|
121
|
+
before(:each) do
|
122
|
+
sanitize_spec_dryer
|
123
|
+
configure_sanitize_email({:sanitized_recipients => 'barney@sanitize_email.org'})
|
124
|
+
end
|
125
|
+
it "used as sanitized_to" do
|
126
|
+
sanitized_mail_delivery(true)
|
127
|
+
@email_file.should have_from("from@example.org")
|
128
|
+
@mail_message.should have_to("to@sanitize_email.org")
|
129
|
+
@email_file.should have_subject("(to at example.org) original subject")
|
130
|
+
end
|
66
131
|
end
|
67
132
|
end
|
133
|
+
|
68
134
|
end
|
135
|
+
|
136
|
+
#TODO: test good_list
|
data/spec/spec_helper.rb
CHANGED
@@ -11,30 +11,61 @@ RSpec.configure do |config|
|
|
11
11
|
#config.filter_run :focus
|
12
12
|
end
|
13
13
|
|
14
|
+
module EmailMatcherHelpers
|
15
|
+
class UnexpectedMailType < StandardError; end
|
16
|
+
|
17
|
+
# Sweet, nourishing recursion
|
18
|
+
def email_matching(matcher, part, mail_or_part)
|
19
|
+
if mail_or_part.respond_to?(part)
|
20
|
+
email_matching(matcher, part, mail_or_part.send(part))
|
21
|
+
elsif mail_or_part.respond_to?(:join)
|
22
|
+
email_matching(matcher, part, mail_or_part.join(', '))
|
23
|
+
elsif mail_or_part.respond_to?(:=~) # Can we match a regex against it?
|
24
|
+
mail_or_part =~ Regexp.new(Regexp.escape(matcher))
|
25
|
+
else
|
26
|
+
raise UnexpectedMailType, "Cannot match #{matcher} for #{part}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
14
32
|
RSpec::Matchers.define :have_from do |from|
|
33
|
+
include EmailMatcherHelpers
|
15
34
|
match do |container|
|
16
|
-
|
35
|
+
email_matching(from, :from, container)
|
17
36
|
end
|
18
37
|
end
|
19
38
|
RSpec::Matchers.define :have_to do |to|
|
39
|
+
include EmailMatcherHelpers
|
20
40
|
match do |container|
|
21
|
-
|
41
|
+
email_matching(to, :to, container)
|
22
42
|
end
|
23
43
|
end
|
24
44
|
RSpec::Matchers.define :have_cc do |cc|
|
45
|
+
include EmailMatcherHelpers
|
25
46
|
match do |container|
|
26
|
-
|
47
|
+
email_matching(cc, :cc, container)
|
27
48
|
end
|
28
49
|
end
|
29
50
|
# The ActionMailer :file delivery method never prints bcc recipients...
|
30
|
-
#
|
51
|
+
# Neither does LetterOpener :(
|
52
|
+
# But the mail object itself can be tested!
|
31
53
|
RSpec::Matchers.define :have_bcc do |bcc|
|
54
|
+
include EmailMatcherHelpers
|
32
55
|
match do |container|
|
33
|
-
|
56
|
+
email_matching(bcc, :bcc, container)
|
34
57
|
end
|
35
58
|
end
|
36
59
|
RSpec::Matchers.define :have_subject do |subject|
|
60
|
+
include EmailMatcherHelpers
|
37
61
|
match do |container|
|
38
|
-
|
62
|
+
email_matching(subject, :subject, container)
|
39
63
|
end
|
40
64
|
end
|
65
|
+
|
66
|
+
#RSpec::Matchers.define :have_to_username do |to|
|
67
|
+
# include EmailMatcherHelpers
|
68
|
+
# match do |container|
|
69
|
+
# email_matching(to, :, container)
|
70
|
+
# end
|
71
|
+
#end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sanitize_email
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-
|
14
|
+
date: 2012-08-04 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
@@ -194,16 +194,15 @@ files:
|
|
194
194
|
- VERSION.yml
|
195
195
|
- init.rb
|
196
196
|
- lib/sanitize_email.rb
|
197
|
+
- lib/sanitize_email/bleach.rb
|
197
198
|
- lib/sanitize_email/config.rb
|
199
|
+
- lib/sanitize_email/deprecation.rb
|
198
200
|
- lib/sanitize_email/engine.rb
|
199
|
-
- lib/sanitize_email/hook.rb
|
200
201
|
- lib/sanitize_email/railtie.rb
|
201
|
-
- lib/sanitize_email/sanitizer.rb
|
202
202
|
- lib/sanitize_email/version.rb
|
203
203
|
- sanitize_email.gemspec
|
204
204
|
- spec/sanitize_email_spec.rb
|
205
205
|
- spec/spec_helper.rb
|
206
|
-
- spec/tmp/mail_dump/1343461037_3f3edd7/plain.html
|
207
206
|
homepage: http://github.com/pboling/sanitize_email
|
208
207
|
licenses:
|
209
208
|
- MIT
|
@@ -219,7 +218,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
219
218
|
version: '0'
|
220
219
|
segments:
|
221
220
|
- 0
|
222
|
-
hash: -
|
221
|
+
hash: -2863798588423167662
|
223
222
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
224
223
|
none: false
|
225
224
|
requirements:
|
data/lib/sanitize_email/hook.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
#Copyright (c) 2008-12 Peter H. Boling of 9thBit LLC
|
2
|
-
#Released under the MIT license
|
3
|
-
|
4
|
-
module SanitizeEmail
|
5
|
-
class Hook
|
6
|
-
|
7
|
-
include SanitizeEmail::Sanitizer
|
8
|
-
|
9
|
-
def self.delivering_email(message)
|
10
|
-
if self.localish?
|
11
|
-
message.subject = self.subject_override(message.subject, message.to)
|
12
|
-
message.to = self.recipients_override(message.to)
|
13
|
-
message.cc = self.cc_override(message.cc)
|
14
|
-
message.bcc = self.bcc_override(message.bcc)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.consider_local?
|
19
|
-
SanitizeEmail.local_environments.include?(Rails.env) if defined?(Rails)
|
20
|
-
end
|
21
|
-
|
22
|
-
# This method will be called by the Hook to determine if an override should occur
|
23
|
-
def self.localish?
|
24
|
-
!SanitizeEmail.force_sanitize.nil? ? SanitizeEmail.force_sanitize : self.consider_local?
|
25
|
-
end
|
26
|
-
|
27
|
-
end # end Class Hook
|
28
|
-
end # end Module SanitizeEmail
|
29
|
-
|
30
|
-
|
@@ -1,73 +0,0 @@
|
|
1
|
-
#Copyright (c) 2008-12 Peter H. Boling of 9thBit LLC
|
2
|
-
#Released under the MIT license
|
3
|
-
module SanitizeEmail
|
4
|
-
module Sanitizer
|
5
|
-
def self.included(base)
|
6
|
-
base.extend SanitizeEmail::Sanitizer::ClassMethods
|
7
|
-
end
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
|
11
|
-
def subject_override(real_subject, actual_addresses)
|
12
|
-
if actual_addresses.nil? || !SanitizeEmail.use_actual_email_prepended_to_subject
|
13
|
-
real_subject
|
14
|
-
else
|
15
|
-
"(#{actual_addresses.join(',').gsub(/@/,' at ').gsub(/[<>]/,'~')}) #{real_subject}"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def recipients_override(actual_addresses)
|
20
|
-
override_email(:recipients, actual_addresses)
|
21
|
-
end
|
22
|
-
|
23
|
-
def cc_override(actual_addresses)
|
24
|
-
override_email(:cc, actual_addresses)
|
25
|
-
end
|
26
|
-
|
27
|
-
def bcc_override(actual_addresses)
|
28
|
-
override_email(:bcc, actual_addresses)
|
29
|
-
end
|
30
|
-
|
31
|
-
#######
|
32
|
-
private
|
33
|
-
#######
|
34
|
-
|
35
|
-
def override_email(type, actual_addresses)
|
36
|
-
real_addresses, sanitized_addresses = case type
|
37
|
-
when :recipients
|
38
|
-
[actual_addresses, SanitizeEmail.sanitized_recipients]
|
39
|
-
when :cc
|
40
|
-
[actual_addresses, SanitizeEmail.sanitized_cc]
|
41
|
-
when :bcc
|
42
|
-
[actual_addresses, SanitizeEmail.sanitized_bcc]
|
43
|
-
else raise "sanitize_email error: unknown email override"
|
44
|
-
end
|
45
|
-
# Normalize to an array
|
46
|
-
real_addresses = [real_addresses] unless real_addresses.is_a?(Array)
|
47
|
-
# Normalize to an array
|
48
|
-
sanitized_addresses = [sanitized_addresses] unless sanitized_addresses.is_a?(Array)
|
49
|
-
|
50
|
-
# If there were no original recipients, then we DO NOT override the nil with the sanitized recipients
|
51
|
-
return nil if real_addresses.blank?
|
52
|
-
# If there are no sanitized addresses we can't override!
|
53
|
-
return nil if sanitized_addresses.blank?
|
54
|
-
# If we don't want to inject the actual email in the 'user name' section of the sanitized recipients,
|
55
|
-
# then just return the default sanitized recipients
|
56
|
-
return sanitized_addresses unless SanitizeEmail.use_actual_email_as_sanitized_user_name
|
57
|
-
|
58
|
-
out = real_addresses.inject([]) do |result, real_recipient|
|
59
|
-
if real_recipient.nil?
|
60
|
-
new_recipient = sanitized_addresses
|
61
|
-
else
|
62
|
-
new_recipient = sanitized_addresses.map{|sanitized| "#{real_recipient.gsub(/@/,' at ').gsub(/[<>]/,'~')} <#{sanitized}>"}
|
63
|
-
end
|
64
|
-
result << new_recipient
|
65
|
-
result
|
66
|
-
end.flatten
|
67
|
-
return out
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
end
|
@@ -1,76 +0,0 @@
|
|
1
|
-
<style type="text/css">
|
2
|
-
#message_headers {
|
3
|
-
position: absolute;
|
4
|
-
top: 0px;
|
5
|
-
left: 0;
|
6
|
-
width: 100%;
|
7
|
-
height: 85px;
|
8
|
-
padding: 10px 0 0 0;
|
9
|
-
margin: 0;
|
10
|
-
background: #fff;
|
11
|
-
font-size: 12px;
|
12
|
-
font-family: "Lucida Grande";
|
13
|
-
border-bottom: 1px solid #dedede;
|
14
|
-
overflow: hidden;
|
15
|
-
}
|
16
|
-
|
17
|
-
#message_headers dl {
|
18
|
-
margin: 0;
|
19
|
-
padding: 0;
|
20
|
-
}
|
21
|
-
|
22
|
-
#message_headers dt {
|
23
|
-
width: 60px;
|
24
|
-
padding: 1px;
|
25
|
-
float: left;
|
26
|
-
text-align: right;
|
27
|
-
font-weight: bold;
|
28
|
-
color: #7f7f7f;
|
29
|
-
}
|
30
|
-
|
31
|
-
#message_headers dd {
|
32
|
-
margin-left: 70px;
|
33
|
-
padding: 1px;
|
34
|
-
}
|
35
|
-
|
36
|
-
#message_headers p.alternate {
|
37
|
-
position: absolute;
|
38
|
-
top: 0;
|
39
|
-
right: 15px;
|
40
|
-
}
|
41
|
-
|
42
|
-
#message_headers p.alternate a {
|
43
|
-
color: #09c;
|
44
|
-
}
|
45
|
-
|
46
|
-
pre#message_body {
|
47
|
-
padding: 10px;
|
48
|
-
word-wrap: break-word;
|
49
|
-
}
|
50
|
-
|
51
|
-
body {
|
52
|
-
margin-top: 96px;
|
53
|
-
}
|
54
|
-
</style>
|
55
|
-
|
56
|
-
<div id="message_headers">
|
57
|
-
<dl>
|
58
|
-
<dt>From:</dt>
|
59
|
-
<dd>from@example.org</dd>
|
60
|
-
|
61
|
-
<dt>Subject:</dt>
|
62
|
-
<dd><strong>(to at example.org) original subject</strong></dd>
|
63
|
-
|
64
|
-
<dt>Date:</dt>
|
65
|
-
<dd>Jul 28, 2012 03:37:17 AM EDT</dd>
|
66
|
-
|
67
|
-
<dt>To:</dt>
|
68
|
-
<dd>to@sanitize_email.org</dd>
|
69
|
-
</dl>
|
70
|
-
|
71
|
-
|
72
|
-
</div>
|
73
|
-
|
74
|
-
|
75
|
-
<pre id="message_body"></pre>
|
76
|
-
|