sanitize_email 1.0.0.alpha2 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,6 +1,18 @@
1
- Version 1.0.0.alpha1
2
- - Implementing initial support for Rails >= 3.0 (new ActionMailer API)
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
@@ -2,4 +2,4 @@
2
2
  :major: 1
3
3
  :minor: 0
4
4
  :patch: 0
5
- :build: alpha2
5
+ :build: rc1
@@ -4,18 +4,19 @@ require 'rails'
4
4
  require 'action_mailer'
5
5
 
6
6
  module SanitizeEmail
7
- if defined?(Rails) && ::Rails::VERSION::MAJOR >= 3
8
- require 'sanitize_email/version'
9
- require 'sanitize_email/config'
10
- require 'sanitize_email/sanitizer'
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
- else
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
- :sanitized_recipients => nil,
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
- :local_environments => %w( development test )
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
@@ -5,7 +5,7 @@ module SanitizeEmail
5
5
  class Engine < ::Rails::Engine
6
6
 
7
7
  config.to_prepare do
8
- ActionMailer::Base.register_interceptor(SanitizeEmail::Hook)
8
+ ActionMailer::Base.register_interceptor(SanitizeEmail::Bleach)
9
9
  end
10
10
 
11
11
  end
@@ -5,7 +5,7 @@ module SanitizeEmail
5
5
  class Railtie < ::Rails::Railtie
6
6
 
7
7
  config.before_configuration do
8
- ActionMailer::Base.register_interceptor(SanitizeEmail::Hook)
8
+ ActionMailer::Base.register_interceptor(SanitizeEmail::Bleach)
9
9
  end
10
10
 
11
11
  end
@@ -1,5 +1,5 @@
1
1
  #Copyright (c) 2008-12 Peter H. Boling of 9thBit LLC
2
2
  #Released under the MIT license
3
3
  module SanitizeEmail
4
- VERSION = '1.0.0.alpha2'
4
+ VERSION = '1.0.0.rc1'
5
5
  end
@@ -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.alpha2"
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-07-28"
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"]
@@ -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
- SanitizeEmail::Config.configure do |config|
6
- config[:sanitized_recipients] = 'to@sanitize_email.org'
7
- config[:sanitized_bcc] = 'bcc@sanitize_email.org'
8
- config[:sanitized_cc] = 'cc@sanitize_email.org'
9
- config[:local_environments] = []
10
- config[:use_actual_email_prepended_to_subject] = true
11
- config[:use_actual_email_as_sanitized_user_name] = true
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 sanitize_mail_delivery(sanitization_switch = false)
15
- # Ensure that localish? will returns sanitization_switch
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
- mail = Mail.deliver do
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
- before(:each) do
28
- Launchy.stub(:open)
29
- location = File.expand_path('../tmp/mail_dump', __FILE__)
30
- FileUtils.rm_rf(location)
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
- context "localish? is false" do
39
- it "alters nothing" do
40
- sanitize_mail_delivery(false)
41
- # All the email gets dumped to file once for each type of recipient (:to, :cc, :bcc)
42
- # Each file is identical, so we only need to check one of them:
43
- email = File.read(Dir["#{@location}/*/plain.html"].first)
44
- email.should have_from("from@example.org")
45
- email.should have_to("to@example.org")
46
- # Letter Opener won't let us test the cc
47
- #email.should have_cc("cc@example.org")
48
- # Letter Opener won't let us test the bcc
49
- #email.should have_bcc("cc@example.org")
50
- email.should have_subject("original subject")
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 "localish? is true" do
55
- it "should override" do
56
- sanitize_mail_delivery(true)
57
- # All the email gets dumped to file once for each type of recipient (:to, :cc, :bcc)
58
- # Each file is identical, so we only need to check one of them:
59
- email = File.read(Dir["#{@location}/*/plain.html"].first)
60
- email.should have_from("from@example.org")
61
- # Letter Opener won't let us test the to when the to has a 'user name'
62
- #email.should have_to("~to at example.org~ <to@sanitize_email.org>")
63
- # Letter Opener won't let us test the bcc
64
- #email.should have_cc("cc@sanitize_email.org")
65
- email.should have_subject("(to at example.org) original subject")
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
- container =~ Regexp.new(Regexp.escape(from))
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
- container =~ Regexp.new(Regexp.escape(to))
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
- container =~ Regexp.new(Regexp.escape(cc))
47
+ email_matching(cc, :cc, container)
27
48
  end
28
49
  end
29
50
  # The ActionMailer :file delivery method never prints bcc recipients...
30
- # so not testable as such, but with letter_opener we can work magic
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
- container =~ Regexp.new(Regexp.escape(bcc))
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
- container =~ Regexp.new(Regexp.escape(subject))
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.alpha2
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-07-28 00:00:00.000000000 Z
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: -3597304773529474340
221
+ hash: -2863798588423167662
223
222
  required_rubygems_version: !ruby/object:Gem::Requirement
224
223
  none: false
225
224
  requirements:
@@ -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
-