escher 0.3.2 → 0.3.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 +4 -4
- data/.travis.yml +2 -1
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/escher.gemspec +2 -0
- data/lib/escher/auth.rb +5 -5
- data/lib/escher/request/action_dispatch_request.rb +42 -0
- data/lib/escher/request/base.rb +33 -0
- data/lib/escher/request/factory.rb +16 -9
- data/lib/escher/request/rack_request.rb +44 -24
- data/lib/escher/version.rb +1 -1
- data/lib/escher.rb +1 -1
- data/spec/escher/request/action_dispatch_request_spec.rb +114 -0
- data/spec/escher/request/factory_spec.rb +11 -3
- data/spec/escher/request/rack_request_spec.rb +2 -0
- data/spec/spec_helper.rb +3 -1
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf5ca3954d669d4c1305dd98027a8b5d4fe37c49
|
4
|
+
data.tar.gz: 4a16a2338e1a81efade3a7bd9e01ac5bc888c453
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f121d4fc3afed7141855fc060e8a6f04af57f783d823b15a43f61bbad4dbcefc671514938b103d01e2fbbd605853aeb0cdb47a7d78762c2c86b5edf2820f133
|
7
|
+
data.tar.gz: 102ca5ed92167b8cfa9ddb9fca6d1cd54e5a6d32006a46e2965185cf575e91ff449012fa7e86be7578600687734adcfc9e6bc210d5ce81b25a409133d0b72c07
|
data/.travis.yml
CHANGED
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2014 Emarsys Technologies Kft.
|
3
|
+
Copyright (c) 2014-2015 Emarsys Technologies Kft.
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -5,4 +5,4 @@ Escher helps you creating secure HTTP requests (for APIs) by signing HTTP(s) req
|
|
5
5
|
|
6
6
|
The algorithm is based on [Amazon's _AWS Signature Version 4_](http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html), but we have generalized and extended it.
|
7
7
|
|
8
|
-
More details will be available at our [documentation site](
|
8
|
+
More details will be available at our [documentation site](http://escherauth.io/).
|
data/escher.gemspec
CHANGED
@@ -21,6 +21,8 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.required_ruby_version = '>= 1.9'
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.6"
|
24
|
+
spec.add_development_dependency "rails"
|
25
|
+
|
24
26
|
spec.add_development_dependency "rake", "~> 10"
|
25
27
|
spec.add_development_dependency "rspec", "~> 2"
|
26
28
|
|
data/lib/escher/auth.rb
CHANGED
@@ -176,12 +176,12 @@ module Escher
|
|
176
176
|
canonicalized_request = canonicalize(method, path, query_parts, body, headers, signed_headers.uniq)
|
177
177
|
string_to_sign = get_string_to_sign(canonicalized_request)
|
178
178
|
|
179
|
-
signing_key =
|
179
|
+
signing_key = OpenSSL::HMAC.digest(@algo, @algo_prefix + api_secret, short_date(@current_time))
|
180
180
|
@credential_scope.split('/').each { |data|
|
181
|
-
signing_key =
|
181
|
+
signing_key = OpenSSL::HMAC.digest(@algo, signing_key, data)
|
182
182
|
}
|
183
183
|
|
184
|
-
|
184
|
+
OpenSSL::HMAC.hexdigest(@algo, signing_key, string_to_sign)
|
185
185
|
end
|
186
186
|
|
187
187
|
|
@@ -236,9 +236,9 @@ module Escher
|
|
236
236
|
def create_algo
|
237
237
|
case @hash_algo
|
238
238
|
when 'SHA256'
|
239
|
-
@algo = Digest::
|
239
|
+
@algo = OpenSSL::Digest::SHA256.new
|
240
240
|
when 'SHA512'
|
241
|
-
@algo = Digest::
|
241
|
+
@algo = OpenSSL::Digest::SHA521.new
|
242
242
|
else
|
243
243
|
raise EscherError, 'Unidentified hash algorithm'
|
244
244
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Escher
|
2
|
+
module Request
|
3
|
+
class ActionDispatchRequest < Base
|
4
|
+
|
5
|
+
def headers
|
6
|
+
request.env.
|
7
|
+
select { |header_name, _| header_name.start_with? "HTTP_" }.
|
8
|
+
map { |header_name, value| [header_name[5..-1].tr('_', '-'), value] }
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
def method
|
14
|
+
request.request_method
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
def body
|
20
|
+
request.body or ''
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
def path
|
26
|
+
request.env['REQUEST_PATH']
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
def query_values
|
32
|
+
Addressable::URI.new(:query => request.env['QUERY_STRING']).query_values(Array) or []
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
def set_header(header_name, value)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/escher/request/base.rb
CHANGED
@@ -24,6 +24,39 @@ module Escher
|
|
24
24
|
header[1]
|
25
25
|
end
|
26
26
|
|
27
|
+
|
28
|
+
|
29
|
+
def method
|
30
|
+
raise("Implementation missing for #{__method__}")
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
def body
|
36
|
+
raise("Implementation missing for #{__method__}")
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
def headers
|
42
|
+
raise('Implementation missing, should return array of array with [key,value] pairs')
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
def path
|
48
|
+
raise("Implementation missing for #{__method__}")
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
def query_values
|
54
|
+
raise("Implementation missing for #{__method__}")
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
27
60
|
end
|
28
61
|
end
|
29
62
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require 'escher/request/base'
|
2
|
+
require 'escher/request/hash_request'
|
3
|
+
require 'escher/request/rack_request'
|
4
|
+
require 'escher/request/legacy_request'
|
5
|
+
require 'escher/request/action_dispatch_request'
|
6
6
|
|
7
7
|
module Escher
|
8
8
|
module Request
|
@@ -10,12 +10,19 @@ module Escher
|
|
10
10
|
|
11
11
|
def self.from_request(request)
|
12
12
|
case request
|
13
|
+
|
14
|
+
when defined?(ActionDispatch::Request) && ActionDispatch::Request
|
15
|
+
ActionDispatchRequest.new(request)
|
16
|
+
|
17
|
+
when defined?(Rack::Request) && Rack::Request
|
18
|
+
RackRequest.new(request)
|
19
|
+
|
13
20
|
when Hash
|
14
|
-
HashRequest.new
|
15
|
-
|
16
|
-
RackRequest.new request
|
21
|
+
HashRequest.new(request)
|
22
|
+
|
17
23
|
else
|
18
|
-
Escher::Request::LegacyRequest.new
|
24
|
+
Escher::Request::LegacyRequest.new(request)
|
25
|
+
|
19
26
|
end
|
20
27
|
end
|
21
28
|
|
@@ -1,42 +1,62 @@
|
|
1
|
-
|
2
|
-
module Request
|
3
|
-
class RackRequest < Base
|
1
|
+
class Escher::Request::RackRequest < Escher::Request::Base
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
3
|
+
def initialize(request_env)
|
4
|
+
super(request_env)
|
5
|
+
@rack_request = request_env
|
6
|
+
end
|
10
7
|
|
8
|
+
def env
|
9
|
+
@rack_request.env
|
10
|
+
end
|
11
11
|
|
12
|
+
def rack_request
|
13
|
+
@rack_request
|
14
|
+
end
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
def uri
|
17
|
+
@rack_request.env['REQUEST_URI']
|
18
|
+
end
|
16
19
|
|
20
|
+
def path
|
21
|
+
@rack_request.env['REQUEST_PATH']
|
22
|
+
end
|
17
23
|
|
24
|
+
def host
|
25
|
+
@rack_request.env['HTTP_HOST']
|
26
|
+
end
|
18
27
|
|
19
|
-
|
20
|
-
|
21
|
-
|
28
|
+
def headers
|
29
|
+
@headers ||= @rack_request.env.select { |k, v| k =~ /^HTTP_/i }.map { |k, v| [k.sub(/^HTTP_/i, '').gsub('_', '-'), v] }
|
30
|
+
end
|
22
31
|
|
32
|
+
def method
|
33
|
+
@rack_request.request_method rescue @rack_request.env['REQUEST_METHOD']
|
34
|
+
end
|
23
35
|
|
36
|
+
def payload
|
37
|
+
@payload ||= fetch_payload
|
38
|
+
end
|
24
39
|
|
25
|
-
|
26
|
-
request.env['REQUEST_PATH']
|
27
|
-
end
|
40
|
+
alias body payload
|
28
41
|
|
42
|
+
def query_values
|
43
|
+
Addressable::URI.new(:query => request.env['QUERY_STRING']).query_values(Array) or []
|
44
|
+
end
|
29
45
|
|
46
|
+
def set_header(header_name, value)
|
47
|
+
end
|
30
48
|
|
31
|
-
|
32
|
-
Addressable::URI.new(:query => request.env['QUERY_STRING']).query_values(Array) or []
|
33
|
-
end
|
49
|
+
protected
|
34
50
|
|
51
|
+
def fetch_payload
|
52
|
+
rack_input = @rack_request.body
|
35
53
|
|
54
|
+
return rack_input.to_s if rack_input.nil? || rack_input.is_a?(String)
|
36
55
|
|
37
|
-
|
38
|
-
|
56
|
+
payload = rack_input.read
|
57
|
+
@rack_request.body.rewind
|
58
|
+
payload
|
39
59
|
|
40
|
-
end
|
41
60
|
end
|
42
|
-
|
61
|
+
|
62
|
+
end
|
data/lib/escher/version.rb
CHANGED
data/lib/escher.rb
CHANGED
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'action_dispatch'
|
4
|
+
|
5
|
+
describe Escher::Request::ActionDispatchRequest do
|
6
|
+
|
7
|
+
let(:request_params) { {"PATH_INFO" => "/", } }
|
8
|
+
let(:request) { ActionDispatch::Request.new(request_params) }
|
9
|
+
|
10
|
+
subject { described_class.new request }
|
11
|
+
|
12
|
+
describe "#request" do
|
13
|
+
it "should return the underlying request object" do
|
14
|
+
expect(subject.request).to eq request
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
describe "#headers" do
|
20
|
+
it "should return only the HTTP request headers" do
|
21
|
+
request_params.merge! 'HTTP_HOST' => 'some host',
|
22
|
+
'SOME_HEADER' => 'some header'
|
23
|
+
|
24
|
+
expect(subject.headers).to eq [['HOST', 'some host']]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should replace underscores with dashes in the header name" do
|
28
|
+
request_params.merge! 'HTTP_HOST_NAME' => 'some host'
|
29
|
+
|
30
|
+
expect(subject.headers).to eq [['HOST-NAME', 'some host']]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
describe "#has_header?" do
|
36
|
+
it "should return true if request has specified header, false otherwise" do
|
37
|
+
request_params.merge! 'HTTP_HOST_NAME' => 'some host'
|
38
|
+
|
39
|
+
expect(subject.has_header? 'host-name').to be_truthy
|
40
|
+
expect(subject.has_header? 'no-such-header').to be_falsey
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
describe "#header" do
|
46
|
+
it "should return the value for the requested header" do
|
47
|
+
request_params.merge! 'HTTP_HOST' => 'some host'
|
48
|
+
|
49
|
+
expect(subject.header 'host').to eq 'some host'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return nil if no such header exists" do
|
53
|
+
expect(subject.header 'host').to be_nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
describe "#method" do
|
59
|
+
it "should return the request method" do
|
60
|
+
request_params.merge! 'REQUEST_METHOD' => 'GET'
|
61
|
+
|
62
|
+
expect(subject.method).to eq 'GET'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
describe "#body" do
|
68
|
+
it "should return the request body" do
|
69
|
+
request_params.merge! 'rack.input' => 'request body'
|
70
|
+
|
71
|
+
expect(subject.body).to eq 'request body'
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should return empty string for no body" do
|
75
|
+
expect(subject.body).to eq ''
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
describe "#path" do
|
81
|
+
it "should return the request path" do
|
82
|
+
request_params.merge! 'REQUEST_PATH' => '/resources/id///'
|
83
|
+
|
84
|
+
expect(subject.path).to eq '/resources/id///'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
describe "#query_values" do
|
90
|
+
it "should return the request query parameters as an array of key-value pairs" do
|
91
|
+
request_params.merge! 'QUERY_STRING' => 'search=query¶m=value'
|
92
|
+
|
93
|
+
expect(subject.query_values).to eq [['search', 'query'], ['param', 'value']]
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should return the query parameters regardless of fragments" do
|
97
|
+
request_params.merge! 'QUERY_STRING' => "@\#$%^&+=/,?><`\";:\\|][{}"
|
98
|
+
|
99
|
+
expect(subject.query_values).to eq [["@\#$%^"], ["+", "/,?><`\";:\\|][{}"]]
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return an empty array if the request has no query parameters" do
|
103
|
+
expect(subject.query_values).to eq []
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
describe "#set_header" do
|
109
|
+
it "should ignore calls" do
|
110
|
+
expect { subject.set_header 'test-header', 'test value' }.not_to raise_error
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -1,12 +1,20 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'rack'
|
2
4
|
require 'rack/request'
|
5
|
+
require 'action_dispatch'
|
3
6
|
|
4
7
|
describe Escher::Request::Factory do
|
5
8
|
|
6
9
|
describe ".from_request" do
|
7
|
-
{
|
8
|
-
|
9
|
-
|
10
|
+
{
|
11
|
+
|
12
|
+
{uri: "request uri"} => Escher::Request::HashRequest,
|
13
|
+
Struct.new(:uri) => Escher::Request::LegacyRequest,
|
14
|
+
Rack::Request.new({}) => Escher::Request::RackRequest,
|
15
|
+
ActionDispatch::Request.new({}) => Escher::Request::ActionDispatchRequest
|
16
|
+
|
17
|
+
}.each do |request, expected_class|
|
10
18
|
|
11
19
|
it "should return a #{expected_class.name} when the request to be wrapped is a #{request.class.name}" do
|
12
20
|
expect(expected_class).to receive(:new).with(request).and_return "#{expected_class.name} wrapping request"
|
data/spec/spec_helper.rb
CHANGED
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: 0.3.
|
4
|
+
version: 0.3.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: 2015-
|
11
|
+
date: 2015-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -97,6 +111,7 @@ files:
|
|
97
111
|
- escher.gemspec
|
98
112
|
- lib/escher.rb
|
99
113
|
- lib/escher/auth.rb
|
114
|
+
- lib/escher/request/action_dispatch_request.rb
|
100
115
|
- lib/escher/request/base.rb
|
101
116
|
- lib/escher/request/factory.rb
|
102
117
|
- lib/escher/request/hash_request.rb
|
@@ -280,6 +295,7 @@ files:
|
|
280
295
|
- spec/emarsys_testsuite/post-header-value-spaces.sreq
|
281
296
|
- spec/emarsys_testsuite/post-header-value-spaces.sts
|
282
297
|
- spec/escher/auth_spec.rb
|
298
|
+
- spec/escher/request/action_dispatch_request_spec.rb
|
283
299
|
- spec/escher/request/factory_spec.rb
|
284
300
|
- spec/escher/request/hash_request_spec.rb
|
285
301
|
- spec/escher/request/rack_request_spec.rb
|
@@ -486,6 +502,7 @@ test_files:
|
|
486
502
|
- spec/emarsys_testsuite/post-header-value-spaces.sreq
|
487
503
|
- spec/emarsys_testsuite/post-header-value-spaces.sts
|
488
504
|
- spec/escher/auth_spec.rb
|
505
|
+
- spec/escher/request/action_dispatch_request_spec.rb
|
489
506
|
- spec/escher/request/factory_spec.rb
|
490
507
|
- spec/escher/request/hash_request_spec.rb
|
491
508
|
- spec/escher/request/rack_request_spec.rb
|