escher 1.0.0 → 2.0.3

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: f5d7892a58786fb9802e66a734ddc2f7f84a4b42
4
- data.tar.gz: 18bf4433e019a4581eb6980f9819f2b336c3495a
2
+ SHA256:
3
+ metadata.gz: e01dd40666cb6ea783bc477f97f8ae673d5208ac8db7a5bba3ef569c95d3061d
4
+ data.tar.gz: 953b4c5dab4d7e8e832bd7bc80204f2d324114f893ae4f31df8c4d8ebf01c189
5
5
  SHA512:
6
- metadata.gz: 006d627eddd82e86ef6e803019bee58183314d85b299a82a62da7e2579b069bd11e247d20d444822dd87acba7276612d19af415f608d5f55ccb88e532bdc36e4
7
- data.tar.gz: 6d7cabbbaba10921751b255dcd9865f9bdc6abb08b1a7114190aac257f168f1118f9ea40b8399ac6502530ae3f04b38ebc7ef43cdc044eedf9f5eee9c4fcc71b
6
+ metadata.gz: 31219982da52121cc942e0bbfe7c18b0d868129c6e55c0cc46be53734d1e6c8886758ed08dba11c7b87234085e5b28c6a073612e2d811633d7196c1b54f688e1
7
+ data.tar.gz: 7c56ef27d72cf2cd80c190dabb973d5355a87eebf8860972217d521c4810086e8d8610f9a49f3d469cbe2cb674182ecb0da90f37db742b5d27e46bb5fb30f3eb
@@ -0,0 +1,33 @@
1
+ name: Ruby
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ matrix:
10
+ ruby-versions: ['2.6', '2.7', '3.0']
11
+
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ - uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: ${{ matrix.ruby-versions }}
17
+ - name: Checkout testsuite
18
+ run: ./scripts/checkout_test_suite.sh
19
+ - name: Install dependencies
20
+ run: bundle install
21
+ - name: Run tests
22
+ run: bundle exec rake
23
+ - name: Deploy
24
+ if : github.event_name == 'push' && startsWith(github.ref, 'refs/tags') && matrix.ruby-versions == '3.0'
25
+ run: |
26
+ mkdir -p $HOME/.gem
27
+ touch $HOME/.gem/credentials
28
+ chmod 0600 $HOME/.gem/credentials
29
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
30
+ gem build *.gemspec
31
+ gem push *.gem
32
+ env:
33
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
data/escher.gemspec CHANGED
@@ -20,14 +20,14 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.required_ruby_version = '>= 1.9'
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.6"
23
+ spec.add_development_dependency "bundler", "~> 2.2.20"
24
24
  spec.add_development_dependency "rails"
25
25
 
26
- spec.add_development_dependency "rake", "~> 10"
27
- spec.add_development_dependency "rspec", "~> 2"
26
+ spec.add_development_dependency "rake", "~> 13.0.6"
27
+ spec.add_development_dependency "rspec", "~> 3"
28
28
 
29
29
  spec.add_development_dependency "rack"
30
30
  spec.add_development_dependency "plissken"
31
31
 
32
- spec.add_runtime_dependency "addressable", "~> 2.3"
32
+ spec.add_runtime_dependency "addressable", "~> 2.8.0"
33
33
  end
data/lib/escher/auth.rb CHANGED
@@ -6,7 +6,7 @@ module Escher
6
6
  @algo_prefix = options[:algo_prefix] || 'ESR'
7
7
  @vendor_key = options[:vendor_key] || 'Escher'
8
8
  @hash_algo = options[:hash_algo] || 'SHA256'
9
- @current_time = options[:current_time] || Time.now
9
+ @current_time = options[:current_time]
10
10
  @auth_header_name = options[:auth_header_name] || 'X-Escher-Auth'
11
11
  @date_header_name = options[:date_header_name] || 'X-Escher-Date'
12
12
  @clock_skew = options[:clock_skew] || 300
@@ -17,15 +17,17 @@ module Escher
17
17
 
18
18
 
19
19
  def sign!(req, client, headers_to_sign = [])
