heroic-sns 1.1.3 → 1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: eee6831c04d011c9161d134748559f3eafb8be77
4
- data.tar.gz: bfc5b96361e45564efc1855dd9681fa1a7ac7feb
2
+ SHA256:
3
+ metadata.gz: 061bb44887daecae4a05c0a3c75debc2d59c55b7e0a733bc783cc665de9d7a3f
4
+ data.tar.gz: e0f2aed506a0ebae75e408376a2c102f7825a6a9123f529286be92d6535c7416
5
5
  SHA512:
6
- metadata.gz: 25215f8ef74c6186384e12a2ec3d3198f6b5a8cec196f7e71eb42e4fd5d337d46d8e447d6d93b964c600b3967cf2d20cc48e5d02d5dd815f2f89be4ae2971966
7
- data.tar.gz: 2b411b716ec99e1de2a3a9f862f77588dd367c92d33b09c9f38f3863f6cf013ccbea283c477bddfd7c7eb66ac4639bae5a393bfb2e807ad68057fcddc991d480
6
+ metadata.gz: 2007d432d0585597cb35e35cb68af3c82c9d9210b31ec227d432b481228973e25aa8c17410ac9ca6ea487cec698ea56842986c42964f88e6c3cd7c5a22ad6dba
7
+ data.tar.gz: d6c83fd48d0f59bc5194bca39773c24eae90c34384251dcd5af8ee8656d4f9794d6e08154c40d39327b91d4713ef9370dccd8873d0d274d63ce5943af898ccec
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  /pkg
4
4
  /tmp
5
5
  /Gemfile.lock
