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 +5 -5
- data/.github/workflows/ruby.yml +33 -0
- data/escher.gemspec +4 -4
- data/lib/escher/auth.rb +24 -21
- data/lib/escher/version.rb +1 -1
- data/repo-info.json +7 -0
- data/spec/emarsys_test_suite_spec.rb +0 -6
- data/spec/escher/auth_spec.rb +2 -2
- metadata +13 -13
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e01dd40666cb6ea783bc477f97f8ae673d5208ac8db7a5bba3ef569c95d3061d
|
4
|
+
data.tar.gz: 953b4c5dab4d7e8e832bd7bc80204f2d324114f893ae4f31df8c4d8ebf01c189
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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", "~>
|
23
|
+
spec.add_development_dependency "bundler", "~> 2.2.20"
|
24
24
|
spec.add_development_dependency "rails"
|
25
25
|
|
26
|
-
spec.add_development_dependency "rake", "~>
|
27
|
-
spec.add_development_dependency "rspec", "~>
|
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.
|
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]
|
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(
|
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(
|
141
|
-
['Date', long_date(
|
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(
|
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' ?
|
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(
|
246
|
-
short_date(
|
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::
|
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?
|
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
|
|
data/lib/escher/version.rb
CHANGED
data/repo-info.json
ADDED
@@ -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
|
data/spec/escher/auth_spec.rb
CHANGED
@@ -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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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: '
|
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: '
|
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:
|
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:
|
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
|
-
|
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)
|