20
+ current_time = @current_time || Time.now
21
+
20
22
  headers_to_sign |= [@date_header_name.downcase, 'host']
21
23
 
22
24
  request = wrap_request req
23
25
  raise EscherError, 'The host header is missing' unless request.has_header? 'host'
24
26
 
25
- request.set_header(@date_header_name.downcase, format_date_for_header) unless request.has_header? @date_header_name
27
+ request.set_header(@date_header_name.downcase, format_date_for_header(current_time)) unless request.has_header? @date_header_name
26
28
 
27
- signature = generate_signature(client[:api_secret], request.body, request.headers, request.method, headers_to_sign, request.path, request.query_values)
28
- request.set_header(@auth_header_name, "#{@algo_id} Credential=#{client[:api_key_id]}/#{short_date(@current_time)}/#{@credential_scope}, SignedHeaders=#{prepare_headers_to_sign headers_to_sign}, Signature=#{signature}")
29
+ signature = generate_signature(client[:api_secret], request.body, request.headers, request.method, headers_to_sign, request.path, request.query_values, current_time)
30
+ request.set_header(@auth_header_name, "#{@algo_id} Credential=#{client[:api_key_id]}/#{short_date(current_time)}/#{@credential_scope}, SignedHeaders=#{prepare_headers_to_sign headers_to_sign}, Signature=#{signature}")
29
31
 
30
32
  request.request
31
33
  end
@@ -44,6 +46,7 @@ module Escher
44
46
 
45
47
 
46
48
  def authenticate(req, key_db, mandatory_signed_headers = nil)
49
+ current_time = @current_time || Time.now
47
50
  request = wrap_request req
48
51
  method = request.method
49
52
  body = request.body
@@ -78,10 +81,9 @@ module Escher
78
81
  raise EscherError, 'Invalid Escher key' unless api_secret
79
82
  raise EscherError, 'Invalid hash algorithm, only SHA256 and SHA512 are allowed' unless %w(SHA256 SHA512).include?(algorithm)
80
83
  raise EscherError, 'The request method is invalid' unless valid_request_method?(method)
81
- raise EscherError, "The request body shouldn't be empty if the request method is POST" if (method.upcase == 'POST' && body.empty?)
82
84
  raise EscherError, "The request url shouldn't contains http or https" if path.match /^https?:\/\//
83
85
  raise EscherError, 'Invalid date in authorization header, it should equal with date header' unless short_date(date) == short_date
84
- raise EscherError, 'The request date is not within the accepted time range' unless is_date_within_range?(date, expires)
86
+ raise EscherError, 'The request date is not within the accepted time range' unless is_date_within_range?(date, expires, current_time)
85
87
  raise EscherError, 'Invalid Credential Scope' unless credential_scope == @credential_scope
86
88
  raise EscherError, 'The mandatorySignedHeaders parameter must be undefined or array of strings' unless mandatory_signed_headers_valid?(mandatory_signed_headers)
87
89
  raise EscherError, 'The host header is not signed' unless signed_headers.include? 'host'
@@ -94,7 +96,7 @@ module Escher
94
96
  raise EscherError, 'The date header is not signed' if !signature_from_query && !signed_headers.include?(@date_header_name.downcase)
95
97
 
96
98
  escher = reconfig(algorithm, credential_scope, date)
97
- expected_signature = escher.generate_signature(api_secret, body, headers, method, signed_headers, path, query_parts)
99
+ expected_signature = escher.generate_signature(api_secret, body, headers, method, signed_headers, path, query_parts, date)
98
100
  raise EscherError, 'The signatures do not match' unless signature == expected_signature
99
101
  api_key_id
100
102
  end
@@ -116,6 +118,7 @@ module Escher
116
118
 
117
119
 
118
120
  def generate_signed_url(url_to_sign, client, expires = 86400)
121
+ current_time = @current_time || Time.now
119
122
  uri = Addressable::URI.parse(url_to_sign)
120
123
 
121
124
  if (not uri.port.nil?) && (uri.port != uri.default_port)
@@ -137,13 +140,13 @@ module Escher
137
140
  body = 'UNSIGNED-PAYLOAD'