6
+ /gemfiles/*.lock
@@ -1,23 +1,22 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "2.3.1"
4
- - "2.2.5"
5
- - "2.1.9"
6
- - "2.0.0"
7
- - "1.9.3"
8
- - "1.8.7"
3
+ - "2.7"
4
+ - "2.6"
5
+ - "2.5"
6
+ - "2.4"
7
+ - "2.3"
8
+ - "2.2"
9
+ - "2.1"
10
+ - "2.0"
9
11
  gemfile:
12
+ - Gemfile
10
13
  - gemfiles/Gemfile.rack-1.x
11
- - gemfiles/Gemfile.rack-2.x
12
14
  before_install:
13
15
  - gem update bundler
14
16
  matrix:
15
17
  exclude:
16
- - rvm: 2.1.9
17
- gemfile: gemfiles/Gemfile.rack-2.x
18
- - rvm: 2.0.0
19
- gemfile: gemfiles/Gemfile.rack-2.x
20
- - rvm: 1.9.3
21
- gemfile: gemfiles/Gemfile.rack-2.x
22
- - rvm: 1.8.7
23
- gemfile: gemfiles/Gemfile.rack-2.x
18
+ - { rvm: "2.1", gemfile: Gemfile }
19
+ - { rvm: "2.0", gemfile: Gemfile }
20
+ include:
21
+ - { rvm: "1.8.7", dist: precise, gemfile: gemfiles/Gemfile.ruby-1.8 }
22
+ - { rvm: "1.9.3", dist: trusty, gemfile: gemfiles/Gemfile.rack-1.x }
@@ -1,11 +1,17 @@
1
+ ### 1.2
2
+
3
+ * Add Ruby 2.4, 2.5, 2.6. 2.7 to the Travis CI tests
4
+ * Relax json gem dependency - [@biinari]
5
+ * Stricter signing URL check - [@biinari]
6
+ * Show age when raising 'time is in the future' error - [@mamedov]
7
+
1
8
  ### 1.1.3 (July 7, 2016)
2
9
 
3
10
  * Relax rack version requirement to allow usage with rack 2.x - [@fschwahn]
4
11
 
5
12
  ### 1.1.2 (March 23, 2016)
6
13
 
7
- * Rewind the request body, in case the application wants to read it again.
8
- [@cobbr2]
14
+ * Rewind the request body, in case the application wants to read it again - [@cobbr2]
9
15
 
10
16
  ### 1.1.1 (August 9, 2013)
11
17
 
@@ -24,7 +30,11 @@
24
30
 
25
31
  * Initial public release - [@benzado]
26
32
 
27
- [@benzado]: http://github.com/benzado
28
- [@sbeckeriv]: http://github.com/sbeckeriv
29
- [@dblock]: http://github.com/dblock
30
- [@speedmanly]: http://github.com/speedmanly
33
+ [@benzado]: https://github.com/benzado
34
+ [@biinari]: https://github.com/biinari
35
+ [@cobbr2]: https://github.com/cobbr2
36
+ [@dblock]: https://github.com/dblock
37
+ [@fschwahn]: https://github.com/fschwahn
38
+ [@mamedov]: https://github.com/mamedov
39
+ [@sbeckeriv]: https://github.com/sbeckeriv
40
+ [@speedmanly]: https://github.com/speedmanly
data/Gemfile CHANGED
@@ -2,4 +2,6 @@ source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem "rake", '~> 10.3'
5
+ gem "rake"
6
+ gem "rack", "~> 2.0"
7
+ gem "test-unit", "~> 3.3"
data/README.md CHANGED
@@ -163,7 +163,7 @@ SNS notification.
163
163
 
164
164
  ## Copyright and License
165
165
 
166
- Copyright 2013, Heroic Software Inc and Contributors.
166
+ Copyright 2013, 2016, 2020, Benjamin Ragheb and Contributors.
167
167
 
168
168
  This project [is licensed under the Apache license](LICENSE).
169
169
 
@@ -4,3 +4,4 @@ gemspec :path => ".."
4
4
 
5
5
  gem "rake", "~> 10.3"
6
6
  gem "rack", "~> 1.0"
7
+ gem "json", "~> 1.7"
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec :path => ".."
4
+
5
+ gem "rake", "~> 10.3"
6
+ gem "rack", "~> 1.0"
7
+ gem "json", "~> 1.7"
8
+ gem "test-unit", "1.2.3"
@@ -27,7 +27,7 @@ EOD
27
27
  s.platform = Gem::Platform::RUBY
28
28
  s.required_ruby_version = '>= 1.8.7'
29
29
  s.add_development_dependency 'rdoc', '~> 4.0'
30
- s.add_development_dependency 'test-unit', '1.2.3'
30
+ s.add_development_dependency 'test-unit', '>= 1.2.3'
31
31
  s.add_runtime_dependency 'rack', '>= 1.4'
32
- s.add_runtime_dependency 'json', '~> 1.7'
32
+ s.add_runtime_dependency 'json', '>= 1.7'
33
33
  end
@@ -115,10 +115,10 @@ module Heroic
115
115
  message.verify!
116
116
  case message.type
117
117
  when 'SubscriptionConfirmation'
118
- open(message.subscribe_url) if @auto_confirm
118
+ URI.parse(message.subscribe_url).open if @auto_confirm
119
119
  return OK_RESPONSE unless @auto_confirm.nil?
120
120
  when 'UnsubscribeConfirmation'
121
- open(message.subscribe_url) if @auto_resubscribe
121
+ URI.parse(message.subscribe_url).open if @auto_resubscribe
122
122
  return OK_RESPONSE unless @auto_resubscribe.nil?
123
123
  end
124
124
  env['sns.message'] = message
@@ -139,7 +139,7 @@ module Heroic
139
139
  begin
140
140
  message = Message.new(env['rack.input'].read)
141
141
  message.verify!
142
- open(message.unsubscribe_url)
142
+ URI.parse(message.unsubscribe_url).open
143
143
  rescue => e
144
144
  raise Error.new("error handling off-topic notification: #{e.message}", message)
145
145
  end
@@ -1,5 +1,6 @@
1
1
  require 'json'
2
2
  require 'base64'
3
+ require 'open-uri'
3
4
  require 'heroic/lru_cache'
4
5
 
5
6
  module Heroic
@@ -10,7 +11,7 @@ module Heroic
10
11
 
11
12
  CERTIFICATE_CACHE = Heroic::LRUCache.new(MAXIMUM_ALLOWED_CERTIFICATES) do |cert_url|
12
13
  begin
13
- cert_data = open(cert_url)
14
+ cert_data = URI.parse(cert_url).open
14
15
  OpenSSL::X509::Certificate.new(cert_data.read)
15
16
  rescue OpenSSL::X509::CertificateError => e
16
17
  raise SNS::Error.new("unable to parse signing certificate: #{e.message}; URL: #{cert_url}")
@@ -19,6 +20,8 @@ module Heroic
19
20
  end
20
21
  end
21
22
 
23
+ VALID_AWS_URL_PATTERN = %r{\Ahttps://sns\.[a-z]{2}(?:-gov)?-(?:north|south|east|west|central){1,2}-\d+\.amazonaws\.com(?:\.cn)?/}
24
+
22
25
  # Encapsulates an SNS message. Since Endpoint takes care of authenticating
23
26
  # the message, most of the time you will simply be interested in retrieving
24
27
  # the +subject+ and +body+ from the message and acting on it.
@@ -120,12 +123,12 @@ module Heroic
120
123
  # See: http://docs.aws.amazon.com/sns/latest/gsg/SendMessageToHttp.verify.signature.html
121
124
  def verify!
122
125
  age = Time.now - timestamp
123
- raise Error.new("timestamp is in the future", self) if age < 0
126
+ raise Error.new("timestamp is in the future, age: #{age}", self) if age < 0
124
127
  raise Error.new("timestamp is too old", self) if age > MAXIMUM_ALLOWED_AGE
125
128
  if signature_version != '1'
126
129
  raise Error.new("unknown signature version: #{signature_version}", self)
127
130
  end
128
- if signing_cert_url !~ %r[^https://.*amazonaws\.com/]
131
+ if signing_cert_url !~ VALID_AWS_URL_PATTERN
129
132
  raise Error.new("signing certificate is not from amazonaws.com", self)
130
133
  end
131
134
  text = string_to_sign # will warn of invalid Type
@@ -1,5 +1,5 @@
1
1
  module Heroic
2
2
  module SNS
3
- VERSION = '1.1.3'
3
+ VERSION = '1.2'
4
4
  end
5
5
  end
@@ -0,0 +1,27 @@
1
+ sns.af-south-1.amazonaws.com
2
+ sns.ap-east-1.amazonaws.com
3
+ sns.ap-northeast-1.amazonaws.com
4
+ sns.ap-northeast-2.amazonaws.com
5
+ sns.ap-northeast-3.amazonaws.com
6
+ sns.ap-south-1.amazonaws.com
7
+ sns.ap-southeast-1.amazonaws.com
8
+ sns.ap-southeast-2.amazonaws.com
9
+ sns.ca-central-1.amazonaws.com
10
+ sns.cn-north-1.amazonaws.com
11
+ sns.cn-northwest-1.amazonaws.com
12
+ sns.eu-central-1.amazonaws.com
13
+ sns.eu-north-1.amazonaws.com
14
+ sns.eu-south-1.amazonaws.com
15
+ sns.eu-west-1.amazonaws.com
16
+ sns.eu-west-2.amazonaws.com
17
+ sns.eu-west-3.amazonaws.com
18
+ sns.me-south-1.amazonaws.com
19
+ sns.sa-east-1.amazonaws.com
20
+ sns.us-east-1.amazonaws.com
21
+ sns.us-east-2.amazonaws.com
22
+ sns.us-west-1.amazonaws.com
23
+ sns.us-west-2.amazonaws.com
24
+ sns.us-gov-east-1.amazonaws.com
25
+ sns.us-gov-west-1.amazonaws.com
26
+ sns.cn-north-1.amazonaws.com.cn
27
+ sns.cn-northwest-1.amazonaws.com.cn
@@ -5,30 +5,34 @@
5
5
 
6
6
  module Heroic
7
7
  module SNS
8
+ # Use a fake certificate cache so tests aren't dependent on
9
+ # network access, or the fact that the certificate is also fake.
10
+ CERTIFICATE_CACHE = Class.new do
11
+ def cert_data
12
+ File.read('test/fixtures/sns.crt')
13
+ end
8
14
 
9
- TEST_CERT_URL = 'https://sns.test.amazonaws.com/self-signed.pem'
10
- TEST_CERT_KEY = OpenSSL::PKey::RSA.new(File.read('test/fixtures/sns.key'))
15
+ def get(_)
16
+ @cert ||= OpenSSL::X509::Certificate.new(cert_data)
17
+ end
18
+ end.new
11
19
 
12
- begin
13
- # Insert the certificate in the cache so that these tests aren't dependent
14
- # on network access (or the fact that the certificate is fake).
15
- cert_data = File.read('test/fixtures/sns.crt')
16
- CERTIFICATE_CACHE.put(TEST_CERT_URL, OpenSSL::X509::Certificate.new(cert_data))
17
- end
20
+ TEST_CERT_URL = 'https://sns.xx-east-1.amazonaws.com/self-signed.pem'
21
+ TEST_CERT_KEY = OpenSSL::PKey::RSA.new(File.read('test/fixtures/sns.key'))
18
22
 
19
23
  class Message
20
-
21
24
  def update_timestamp!(t = Time.now)
22
25
  @msg['Timestamp'] = t.utc.xmlschema(3)
23
26
  end
24
27
 
28
+ def update_signing_cert_url!(url = nil)
29
+ @msg['SigningCertURL'] = url || TEST_CERT_URL
30
+ end
31
+
25
32
  def sign!
26
- @msg['SigningCertURL'] = TEST_CERT_URL
27
33
  signature = TEST_CERT_KEY.sign(OpenSSL::Digest::SHA1.new, string_to_sign)
28
34
  @msg['Signature'] = Base64::encode64(signature)
29
35
  end
30
-
31
36
  end
32
-
33
37
  end
34
38
  end
@@ -10,6 +10,7 @@ class EndpointTest < Test::Unit::TestCase
10
10
  json = File.read("test/fixtures/#{name}.json")
11
11
  @msg = Heroic::SNS::Message.new(json)
12
12
  @msg.update_timestamp!
13
+ @msg.update_signing_cert_url!
13
14
  @msg.sign!
14
15
  @env = {
15
16
  'HTTP_X_AMZ_SNS_MESSAGE_TYPE' => @msg.type,
@@ -3,11 +3,11 @@ require 'heroic/sns'
3
3
  require 'helper'
4
4
 
5
5
  class MessageTest < Test::Unit::TestCase
6
-
7
- def sns(name, timestamp = Time.now)
6
+ def sns(name, options = {})
8
7
  json = File.read("test/fixtures/#{name}.json")
9
8
  msg = Heroic::SNS::Message.new(json)
10
- msg.update_timestamp!(timestamp)
9
+ msg.update_timestamp!(options[:timestamp] || Time.now)
10
+ msg.update_signing_cert_url!(options[:signing_cert_url])
11
11
  msg.sign!
12
12
  return msg
13
13
  end
@@ -51,13 +51,41 @@ class MessageTest < Test::Unit::TestCase
51
51
  end
52
52
  end
53
53
 
54
+ def test_untrusted_cert_url_s3
55
+ cert_url = 'https://sns.s3.amazonaws.com/self-signed.pem'
56
+ msg = sns("notification", :signing_cert_url => cert_url)
57
+ assert_equal cert_url, msg.signing_cert_url
58
+ assert_raises Heroic::SNS::Error do
59
+ msg.verify!
60
+ end
61
+ end
62
+
63
+ def test_untrusted_cert_url_other
64
+ cert_url = 'https://example.com/sns.us-east-1.amazonaws.com/self-signed.pem'
65
+ msg = sns("subscription", :signing_cert_url => cert_url)
66
+ assert_equal cert_url, msg.signing_cert_url
67
+ assert_raises Heroic::SNS::Error do
68
+ msg.verify!
69
+ end
70
+ end
71
+
72
+ # Generate tests for every known AWS SNS endpoint.
73
+ # https://docs.aws.amazon.com/general/latest/gr/sns.html
74
+ File.read('test/fixtures/aws-sns-endpoints.txt').split(/\n/).each do |domain|
75
+ define_method("test_trusted_cert_url_#{domain}") do
76
+ cert_url = "https://#{domain}/certificate.pem"
77
+ msg = sns("notification", :signing_cert_url => cert_url)
78
+ assert_equal cert_url, msg.signing_cert_url
79
+ assert_nothing_raised { msg.verify! }
80
+ end
81
+ end
82
+
54
83
  def test_expired
55
84
  t = Time.utc(1984, 5)
56
- msg = sns("notification", t)
85
+ msg = sns("notification", :timestamp => t)
57
86
  assert_equal t, msg.timestamp
58
87
  assert_raises Heroic::SNS::Error do
59
88
  msg.verify!
60
89
  end
61
90
  end
62
-
63
91
  end
metadata CHANGED
@@ -1,69 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heroic-sns
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: '1.2'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Ragheb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-13 00:00:00.000000000 Z
11
+ date: 2020-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '4.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: test-unit
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.2.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.2.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rack
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.4'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.4'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: json
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.7'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.7'
69
69
  description: |
@@ -78,8 +78,8 @@ executables: []
78
78
  extensions: []
79
79
  extra_rdoc_files: []
80
80
  files:
81
- - .gitignore
82
- - .travis.yml
81
+ - ".gitignore"
82
+ - ".travis.yml"
83
83
  - CHANGELOG.md
84
84
  - Gemfile
85
85
  - LICENSE
@@ -89,13 +89,14 @@ files:
89
89
  - demo/config.ru
90
90
  - demo/demo.erb
91
91
  - gemfiles/Gemfile.rack-1.x
92
- - gemfiles/Gemfile.rack-2.x
92
+ - gemfiles/Gemfile.ruby-1.8
93
93
  - heroic-sns.gemspec
94
94
  - lib/heroic/lru_cache.rb
95
95
  - lib/heroic/sns.rb
96
96
  - lib/heroic/sns/endpoint.rb
97
97
  - lib/heroic/sns/message.rb
98
98
  - lib/heroic/sns/version.rb
99
+ - test/fixtures/aws-sns-endpoints.txt
99
100
  - test/fixtures/notification.json
100
101
  - test/fixtures/sns.crt
101
102
  - test/fixtures/sns.key
@@ -115,17 +116,16 @@ require_paths:
115
116
  - lib
116
117
  required_ruby_version: !ruby/object:Gem::Requirement
117
118
  requirements:
118
- - - '>='
119
+ - - ">="
119
120
  - !ruby/object:Gem::Version
120
121
  version: 1.8.7
121
122
  required_rubygems_version: !ruby/object:Gem::Requirement
122
123
  requirements:
123
- - - '>='
124
+ - - ">="
124
125
  - !ruby/object:Gem::Version
125
126
  version: '0'
126
127
  requirements: []
127
- rubyforge_project:
128
- rubygems_version: 2.0.14.1
128
+ rubygems_version: 3.0.8
129
129
  signing_key:
130
130
  specification_version: 4
131
131
  summary: Lightweight Rack middleware for AWS SNS endpoints
@@ -1,5 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gemspec path: ".."
4
-
5
- gem "rack", "~> 2.0"