aws-ses 0.6.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d83b84b06b584bdb5c4643e75dde6cd185d7b54
4
- data.tar.gz: f7c7c7d108a5e87ba91b5249f2e8795a6ace7606
3
+ metadata.gz: 649f6d5775f0057147e1b411dd5f43af48812bf2
4
+ data.tar.gz: b3b7fd033599ef3678b3c93d0ed6f0456bcef2d5
5
5
  SHA512:
6
- metadata.gz: bd17ce170e886f373038bbee96b593398ad2f9a1397bcce409cc7d9c0ecdcd6adceca4756d9380b7d114cc503797065de349df675ff409d1a8ab8806c147e00b
7
- data.tar.gz: 97d79a71412f8bf55659ac2bca9697072b5ad0a7ec6531d45ab249d56e817f6b56f0f432b1a2f21acdf9a5cb3c68869dd3aa5f50ae853828b6cc9bd25a46fd47
6
+ metadata.gz: d8e1a237725651f2e99fcc6a8207466df258b9ce466058ca13287a9f6e16f9fbd60fcb6690a54cbafe382131149180e2474e23dad3d02e56d6e261b7895f8bcb
7
+ data.tar.gz: 776c4d15557c85664f81dbcbd49caf401a48d4e21bc7beb01846688055da1b3d243e7ad1040e82742e9167d46f9d46b193359256a438c711b6f4659068462db4
data/CHANGELOG CHANGED
@@ -1,4 +1,14 @@
1
- 0.4.5:
1
+ 0.7.1:
2
+ * Bugfix in sig version v4 detection
3
+
4
+ 0.7.0:
5
+ * Implement Authorization Header v4 (add config: `signature_version: 4`)
6
+ * Wrap message ID in `<>` correctly
7
+
8
+ 0.6.0:
9
+ * Various small bug fixes
10
+
11
+ 0.5.0:
2
12
  * Check for existence of html or text body when attachments are included
3
13
  * Message ids in mail objects should now reflect what is actually sent.
4
14
 
data/Gemfile CHANGED
@@ -6,13 +6,16 @@ source "http://rubygems.org"
6
6
  # Add dependencies to develop your gem here.
7
7
  # Include everything needed to run rake, tests, features, etc.
8
8
  group :development do
9
- gem "shoulda-context", ">= 0"
10
- gem "bundler"
11
- #gem "rcov", ">= 0"
9
+ gem "bundler", ">= 1.17"
12
10
  gem 'flexmock', '~> 0.8.11'
11
+ gem "jeweler"
12
+ gem "rake"
13
+ gem "shoulda-context", ">= 0"
14
+ gem 'test-unit'
15
+ gem 'timecop'
13
16
  end
14
17
 
15
- gem 'xml-simple'
16
18
  gem 'builder'
17
- gem 'mime-types'
18
19
  gem 'mail', '> 2.2.5'
20
+ gem 'mime-types'
21
+ gem 'xml-simple'
data/Gemfile.lock CHANGED
@@ -1,12 +1,63 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ addressable (2.4.0)
4
5
  builder (3.2.2)
6
+ descendants_tracker (0.0.4)
7
+ thread_safe (~> 0.3, >= 0.3.1)
8
+ faraday (0.9.2)
9
+ multipart-post (>= 1.2, < 3)
5
10
  flexmock (0.8.11)
11
+ git (1.7.0)
12
+ rchardet (~> 1.8)
13
+ github_api (0.16.0)
14
+ addressable (~> 2.4.0)
15
+ descendants_tracker (~> 0.0.4)
16
+ faraday (~> 0.8, < 0.10)
17
+ hashie (>= 3.4)
18
+ mime-types (>= 1.16, < 3.0)
19
+ oauth2 (~> 1.0)
20
+ hashie (4.1.0)
21
+ highline (2.0.3)
22
+ jeweler (2.3.9)
23
+ builder
24
+ bundler
25
+ git (>= 1.2.5)
26
+ github_api (~> 0.16.0)
27
+ highline (>= 1.6.15)
28
+ nokogiri (>= 1.5.10)
29
+ psych
30
+ rake
31
+ rdoc
32
+ semver2
33
+ jwt (2.2.2)
6
34
  mail (2.6.1)
7
35
  mime-types (>= 1.16, < 3)
8
36
  mime-types (2.4.1)