138
141
  query_parts += [
139
142
  ['Algorithm', @algo_id],
140
- ['Credentials', "#{client[:api_key_id]}/#{short_date(@current_time)}/#{@credential_scope}"],
141
- ['Date', long_date(@current_time)],
143
+ ['Credentials', "#{client[:api_key_id]}/#{short_date(current_time)}/#{@credential_scope}"],
144
+ ['Date', long_date(current_time)],
142
145
  ['Expires', expires.to_s],
143
146
  ['SignedHeaders', headers_to_sign.join(';')],
144
147
  ].map { |k, v| query_pair(k, v) }
145
148
 
146
- signature = generate_signature(client[:api_secret], body, headers, 'GET', headers_to_sign, path, query_parts)
149
+ signature = generate_signature(client[:api_secret], body, headers, 'GET', headers_to_sign, path, query_parts, current_time)
147
150
  query_parts_with_signature = (query_parts.map { |k, v| [uri_encode(k), uri_encode(v)] } << query_pair('Signature', signature))
148
151
  "#{uri.scheme}://#{host}#{path}?#{query_parts_with_signature.map { |k, v| k + '=' + v }.join('&')}#{(fragment === nil ? '' : '#' + fragment)}"
149
152
  end
@@ -189,11 +192,11 @@ module Escher
189
192
 
190
193
 
191
194
 
192
- def generate_signature(api_secret, body, headers, method, signed_headers, path, query_parts)
195
+ def generate_signature(api_secret, body, headers, method, signed_headers, path, query_parts, current_time)
193
196
  canonicalized_request = canonicalize(method, path, query_parts, body, headers, signed_headers.uniq)
194
- string_to_sign = get_string_to_sign(canonicalized_request)
197
+ string_to_sign = get_string_to_sign(canonicalized_request, current_time)
195
198
 
196
- signing_key = OpenSSL::HMAC.digest(@algo, @algo_prefix + api_secret, short_date(@current_time))
199
+ signing_key = OpenSSL::HMAC.digest(@algo, @algo_prefix + api_secret, short_date(current_time))
197
200
  @credential_scope.split('/').each { |data|
198
201
  signing_key = OpenSSL::HMAC.digest(@algo, signing_key, data)
199
202
  }
@@ -203,8 +206,8 @@ module Escher
203
206
 
204
207
 
205
208
 
206
- def format_date_for_header
207
- @date_header_name.downcase == 'date' ? @current_time.utc.rfc2822.sub('-0000', 'GMT') : long_date(@current_time)
209
+ def format_date_for_header(current_time)
210
+ @date_header_name.downcase == 'date' ? current_time.utc.rfc2822.sub('-0000', 'GMT') : long_date(current_time)
208
211
  end
209
212
 
210
213
 
@@ -239,11 +242,11 @@ module Escher
239
242
 
240
243
 
241
244
 
242
- def get_string_to_sign(canonicalized_request)
245
+ def get_string_to_sign(canonicalized_request, current_time)
243
246
  [
244
247
  @algo_id,
245
- long_date(@current_time),
246
- short_date(@current_time) + '/' + @credential_scope,
248
+ long_date(current_time),
249
+ short_date(current_time) + '/' + @credential_scope,
247
250
  @algo.new.hexdigest(canonicalized_request)
248
251
  ].join("\n")
249
252
  end
@@ -255,7 +258,7 @@ module Escher
255
258
  when 'SHA256'
256
259
  @algo = OpenSSL::Digest::SHA256.new
257
260
  when 'SHA512'
258
- @algo = OpenSSL::Digest::SHA521.new
261
+ @algo = OpenSSL::Digest::SHA512.new
259
262
  else
260
263
  raise EscherError, 'Unidentified hash algorithm'
261
264
  end
@@ -275,8 +278,8 @@ module Escher
275
278
 
276
279
 
277
280
 
278
- def is_date_within_range?(request_date, expires)
279
- (request_date - @clock_skew .. request_date + expires + @clock_skew).cover? @current_time
281
+ def is_date_within_range?(request_date, expires, current_time)
282
+ (request_date - @clock_skew .. request_date + expires + @clock_skew).cover? current_time
280
283
  end
