heroic-sns 1.1.3 → 1.2

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
- 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"