37
+ mini_portile2 (2.4.0)
38
+ multi_json (1.15.0)
39
+ multi_xml (0.6.0)
40
+ multipart-post (2.1.1)
41
+ nokogiri (1.10.10)
42
+ mini_portile2 (~> 2.4.0)
43
+ oauth2 (1.4.4)
44
+ faraday (>= 0.8, < 2.0)
45
+ jwt (>= 1.0, < 3.0)
46
+ multi_json (~> 1.3)
47
+ multi_xml (~> 0.5)
48
+ rack (>= 1.2, < 3)
49
+ power_assert (1.2.0)
50
+ psych (3.1.0)
51
+ rack (2.2.3)
52
+ rake (13.0.1)
53
+ rchardet (1.8.0)
54
+ rdoc (6.2.0)
55
+ semver2 (3.4.2)
9
56
  shoulda-context (1.2.1)
57
+ test-unit (3.3.6)
58
+ power_assert
59
+ thread_safe (0.3.6)
60
+ timecop (0.9.1)
10
61
  xml-simple (1.1.4)
11
62
 
12
63
  PLATFORMS
@@ -14,9 +65,16 @@ PLATFORMS
14
65
 
15
66
  DEPENDENCIES
16
67
  builder
17
- bundler
68
+ bundler (>= 1.17)
18
69
  flexmock (~> 0.8.11)
70
+ jeweler
19
71
  mail (> 2.2.5)
20
72
  mime-types
73
+ rake
21
74
  shoulda-context
75
+ test-unit
76
+ timecop
22
77
  xml-simple
78
+
79
+ BUNDLED WITH
80
+ 1.17.3
data/README.erb CHANGED
@@ -16,11 +16,11 @@
16
16
 
17
17
  == Rails
18
18
 
19
- This gem is compatible with Rails >= 3.0.0 and Rails 2.3.x
19
+ This gem is compatible with Rails >= 3.0.0 and Ruby 2.3.x
20
20
 
21
21
  To use, first add the gem to your Gemfile:
22
22
 
23
- gem "aws-ses", "~> 0.6.0", :require => 'aws/ses'
23
+ gem "aws-ses", "~> 0.7.1", :require => 'aws/ses'
24
24
 
25
25
  == For Rails 3.x
26
26
 