281
284
 
282
285
 
@@ -1,3 +1,3 @@
1
1
  module Escher
2
- VERSION = '1.0.0'
2
+ VERSION = '2.0.3'
3
3
  end
data/repo-info.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "is_in_production": false,
3
+ "is_scannable": true,
4
+ "is_critical": false,
5
+ "contact": "G-GSUITE-Security@emarsys.com",
6
+ "hosted": null
7
+ }
@@ -35,11 +35,5 @@ module Escher
35
35
  expect(request).to eq(test_case.expected_request)
36
36
  end
37
37
  end
38
-
39
-
40
- xspecify "every case in the test suite is being used" do
41
- expect(::EmarsysTestSuiteHelpers::TestSuite.in_use_size).to eq ::EmarsysTestSuiteHelpers::TestSuite.size
42
- end
43
-
44
38
  end
45
39
  end
@@ -101,7 +101,7 @@ module Escher
101
101
  headers_to_sign = headers.map { |k| k[0].downcase }
102
102
  path, query_parts = escher.parse_uri(request_uri)
103
103
  canonicalized_request = escher.canonicalize(method, path, query_parts, body, headers, headers_to_sign)
104
- string_to_sign = escher.get_string_to_sign(canonicalized_request)
104
+ string_to_sign = escher.get_string_to_sign(canonicalized_request, Time.parse(date))
105
105
  expect(string_to_sign).to eq(fixture(suite, test, 'sts'))
106
106
  end
107
107
  end
@@ -484,7 +484,7 @@ module Escher
484
484
 
485
485
  it 'should convert dates' do
486
486
  date_str = 'Fri, 09 Sep 2011 23:36:00 GMT'
487
- expect(described_class.new('irrelevant', date_header_name: 'date', current_time: Time.parse(date_str)).format_date_for_header).to eq date_str
487
+ expect(described_class.new('irrelevant', date_header_name: 'date', current_time: Time.parse(date_str)).format_date_for_header(Time.parse(date_str))).to eq date_str
488
488
  end
489
489
 
490
490
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: escher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andras Barthazi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-23 00:00:00.000000000 Z
11
+ date: 2021-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.6'
19
+ version: 2.2.20
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
- version: '1.6'
26
+ version: 2.2.20
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,28 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10'
47
+ version: 13.0.6
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10'
54
+ version: 13.0.6
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2'
61
+ version: '3'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2'
68
+ version: '3'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rack
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '2.3'
103
+ version: 2.8.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '2.3'
110
+ version: 2.8.0
111
111
  description: Escher helps you creating secure HTTP requests (for APIs) by signing
112
112
  HTTP(s) requests.
113
113
  email:
@@ -116,8 +116,8 @@ executables: []
116
116
  extensions: []
117
117
  extra_rdoc_files: []
118
118
  files:
119
+ - ".github/workflows/ruby.yml"
119
120
  - ".gitignore"
120
- - ".travis.yml"
121
121
  - Gemfile
122
122
  - LICENSE
123
123
  - README.md
@@ -135,6 +135,7 @@ files:
135
135
  - lib/escher/request/legacy_request.rb
136
136
  - lib/escher/request/rack_request.rb
137
137
  - lib/escher/version.rb
138
+ - repo-info.json
138
139
  - scripts/checkout_test_suite.sh
139
140
  - spec/aws4_testsuite/get-header-key-duplicate.authz
140
141
  - spec/aws4_testsuite/get-header-key-duplicate.creq
@@ -340,8 +341,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
340
341
  - !ruby/object:Gem::Version
341
342
  version: '0'
342
343
  requirements: []
343
- rubyforge_project:
344
- rubygems_version: 2.6.8
344
+ rubygems_version: 3.2.22
345
345
  signing_key:
346
346
  specification_version: 4
347
347
  summary: Library for HTTP request signing (Ruby implementation)
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.2.3
4
- - 2.3.0
5
- before_script: ./scripts/checkout_test_suite.sh