@@ -28,7 +28,8 @@ Then, add your Amazon credentials and extend ActionMailer in `config/initializer
28
28
 
29
29
  ActionMailer::Base.add_delivery_method :ses, AWS::SES::Base,
30
30
  :access_key_id => 'abc',
31
- :secret_access_key => '123'
31
+ :secret_access_key => '123',
32
+ :signature_version => 4
32
33
 
33
34
  Then set the delivery method in `config/environments/*rb` as appropriate:
34
35
 
@@ -77,7 +78,7 @@ Available at: https://github.com/drewblas/aws-ses
77
78
 
78
79
  == Copyright
79
80
 
80
- Copyright (c) 2011 Drew Blas. See LICENSE for further details.
81
+ Copyright (c) 2020 Drew Blas. See LICENSE for further details.
81
82
 
82
83
  == Thanks
83
84
 
@@ -90,3 +91,5 @@ Special thanks to Marcel Molina Jr. for his creation of AWS::S3 which I used por
90
91
  * sshaw
91
92
  * teeparham (documentation)
92
93
  * pzb
94
+ * NicholasHely
95
+ * m33h
data/README.rdoc CHANGED
@@ -28,7 +28,8 @@ To connect to a different one, just pass it as a parameter to the AWS::SES::Base
28
28
  ses = AWS::SES::Base.new(
29
29
  :access_key_id => 'abc',
30
30
  :secret_access_key => '123',
31
- :server => 'email.eu-west-1.amazonaws.com'
31
+ :server => 'email.eu-west-1.amazonaws.com',
32
+ :message_id_domain => 'eu-west-1.amazonses.com'
32
33
  )
33
34
 
34
35
  == Send E-mail
@@ -134,14 +135,13 @@ will return:
134
135
  "Rejects"=>"0",
135
136
  "Complaints"=>"0"}]
136
137
 
137
-
138
138
  == Rails
139
139
 
140
- This gem is compatible with Rails >= 3.0.0 and Rails 2.3.x
140
+ This gem is compatible with Rails >= 3.0.0 and Ruby 2.3.x
141
141
 
142
142
  To use, first add the gem to your Gemfile:
143
143
 
144
- gem "aws-ses", "~> 0.6.0", :require => 'aws/ses'
144
+ gem "aws-ses", "~> 0.7.0", :require => 'aws/ses'
145
145
 
146
146
  == For Rails 3.x
147
147
 
@@ -149,9 +149,10 @@ Then, add your Amazon credentials and extend ActionMailer in `config/initializer
149
149
 
150
150
  ActionMailer::Base.add_delivery_method :ses, AWS::SES::Base,
151
151
  :access_key_id => 'abc',
152
- :secret_access_key => '123'
152
+ :secret_access_key => '123',
153
+ :signature_version => 4
153
154
 
154
- Then set the delivery method in `config/environments/*rb` as appropriate:
155
+ Then set the delivery method in `config/environments/*.rb` as appropriate:
155
156
 
156
157
  config.action_mailer.delivery_method = :ses
157
158
 
@@ -179,8 +180,12 @@ It means that you are not running with SSL enabled in ruby. Re-compile ruby wit
179
180
  If you are receiving this message and you HAVE verified the [source] please <b>check to be sure you are not in sandbox mode!</b>
180
181
  "Email address is not verified.MessageRejected (AWS::Error)"
181
182
  If you have not been granted production access, you will have to <b>verify all recipients</b> as well.
182
-
183
- http://docs.amazonwebservices.com/ses/2010-12-01/DeveloperGuide/index.html?InitialSetup.Customer.html
183
+
184
+ To verify email addresses and domains:
185
+ https://docs.aws.amazon.com/ses/latest/DeveloperGuide/verify-addresses-and-domains.html
186
+
187
+ To request production access:
188
+ https://docs.aws.amazon.com/ses/latest/DeveloperGuide/request-production-access.html
184
189
 
185
190
  == Source
186
191
 
data/Rakefile CHANGED
@@ -67,3 +67,17 @@ namespace :doc do
67
67
  end
68
68
  end
69
69
  end
70
+
71
+ require 'jeweler'
72
+ Jeweler::Tasks.new do |gem|
73
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
74
+ gem.name = "aws-ses"
75
+ gem.homepage = "http://github.com/drewblas/aws-ses"
76
+ gem.license = "MIT"
77
+ gem.summary = "Client library for Amazon's Simple Email Service's REST API"
78
+ gem.description = "Client library for Amazon's Simple Email Service's REST API"
79
+ gem.email = "drew.blas@gmail.com"
80
+ gem.authors = ["Drew Blas", "Marcel Molina Jr."]
81
+ # dependencies defined in Gemfile
82
+ end
83
+ Jeweler::RubygemsDotOrgTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.7.1
data/aws-ses.gemspec CHANGED
@@ -2,17 +2,20 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
+ # stub: aws-ses 0.7.1 ruby lib
5
6
 
6
7
  Gem::Specification.new do |s|
7
- s.name = "aws-ses"
8
- s.version = "0.6.0"
8
+ s.name = "aws-ses".freeze
9
+ s.version = "0.7.1"
9
10
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Drew Blas", "Marcel Molina Jr."]
12
- s.date = "2014-10-13"
13
- s.description = "Client library for Amazon's Simple Email Service's REST API"
14
- s.email = "drew.blas@gmail.com"
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib".freeze]
13
+ s.authors = ["Drew Blas".freeze, "Marcel Molina Jr.".freeze]
14
+ s.date = "2020-09-30"
15
+ s.description = "Client library for Amazon's Simple Email Service's REST API".freeze
16
+ s.email = "drew.blas@gmail.com".freeze
15
17
  s.extra_rdoc_files = [
18
+ "CHANGELOG",
16
19
  "LICENSE",
17
20
  "README.erb",
18
21
  "README.rdoc",
@@ -49,48 +52,51 @@ Gem::Specification.new do |s|
49
52
  "test/response_test.rb",
50
53
  "test/send_email_test.rb"
51
54
  ]
52
- s.homepage = "http://github.com/drewblas/aws-ses"
53
- s.licenses = ["MIT"]
54
- s.require_paths = ["lib"]
55
- s.rubygems_version = "1.8.19"
56
- s.summary = "Client library for Amazon's Simple Email Service's REST API"
57
- s.test_files = [
58
- "test/address_test.rb",
59
- "test/base_test.rb",
60
- "test/extensions_test.rb",
61
- "test/fixtures.rb",
62
- "test/helper.rb",
63
- "test/info_test.rb",
64
- "test/mocks/fake_response.rb",
65
- "test/response_test.rb",
66
- "test/send_email_test.rb"
67
- ]
55
+ s.homepage = "http://github.com/drewblas/aws-ses".freeze
56
+ s.licenses = ["MIT".freeze]
57
+ s.rubygems_version = "2.5.2.3".freeze
58
+ s.summary = "Client library for Amazon's Simple Email Service's REST API".freeze
68
59
 
69
60
  if s.respond_to? :specification_version then
70
- s.specification_version = 3
61
+ s.specification_version = 4
71
62
 
72
63
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
73
- s.add_runtime_dependency(%q<xml-simple>, [">= 0"])
74
- s.add_runtime_dependency(%q<builder>, [">= 0"])
75
- s.add_runtime_dependency(%q<mime-types>, [">= 0"])
76
- s.add_runtime_dependency(%q<mail>, ["> 2.2.5"])
77
- s.add_development_dependency(%q<shoulda-context>, [">= 0"])
78
- s.add_development_dependency(%q<flexmock>, ["~> 0.8.11"])
64
+ s.add_runtime_dependency(%q<builder>.freeze, [">= 0"])
65
+ s.add_runtime_dependency(%q<mail>.freeze, ["> 2.2.5"])
66
+ s.add_runtime_dependency(%q<mime-types>.freeze, [">= 0"])
67
+ s.add_runtime_dependency(%q<xml-simple>.freeze, [">= 0"])
68
+ s.add_development_dependency(%q<bundler>.freeze, [">= 1.17"])
69
+ s.add_development_dependency(%q<flexmock>.freeze, ["~> 0.8.11"])
70
+ s.add_development_dependency(%q<jeweler>.freeze, [">= 0"])
71
+ s.add_development_dependency(%q<rake>.freeze, [">= 0"])
72
+ s.add_development_dependency(%q<shoulda-context>.freeze, [">= 0"])
73
+ s.add_development_dependency(%q<test-unit>.freeze, [">= 0"])
74
+ s.add_development_dependency(%q<timecop>.freeze, [">= 0"])
79
75
  else
80
- s.add_dependency(%q<xml-simple>, [">= 0"])
81
- s.add_dependency(%q<builder>, [">= 0"])
82
- s.add_dependency(%q<mime-types>, [">= 0"])
83
- s.add_dependency(%q<mail>, ["> 2.2.5"])
84
- s.add_dependency(%q<shoulda-context>, [">= 0"])
85
- s.add_dependency(%q<flexmock>, ["~> 0.8.11"])
76
+ s.add_dependency(%q<builder>.freeze, [">= 0"])
77
+ s.add_dependency(%q<mail>.freeze, ["> 2.2.5"])
78
+ s.add_dependency(%q<mime-types>.freeze, [">= 0"])
79
+ s.add_dependency(%q<xml-simple>.freeze, [">= 0"])
80
+ s.add_dependency(%q<bundler>.freeze, [">= 1.17"])
81
+ s.add_dependency(%q<flexmock>.freeze, ["~> 0.8.11"])
82
+ s.add_dependency(%q<jeweler>.freeze, [">= 0"])
83
+ s.add_dependency(%q<rake>.freeze, [">= 0"])
84
+ s.add_dependency(%q<shoulda-context>.freeze, [">= 0"])
85
+ s.add_dependency(%q<test-unit>.freeze, [">= 0"])
86
+ s.add_dependency(%q<timecop>.freeze, [">= 0"])
86
87
  end
87
88
  else
88
- s.add_dependency(%q<xml-simple>, [">= 0"])
89
- s.add_dependency(%q<builder>, [">= 0"])
90
- s.add_dependency(%q<mime-types>, [">= 0"])
91
- s.add_dependency(%q<mail>, ["> 2.2.5"])
92
- s.add_dependency(%q<shoulda-context>, [">= 0"])
93
- s.add_dependency(%q<flexmock>, ["~> 0.8.11"])
89
+ s.add_dependency(%q<builder>.freeze, [">= 0"])
90
+ s.add_dependency(%q<mail>.freeze, ["> 2.2.5"])
91
+ s.add_dependency(%q<mime-types>.freeze, [">= 0"])
92
+ s.add_dependency(%q<xml-simple>.freeze, [">= 0"])
93
+ s.add_dependency(%q<bundler>.freeze, [">= 1.17"])
94
+ s.add_dependency(%q<flexmock>.freeze, ["~> 0.8.11"])
95
+ s.add_dependency(%q<jeweler>.freeze, [">= 0"])
96
+ s.add_dependency(%q<rake>.freeze, [">= 0"])
97
+ s.add_dependency(%q<shoulda-context>.freeze, [">= 0"])
98
+ s.add_dependency(%q<test-unit>.freeze, [">= 0"])
99
+ s.add_dependency(%q<timecop>.freeze, [">= 0"])
94
100
  end
95
101
  end
96
102
 
data/lib/aws/ses/base.rb CHANGED
@@ -26,14 +26,22 @@ module AWS #:nodoc:
26
26
  # ses = AWS::SES::Base.new(
27
27
  # :access_key_id => 'abc',
28
28
  # :secret_access_key => '123',
29
- # :server => 'email.eu-west-1.amazonaws.com'
29
+ # :server => 'email.eu-west-1.amazonaws.com',
30
+ # :message_id_domain => 'eu-west-1.amazonses.com'
30
31
  # )
32
+ #
31
33
 
32
34
  module SES
33
35
 
34
36
  API_VERSION = '2010-12-01'
35
-
37
+
38
+ DEFAULT_REGION = 'us-east-1'
39
+
40
+ SERVICE = 'ec2'
41
+
36
42
  DEFAULT_HOST = 'email.us-east-1.amazonaws.com'
43
+
44
+ DEFAULT_MESSAGE_ID_DOMAIN = 'email.amazonses.com'
37
45
 
38
46
  USER_AGENT = 'github-aws-ses-ruby-gem'
39
47
 
@@ -67,13 +75,17 @@ module AWS #:nodoc:
67
75
  def SES.authorization_header(key, alg, sig)
68
76
  "AWS3-HTTPS AWSAccessKeyId=#{key}, Algorithm=#{alg}, Signature=#{sig}"
69
77
  end
70
-
78
+
79
+ def SES.authorization_header_v4(credential, signed_headers, signature)
80
+ "AWS4-HMAC-SHA256 Credential=#{credential}, SignedHeaders=#{signed_headers}, Signature=#{signature}"
81
+ end
82
+
71
83
  # AWS::SES::Base is the abstract super class of all classes who make requests against SES
72
84
  class Base
73
85
  include SendEmail
74
86
  include Info
75
87
 
76
- attr_reader :use_ssl, :server, :proxy_server, :port
88
+ attr_reader :use_ssl, :server, :proxy_server, :port, :message_id_domain, :signature_version, :region
77
89
  attr_accessor :settings
78
90
 
79
91
  # @option options [String] :access_key_id ("") The user's AWS Access Key ID
@@ -82,6 +94,8 @@ module AWS #:nodoc:
82
94
  # @option options [String] :server ("email.us-east-1.amazonaws.com") The server API endpoint host
83
95
  # @option options [String] :proxy_server (nil) An HTTP proxy server FQDN
84
96
  # @option options [String] :user_agent ("github-aws-ses-ruby-gem") The HTTP User-Agent header value
97
+ # @option options [String] :region ("us-east-1") The server API endpoint host
98
+ # @option options [String] :message_id_domain ("us-east-1.amazonses.com") Domain used to build message_id header
85
99
  # @return [Object] the object.
86
100
  def initialize( options = {} )
87
101
 
@@ -89,16 +103,21 @@ module AWS #:nodoc:
89
103
  :secret_access_key => "",
90
104
  :use_ssl => true,
91
105
  :server => DEFAULT_HOST,
106
+ :message_id_domain => DEFAULT_MESSAGE_ID_DOMAIN,
92
107
  :path => "/",
93
108
  :user_agent => USER_AGENT,
94
- :proxy_server => nil
109
+ :proxy_server => nil,
110
+ :region => DEFAULT_REGION
95
111
  }.merge(options)
96
112
 
113
+ @signature_version = options[:signature_version] || 2
97
114
  @server = options[:server]
115
+ @message_id_domain = options[:message_id_domain]
98
116
  @proxy_server = options[:proxy_server]
99
117
  @use_ssl = options[:use_ssl]
100
118
  @path = options[:path]
101
119
  @user_agent = options[:user_agent]
120
+ @region = options[:region]
102
121
  @settings = {}
103
122
 
104
123
  raise ArgumentError, "No :access_key_id provided" if options[:access_key_id].nil? || options[:access_key_id].empty?
@@ -130,10 +149,6 @@ module AWS #:nodoc:
130
149
  proxy.password).new(options[:server], @port)
131
150
 
132
151
  @http.use_ssl = @use_ssl
133
-
134
- # Don't verify the SSL certificates. Avoids SSL Cert warning in log on every GET.
135
- @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
136
-
137
152
  end
138
153
 
139
154
  def connection
@@ -150,7 +165,7 @@ module AWS #:nodoc:
150
165
  timestamp = Time.now.getutc
151
166
 
152
167
  params.merge!( {"Action" => action,
153
- "SignatureVersion" => "2",
168
+ "SignatureVersion" => signature_version.to_s,
154
169
  "SignatureMethod" => 'HmacSHA256',
155
170
  "AWSAccessKeyId" => @access_key_id,
156
171
  "Version" => API_VERSION,
@@ -162,9 +177,9 @@ module AWS #:nodoc:
162
177
 
163
178
  req = {}
164
179
 
165
- req['X-Amzn-Authorization'] = get_aws_auth_param(timestamp.httpdate, @secret_access_key)
180
+ req['X-Amzn-Authorization'] = get_aws_auth_param(timestamp.httpdate, @secret_access_key, action, signature_version)
166
181
  req['Date'] = timestamp.httpdate
167
- req['User-Agent'] = @user_agent
182
+ req['User-Agent'] = @user_agent
168
183
 
169
184
  response = connection.post(@path, query, req)
170
185
 
@@ -179,9 +194,77 @@ module AWS #:nodoc:
179
194
  end
180
195
 
181
196
  # Set the Authorization header using AWS signed header authentication
182
- def get_aws_auth_param(timestamp, secret_access_key)
197
+ def get_aws_auth_param(timestamp, secret_access_key, action = '', signature_version = 2)
198
+ raise(ArgumentError, "signature_version must be `2` or `4`") unless signature_version == 2 || signature_version == 4
183
199
  encoded_canonical = SES.encode(secret_access_key, timestamp, false)
184
- SES.authorization_header(@access_key_id, 'HmacSHA256', encoded_canonical)
200
+
201
+ if signature_version == 4
202
+ SES.authorization_header_v4(sig_v4_auth_credential, sig_v4_auth_signed_headers, sig_v4_auth_signature(action))
203
+ else
204
+ SES.authorization_header(@access_key_id, 'HmacSHA256', encoded_canonical)
205
+ end
206
+ end
207
+
208
+ private
209
+
210
+ def sig_v4_auth_credential
211
+ @access_key_id + '/' + credential_scope
212
+ end
213
+
214
+ def sig_v4_auth_signed_headers
215
+ 'host;x-amz-date'
216
+ end
217
+
218
+ def credential_scope
219
+ datestamp + '/' + region + '/' + SERVICE + '/' + 'aws4_request'
220
+ end
221
+
222
+ def string_to_sign(for_action)
223
+ "AWS4-HMAC-SHA256\n" + amzdate + "\n" + credential_scope + "\n" + Digest::SHA256.hexdigest(canonical_request(for_action).encode('utf-8').b)
224
+ end
225
+
226
+
227
+ def amzdate
228
+ Time.now.utc.strftime('%Y%m%dT%H%M%SZ')
229
+ end
230
+
231
+ def datestamp
232
+ Time.now.utc.strftime('%Y%m%d')
233
+ end
234
+
235
+ def canonical_request(for_action)
236
+ "GET" + "\n" + "/" + "\n" + canonical_querystring(for_action) + "\n" + canonical_headers + "\n" + sig_v4_auth_signed_headers + "\n" + payload_hash
237
+ end
238
+
239
+ def canonical_querystring(action)
240
+ "Action=#{action}&Version=2013-10-15"
241
+ end
242
+
243
+ def canonical_headers
244
+ 'host:' + server + "\n" + 'x-amz-date:' + amzdate + "\n"
245
+ end
246
+
247
+ def payload_hash
248
+ Digest::SHA256.hexdigest(''.encode('utf-8'))
249
+ end
250
+
251
+ def sig_v4_auth_signature(for_action)
252
+ signing_key = getSignatureKey(@secret_access_key, datestamp, region, SERVICE)
253
+
254
+ OpenSSL::HMAC.hexdigest("SHA256", signing_key, string_to_sign(for_action).encode('utf-8'))
255
+ end
256
+
257
+ def getSignatureKey(key, dateStamp, regionName, serviceName)
258
+ kDate = sign(('AWS4' + key).encode('utf-8'), dateStamp)
259
+ kRegion = sign(kDate, regionName)
260
+ kService = sign(kRegion, serviceName)
261
+ kSigning = sign(kService, 'aws4_request')
262
+
263
+ kSigning
264
+ end
265
+
266
+ def sign(key, msg)
267
+ OpenSSL::HMAC.digest("SHA256", key, msg.encode('utf-8'))
185
268
  end
186
269
  end # class Base
187
270
  end # Module SES
@@ -101,7 +101,7 @@ module AWS
101
101
 
102
102
  raw_email = build_raw_email(message, args)
103
103
  result = request('SendRawEmail', raw_email)
104
- message.message_id = "#{result.parsed['SendRawEmailResult']['MessageId']}@email.amazonses.com"
104
+ message.message_id = "<#{result.parsed['SendRawEmailResult']['MessageId']}@#{message_id_domain}>"
105
105
  result
106
106
  end
107
107
 
data/test/base_test.rb CHANGED
@@ -37,4 +37,69 @@ class BaseTest < Test::Unit::TestCase
37
37
  # assert result.error.error?
38
38
  # assert_equal 'ValidationError', result.error.code
39
39
  end
40
+
41
+ def test_ses_authorization_header_v2
42
+ aws_access_key_id = 'fake_aws_key_id'
43
+ aws_secret_access_key = 'fake_aws_access_key'
44
+ timestamp = Time.new(2020, 7, 2, 7, 17, 58, '+00:00')
45
+
46
+ base = ::AWS::SES::Base.new(
47
+ access_key_id: aws_access_key_id,
48
+ secret_access_key: aws_secret_access_key
49
+ )
50
+
51
+ assert_equal 'AWS3-HTTPS AWSAccessKeyId=fake_aws_key_id, Algorithm=HmacSHA256, Signature=eHh/cPIJJUc1+RMCueAi50EPlYxkZNXMrxtGxjkBD1w=', base.get_aws_auth_param(timestamp.httpdate, aws_secret_access_key)
52
+ end
53
+
54
+ def test_ses_authorization_header_v4
55
+ aws_access_key_id = 'fake_aws_key_id'
56
+ aws_secret_access_key = 'fake_aws_access_key'
57
+ time = Time.new(2020, 7, 2, 7, 17, 58, '+00:00')
58
+ ::Timecop.freeze(time)
59
+
60
+ base = ::AWS::SES::Base.new(
61
+ server: 'ec2.amazonaws.com',
62
+ signature_version: 4,
63
+ access_key_id: aws_access_key_id,
64
+ secret_access_key: aws_secret_access_key
65
+ )
66
+
67
+ assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=c0465b36efd110b14a1c6dcca3e105085ed2bfb2a3fd3b3586cc459326ab43aa', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4)
68
+ Timecop.return
69
+ end
70
+
71
+ def test_ses_authorization_header_v4_changed_host
72
+ aws_access_key_id = 'fake_aws_key_id'
73
+ aws_secret_access_key = 'fake_aws_access_key'
74
+ time = Time.new(2020, 7, 2, 7, 17, 58, '+00:00')
75
+ ::Timecop.freeze(time)
76
+
77
+ base = ::AWS::SES::Base.new(
78
+ server: 'email.us-east-1.amazonaws.com',
79
+ signature_version: 4,
80
+ access_key_id: aws_access_key_id,
81
+ secret_access_key: aws_secret_access_key
82
+ )
83
+
84
+ assert_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4)
85
+ Timecop.return
86
+ end
87
+
88
+ def test_ses_authorization_header_v4_changed_region
89
+ aws_access_key_id = 'fake_aws_key_id'
90
+ aws_secret_access_key = 'fake_aws_access_key'
91
+ time = Time.new(2020, 7, 2, 7, 17, 58, '+00:00')
92
+ ::Timecop.freeze(time)
93
+
94
+ base = ::AWS::SES::Base.new(
95
+ server: 'email.us-east-1.amazonaws.com',
96
+ signature_version: 4,
97
+ access_key_id: aws_access_key_id,
98
+ secret_access_key: aws_secret_access_key,
99
+ region: 'eu-west-1'
100
+ )
101
+
102
+ assert_not_equal 'AWS4-HMAC-SHA256 Credential=fake_aws_key_id/20200702/us-east-1/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=b872601457070ab98e7038bdcd4dc1f5eab586ececf9908525474408b0740515', base.get_aws_auth_param(time.httpdate, aws_secret_access_key, 'DescribeRegions', 4)
103
+ Timecop.return
104
+ end
40
105
  end
data/test/helper.rb CHANGED
@@ -24,6 +24,7 @@ require File.dirname(__FILE__) + '/fixtures'
24
24
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
25
25
  $LOAD_PATH.unshift(File.dirname(__FILE__))
26
26
  require 'aws/ses'
27
+ require 'timecop'
27
28
 
28
29
  class Test::Unit::TestCase
29
30
  require 'net/http'
@@ -82,6 +82,27 @@ class SendEmailTest < Test::Unit::TestCase
82
82
  assert_equal 'xyz-123', result.request_id
83
83
  end
84
84
 
85
+ should 'send a raw e-mail with a mail object' do
86
+ mock_connection(@base, :body => %{
87
+ <SendRawEmailResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
88
+ <SendRawEmailResult>
89
+ <MessageId>abc-123</MessageId>
90
+ </SendRawEmailResult>
91
+ <ResponseMetadata>
92
+ <RequestId>xyz-123</RequestId>
93
+ </ResponseMetadata>
94
+ </SendRawEmailResponse>
95
+ })
96
+
97
+ message = Mail.new(@basic_email)
98
+ result = @base.send_raw_email(message)
99
+ assert result.success?
100
+ assert_equal 'abc-123', result.message_id
101
+ assert_equal 'xyz-123', result.request_id
102
+ assert message.errors.empty?
103
+ assert_equal 'abc-123@email.amazonses.com', message.message_id
104
+ end
105
+
85
106
  context "with a standard email" do
86
107
  setup do
87
108
  @message = Mail.new({:from => 'jon@example.com', :to => 'dave@example.com', :cc => 'sally@example.com', :subject => 'Subject1', :body => "test body"})
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-ses
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Drew Blas
@@ -9,10 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-10-13 00:00:00.000000000 Z
12
+ date: 2020-09-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: xml-simple
15
+ name: builder
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
18
  - - ">="
@@ -26,19 +26,19 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
- name: builder
29
+ name: mail
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
32
+ - - ">"
33
33
  - !ruby/object:Gem::Version
34
- version: '0'
34
+ version: 2.2.5
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ">="
39
+ - - ">"
40
40
  - !ruby/object:Gem::Version
41
- version: '0'
41
+ version: 2.2.5
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: mime-types
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -54,33 +54,33 @@ dependencies:
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: mail
57
+ name: xml-simple
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - ">"
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: 2.2.5
62
+ version: '0'
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - ">"
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 2.2.5
69
+ version: '0'
70
70
  - !ruby/object:Gem::Dependency
71
- name: shoulda-context
71
+ name: bundler
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
74
  - - ">="
75
75
  - !ruby/object:Gem::Version
76
- version: '0'
76
+ version: '1.17'
77
77
  type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
- version: '0'
83
+ version: '1.17'
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: flexmock
86
86
  requirement: !ruby/object:Gem::Requirement
@@ -95,11 +95,82 @@ dependencies:
95
95
  - - "~>"
96
96
  - !ruby/object:Gem::Version
97
97
  version: 0.8.11
98
+ - !ruby/object:Gem::Dependency
99
+ name: jeweler
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rake
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: shoulda-context
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: test-unit
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: timecop
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
98
168
  description: Client library for Amazon's Simple Email Service's REST API
99
169
  email: drew.blas@gmail.com
100
170
  executables: []
101
171
  extensions: []
102
172
  extra_rdoc_files:
173
+ - CHANGELOG
103
174
  - LICENSE
104
175
  - README.erb
105
176
  - README.rdoc
@@ -154,17 +225,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
225
  version: '0'
155
226
  requirements: []
156
227
  rubyforge_project:
157
- rubygems_version: 2.2.2
228
+ rubygems_version: 2.5.2.3
158
229
  signing_key:
159
- specification_version: 3
230
+ specification_version: 4
160
231
  summary: Client library for Amazon's Simple Email Service's REST API
161
- test_files:
162
- - test/address_test.rb
163
- - test/base_test.rb
164
- - test/extensions_test.rb
165
- - test/fixtures.rb
166
- - test/helper.rb
167
- - test/info_test.rb
168
- - test/mocks/fake_response.rb
169
- - test/response_test.rb
170
- - test/send_email_test.rb
232
+ test_files: []