ey-hmac 2.0.2 → 2.3.1

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.
@@ -1,21 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ey-hmac'
2
4
  require 'faraday'
3
5
 
4
- class Ey::Hmac::Faraday < Faraday::Response::Middleware
5
- dependency("ey-hmac")
6
+ class Ey::Hmac::Faraday < Faraday::Middleware
7
+ dependency('ey-hmac') if respond_to?(:dependency)
6
8
 
7
9
  attr_reader :key_id, :key_secret, :options
8
10
 
9
11
  def initialize(app, key_id, key_secret, options = {})
10
12
  super(app)
11
- @key_id, @key_secret = key_id, key_secret
13
+ @key_id = key_id
14
+ @key_secret = key_secret
12
15
  @options = options
13
16
  end
14
17
 
15
18
  def call(env)
16
- Ey::Hmac.sign!(env, key_id, key_secret, {adapter: Ey::Hmac::Adapter::Faraday}.merge(options))
19
+ Ey::Hmac.sign!(env, key_id, key_secret, { adapter: Ey::Hmac::Adapter::Faraday }.merge(options))
17
20
  @app.call(env)
18
21
  end
19
22
  end
20
23
 
21
- Faraday::Middleware.register_middleware :hmac => Ey::Hmac::Faraday
24
+ Faraday::Middleware.register_middleware hmac: Ey::Hmac::Faraday
data/lib/ey-hmac/rack.rb CHANGED
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Request middleware that performs HMAC request signing
2
4
  class Ey::Hmac::Rack
3
5
  attr_reader :key_id, :key_secret, :options
4
6
 
5
7
  def initialize(app, key_id, key_secret, options = {})
6
8
  @app = app
7
- @key_id, @key_secret = key_id, key_secret
9
+ @key_id = key_id
10
+ @key_secret = key_secret
8
11
  @options = options
9
12
  end
10
13
 
@@ -1,5 +1,7 @@
1
- module Ey
1
+ # frozen_string_literal: true
2
+
3
+ module Ey # rubocop:disable Style/ClassAndModuleChildren
2
4
  module Hmac
3
- VERSION = "2.0.2"
5
+ VERSION = '2.3.1'
4
6
  end
5
7
  end
data/lib/ey-hmac.rb CHANGED
@@ -1,102 +1,102 @@
1
- require "ey-hmac/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'ey-hmac/version'
2
4
 
3
5
  require 'base64'
4
6
  require 'digest/md5'
5
7
  require 'openssl'
6
8
  require 'time'
7
9
 
8
- module Ey
9
- module Hmac
10
- Error = Class.new(StandardError)
11
-
12
- MissingSecret = Class.new(Error)
13
- MissingAuthorization = Class.new(Error)
14
- SignatureMismatch = Class.new(Error)
15
-
16
- autoload :Adapter, "ey-hmac/adapter"
17
- autoload :Faraday, "ey-hmac/faraday"
18
- autoload :Rack, "ey-hmac/rack"
19
-
20
- def self.default_adapter=(default_adapter)
21
- @default_adapter = default_adapter
22
- end
23
-
24
- def self.default_adapter
25
- @default_adapter ||= begin
26
- if defined?(Rack) || defined?(Rails)
27
- Ey::Hmac::Adapter::Rack
28
- elsif defined?(Faraday)
29
- Ey::Hmac::Adapter::Rails
30
- end
31
- end
32
- end
33
-
34
- # Signs request by calculating signature and adding it to the specified header
35
- # @example
36
- # Ey::Hmac.sign!(env, @key_id, @key_secret)
37
- #
38
- # @see Ey::Hmac::Adapter#sign!
39
- #
40
- # @param request [Hash] request environment
41
- # @option options [Ey::Hmac::Adapter] :adapter (#{default_adapter}) adapter to sign request with
42
- # @option options [Integer] :version (nil) signature version
43
- # @option options [String] :authorization_header ('Authorization') Authorization header key.
44
- # @option options [String] :service ('EyHmac') service name prefixed to {Ey::Hmac::Adapter#authorization}
45
- #
46
- # @return [String] authorization signature
47
- def self.sign!(request, key_id, key_secret, options={})
48
- adapter = options[:adapter] || Ey::Hmac.default_adapter
49
-
50
- raise ArgumentError, "Missing adapter and Ey::Hmac.default_adapter" unless adapter
51
-
52
- adapter.new(request, options).sign!(key_id, key_secret)
53
- end
54
-
55
- # @example
56
- # Ey::Hmac.authenticated? do |key_id|
57
- # @consumer = Consumer.where(auth_id: key_id).first
58
- # @consumer && @consumer.auth_key
59
- # end
60
- #
61
- # @see Ey::Hmac::Adapter#authenticated?
62
- # @see Ey::Hmac#authenticate!
63
- #
64
- # @param request [Hash] request environment
65
- # @option options [Ey::Hmac::Adapter] :adapter ({#default_adapter}) adapter to verify request with
66
- # @yieldparam key_id [String] public HMAC key
67
- #
68
- # @return [Boolean] success of authentication
69
- def self.authenticated?(request, options={}, &block)
70
- adapter = options[:adapter] || Ey::Hmac.default_adapter
71
-
72
- raise ArgumentError, "Missing adapter and Ey::Hmac.default_adapter" unless adapter
73
-
74
- adapter.new(request, options).authenticated?(&block)
75
- end
76
-
77
- # Check {Ey::Hmac::Adapter#authorization_signature} against calculated {Ey::Hmac::Adapter#signature}
78
- # @example
79
- # Ey::Hmac.authenticate! do |key_id|
80
- # @consumer = Consumer.where(auth_id: key_id).first
81
- # @consumer && @consumer.auth_key
82
- # end
83
- #
84
- # @see Ey::Hmac::Adapter#authenticate!
85
- #
86
- # @param request [Hash] request environment
87
- # @yieldparam key_id [String] public HMAC key
88
- # @option options [Ey::Hmac::Adapter] :adapter ({#default_adapter}) adapter to verify request with
89
- #
90
- # @raise [SignatureMismatch] if the value of {Ey::Hmac::Adapter#authorization_signature} does not match {Ey::Hmac::Adapter#signature}
91
- # @raise [MissingSecret] if the block does not return a private key matching +key_id+
92
- # @raise [MissingAuthorization] if the value of {Ey::Hmac::Adapter#authorization_signature} is nil
93
- # @return [TrueClass] if authentication was successful
94
- def self.authenticate!(request, options={}, &block)
95
- adapter = options[:adapter] || Ey::Hmac.default_adapter
96
-
97
- raise ArgumentError, "Missing adapter and Ey::Hmac.default_adapter" unless adapter
98
-
99
- adapter.new(request, options).authenticate!(&block)
100
- end
10
+ module Ey::Hmac
11
+ Error = Class.new(StandardError)
12
+
13
+ MissingSecret = Class.new(Error)
14
+ MissingAuthorization = Class.new(Error)
15
+ SignatureMismatch = Class.new(Error)
16
+ ExpiredHmac = Class.new(Error)
17
+
18
+ autoload :Adapter, 'ey-hmac/adapter'
19
+ autoload :Faraday, 'ey-hmac/faraday'
20
+ autoload :Rack, 'ey-hmac/rack'
21
+
22
+ def self.default_adapter=(default_adapter)
23
+ @default_adapter = default_adapter
24
+ end
25
+
26
+ def self.default_adapter
27
+ @default_adapter ||= if defined?(::Rack) || defined?(::Rails)
28
+ Ey::Hmac::Adapter::Rack
29
+ elsif defined?(::Faraday)
30
+ Ey::Hmac::Adapter::Faraday
31
+ end
32
+ end
33
+
34
+ # Signs request by calculating signature and adding it to the specified header
35
+ # @example
36
+ # Ey::Hmac.sign!(env, @key_id, @key_secret)
37
+ #
38
+ # @see Ey::Hmac::Adapter#sign!
39
+ #
40
+ # @param request [Hash] request environment
41
+ # @option options [Ey::Hmac::Adapter] :adapter (#{default_adapter}) adapter to sign request with
42
+ # @option options [Integer] :version (nil) signature version
43
+ # @option options [String] :authorization_header ('Authorization') Authorization header key.
44
+ # @option options [String] :service ('EyHmac') service name prefixed to {Ey::Hmac::Adapter#authorization}
45
+ #
46
+ # @return [String] authorization signature
47
+ def self.sign!(request, key_id, key_secret, options = {})
48
+ adapter = options[:adapter] || Ey::Hmac.default_adapter
49
+
50
+ raise ArgumentError, 'Missing adapter and Ey::Hmac.default_adapter' unless adapter
51
+
52
+ adapter.new(request, options).sign!(key_id, key_secret)
53
+ end
54
+
55
+ # @example
56
+ # Ey::Hmac.authenticated? do |key_id|
57
+ # @consumer = Consumer.where(auth_id: key_id).first
58
+ # @consumer && @consumer.auth_key
59
+ # end
60
+ #
61
+ # @see Ey::Hmac::Adapter#authenticated?
62
+ # @see Ey::Hmac#authenticate!
63
+ #
64
+ # @param request [Hash] request environment
65
+ # @option options [Ey::Hmac::Adapter] :adapter ({#default_adapter}) adapter to verify request with
66
+ # @yieldparam key_id [String] public HMAC key
67
+ #
68
+ # @return [Boolean] success of authentication
69
+ def self.authenticated?(request, options = {}, &block)
70
+ adapter = options[:adapter] || Ey::Hmac.default_adapter
71
+
72
+ raise ArgumentError, 'Missing adapter and Ey::Hmac.default_adapter' unless adapter
73
+
74
+ adapter.new(request, options).authenticated?(&block)
75
+ end
76
+
77
+ # Check {Ey::Hmac::Adapter#authorization_signature} against calculated {Ey::Hmac::Adapter#signature}
78
+ # @example
79
+ # Ey::Hmac.authenticate! do |key_id|
80
+ # @consumer = Consumer.where(auth_id: key_id).first
81
+ # @consumer && @consumer.auth_key
82
+ # end
83
+ #
84
+ # @see Ey::Hmac::Adapter#authenticate!
85
+ #
86
+ # @param request [Hash] request environment
87
+ # @yieldparam key_id [String] public HMAC key
88
+ # @option options [Ey::Hmac::Adapter] :adapter ({#default_adapter}) adapter to verify request with
89
+ #
90
+ # @raise [SignatureMismatch] if the value of {Ey::Hmac::Adapter#authorization_signature} does not
91
+ # match {Ey::Hmac::Adapter#signature}
92
+ # @raise [MissingSecret] if the block does not return a private key matching +key_id+
93
+ # @raise [MissingAuthorization] if the value of {Ey::Hmac::Adapter#authorization_signature} is nil
94
+ # @return [TrueClass] if authentication was successful
95
+ def self.authenticate!(request, options = {}, &block)
96
+ adapter = options[:adapter] || Ey::Hmac.default_adapter
97
+
98
+ raise ArgumentError, 'Missing adapter and Ey::Hmac.default_adapter' unless adapter
99
+
100
+ adapter.new(request, options).authenticate!(&block)
101
101
  end
102
102
  end
data/spec/faraday_spec.rb CHANGED
@@ -1,20 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe "faraday" do
5
+ describe 'faraday' do
4
6
  before(:all) { Bundler.require(:faraday) }
5
7
 
6
8
  let!(:key_id) { SecureRandom.hex(8) }
7
9
  let!(:key_secret) { SecureRandom.hex(16) }
8
10
 
9
- describe "adapter" do
11
+ describe 'adapter' do
10
12
  let!(:adapter) { Ey::Hmac::Adapter::Faraday }
11
13
 
12
- it "signs a multipart post" do
14
+ it 'signs a multipart post' do
13
15
  app = lambda do |env|
14
16
  authenticated = Ey::Hmac.authenticate!(env, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
15
17
  (auth_id == key_id) && key_secret
16
18
  end
17
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
19
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
18
20
  end
19
21
 
20
22
  require 'ey-hmac/faraday'
@@ -28,117 +30,115 @@ describe "faraday" do
28
30
  c.adapter(:rack, app)
29
31
  end
30
32
 
31
- tempfile = Tempfile.new("hmac")
33
+ tempfile = Tempfile.new('hmac')
32
34
  tempfile.write SecureRandom.hex(512)
33
35
  tempfile.close
34
36
 
35
37
  expect(
36
- connection.post { |req| req.body = {"output" => Faraday::UploadIO.new(tempfile.path, "text/plain")} }.status
38
+ connection.post { |req| req.body = { 'output' => Faraday::UploadIO.new(tempfile.path, 'text/plain') } }.status
37
39
  ).to eq(200)
38
40
  end
39
41
 
40
- it "signs and reads a request" do
41
- request = Faraday::Request.new.tap { |r|
42
- r.method = :get
43
- r.path = "/auth"
44
- r.body = "{1: 2}"
45
- r.headers = {"Content-Type" => "application/xml"}
46
- }.to_env(
47
- Faraday::Connection.new("http://localhost")
42
+ it 'signs and reads a request' do
43
+ request = Faraday::Request.create(:get) do |r|
44
+ r.path = '/auth'
45
+ r.body = '{1: 2}'
46
+ r.headers = { 'Content-Type' => 'application/xml' }
47
+ end.to_env(
48
+ Faraday::Connection.new('http://localhost')
48
49
  )
49
50
 
50
51
  Ey::Hmac.sign!(request, key_id, key_secret, adapter: adapter)
51
52
 
52
- expect(request[:request_headers]['Authorization']).to start_with("EyHmac")
53
- expect(request[:request_headers]['Content-Digest']).to eq(Digest::MD5.hexdigest(request[:body]))
53
+ expect(request[:request_headers]['Authorization']).to start_with('EyHmac')
54
+ expect(request[:request_headers]['Content-Digest']).to eq(Digest::MD5.hexdigest(request[:body]))
54
55
  expect(Time.parse(request[:request_headers]['Date'])).not_to be_nil
55
56
 
56
57
  yielded = false
57
58
 
58
- expect(Ey::Hmac.authenticated?(request, adapter: adapter) do |key_id|
59
+ expect(Ey::Hmac).to be_authenticated(request, adapter: adapter) do |key_id|
59
60
  expect(key_id).to eq(key_id)
60
61
  yielded = true
61
62
  key_secret
62
- end).to be_truthy
63
+ end
63
64
 
64
65
  expect(yielded).to be_truthy
65
66
  end
66
67
 
67
- it "does not set Content-Digest if body is nil" do
68
- request = Faraday::Request.new.tap { |r|
69
- r.method = :get
70
- r.path = "/auth"
68
+ it 'does not set Content-Digest if body is nil' do
69
+ request = Faraday::Request.create(:get) do |r|
70
+ r.path = '/auth'
71
71
  r.body = nil
72
- r.headers = {"Content-Type" => "application/xml"}
73
- }.to_env(
74
- Faraday::Connection.new("http://localhost")
72
+ r.headers = { 'Content-Type' => 'application/xml' }
73
+ end.to_env(
74
+ Faraday::Connection.new('http://localhost')
75
75
  )
76
76
 
77
77
  Ey::Hmac.sign!(request, key_id, key_secret, adapter: adapter)
78
78
 
79
- expect(request[:request_headers]['Authorization']).to start_with("EyHmac")
79
+ expect(request[:request_headers]['Authorization']).to start_with('EyHmac')
80
80
  expect(request[:request_headers]).not_to have_key('Content-Digest')
81
81
  expect(Time.parse(request[:request_headers]['Date'])).not_to be_nil
82
82
 
83
83
  yielded = false
84
84
 
85
- expect(Ey::Hmac.authenticated?(request, adapter: adapter) do |key_id|
85
+ expect(Ey::Hmac).to be_authenticated(request, adapter: adapter) do |key_id|
86
86
  expect(key_id).to eq(key_id)
87
87
  yielded = true
88
88
  key_secret
89
- end).to be_truthy
89
+ end
90
90
 
91
91
  expect(yielded).to be_truthy
92
92
  end
93
93
 
94
- it "does not set Content-Digest if body is empty" do
95
- request = Faraday::Request.new.tap do |r|
96
- r.method = :get
97
- r.path = "/auth"
98
- r.body = ""
99
- r.headers = {"Content-Type" => "application/xml"}
100
- end.to_env(Faraday::Connection.new("http://localhost"))
94
+ it 'does not set Content-Digest if body is empty' do
95
+ request = Faraday::Request.create(:get) do |r|
96
+ r.path = '/auth'
97
+ r.body = ''
98
+ r.headers = { 'Content-Type' => 'application/xml' }
99
+ end.to_env(Faraday::Connection.new('http://localhost'))
101
100
 
102
101
  Ey::Hmac.sign!(request, key_id, key_secret, adapter: adapter)
103
102
 
104
- expect(request[:request_headers]['Authorization']).to start_with("EyHmac")
103
+ expect(request[:request_headers]['Authorization']).to start_with('EyHmac')
105
104
  expect(request[:request_headers]).not_to have_key('Content-Digest')
106
- #expect(Time.parse(request[:request_headers]['Date'])).not_to be_nil
105
+ # expect(Time.parse(request[:request_headers]['Date'])).not_to be_nil
107
106
 
108
107
  yielded = false
109
108
 
110
- expect(Ey::Hmac.authenticated?(request, adapter: adapter) do |key_id|
109
+ expect(Ey::Hmac).to be_authenticated(request, adapter: adapter) do |key_id|
111
110
  expect(key_id).to eq(key_id)
112
111
  yielded = true
113
112
  key_secret
114
- end).to be_truthy
113
+ end
115
114
 
116
115
  expect(yielded).to be_truthy
117
116
  end
118
117
 
119
- context "with a request" do
118
+ context 'with a request' do
120
119
  let!(:request) do
121
- Faraday::Request.new.tap do |r|
122
- r.method = :get
123
- r.path = "/auth"
124
- r.body = "{1: 2}"
125
- r.headers = {"Content-Type" => "application/xml"}
126
- end.to_env(Faraday::Connection.new("http://localhost"))
120
+ Faraday::Request.create(:get) do |r|
121
+ r.path = '/auth'
122
+ r.body = '{1: 2}'
123
+ r.headers = { 'Content-Type' => 'application/xml' }
124
+ end.to_env(Faraday::Connection.new('http://localhost'))
127
125
  end
128
- include_examples "authentication"
126
+
127
+ include_examples 'authentication'
129
128
  end
130
129
  end
131
130
 
132
- describe "middleware" do
133
- it "accepts a SHA1 signature" do
131
+ describe 'middleware' do
132
+ it 'accepts a SHA1 signature' do
134
133
  require 'ey-hmac/faraday'
135
134
  Bundler.require(:rack)
136
135
 
137
136
  app = lambda do |env|
138
- authenticated = Ey::Hmac.authenticated?(env, accept_digests: :sha1, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
137
+ authenticated = Ey::Hmac.authenticated?(env, accept_digests: :sha1,
138
+ adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
139
139
  (auth_id == key_id) && key_secret
140
140
  end
141
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
141
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
142
142
  end
143
143
 
144
144
  connection = Faraday.new do |c|
@@ -146,10 +146,10 @@ describe "faraday" do
146
146
  c.adapter(:rack, app)
147
147
  end
148
148
 
149
- expect(connection.get("/resources").status).to eq(200)
149
+ expect(connection.get('/resources').status).to eq(200)
150
150
  end
151
151
 
152
- it "accepts a SHA256 signature" do # default
152
+ it 'accepts a SHA256 signature' do # default
153
153
  require 'ey-hmac/faraday'
154
154
  Bundler.require(:rack)
155
155
 
@@ -157,7 +157,7 @@ describe "faraday" do
157
157
  authenticated = Ey::Hmac.authenticated?(env, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
158
158
  (auth_id == key_id) && key_secret
159
159
  end
160
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
160
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
161
161
  end
162
162
 
163
163
  connection = Faraday.new do |c|
@@ -165,18 +165,19 @@ describe "faraday" do
165
165
  c.adapter(:rack, app)
166
166
  end
167
167
 
168
- expect(connection.get("/resources").status).to eq(200)
168
+ expect(connection.get('/resources').status).to eq(200)
169
169
  end
170
170
 
171
- it "accepts multiple digest signatures" do # default
171
+ it 'accepts multiple digest signatures' do # default
172
172
  require 'ey-hmac/faraday'
173
173
  Bundler.require(:rack)
174
174
 
175
175
  app = lambda do |env|
176
- authenticated = Ey::Hmac.authenticated?(env, accept_digests: [:sha1, :sha256], adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
176
+ authenticated = Ey::Hmac.authenticated?(env, accept_digests: %i[sha1 sha256],
177
+ adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
177
178
  (auth_id == key_id) && key_secret
178
179
  end
179
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
180
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
180
181
  end
181
182
 
182
183
  connection = Faraday.new do |c|
@@ -184,23 +185,24 @@ describe "faraday" do
184
185
  c.adapter(:rack, app)
185
186
  end
186
187
 
187
- expect(connection.get("/resources").status).to eq(200)
188
+ expect(connection.get('/resources').status).to eq(200)
188
189
  end
189
190
 
190
- it "signs empty request" do
191
+ it 'signs empty request' do
191
192
  require 'ey-hmac/faraday'
192
193
  Bundler.require(:rack)
193
194
 
194
- _key_id, _key_secret = key_id, key_secret
195
+ outer_key_id = key_id
196
+ outer_key_secret = key_secret
195
197
  app = Rack::Builder.new do
196
198
  use Rack::Config do |env|
197
- env["CONTENT_TYPE"] ||= "text/html"
199
+ env['CONTENT_TYPE'] ||= 'text/html'
198
200
  end
199
- run(lambda {|env|
201
+ run(lambda { |env|
200
202
  authenticated = Ey::Hmac.authenticate!(env, adapter: Ey::Hmac::Adapter::Rack) do |auth_id|
201
- (auth_id == _key_id) && _key_secret
203
+ (auth_id == outer_key_id) && outer_key_secret
202
204
  end
203
- [(authenticated ? 200 : 401), {"Content-Type" => "text/plain"}, []]
205
+ [(authenticated ? 200 : 401), { 'Content-Type' => 'text/plain' }, []]
204
206
  })
205
207
  end
206
208
 
@@ -210,10 +212,10 @@ describe "faraday" do
210
212
  end
211
213
 
212
214
  expect(connection.get do |req|
213
- req.path = "/resource"
215
+ req.path = '/resource'
214
216
  req.body = nil
215
- req.params = {"a" => "1"}
216
- req.headers = {"Content-Type" => "application/x-www-form-urlencoded"}
217
+ req.params = { 'a' => '1' }
218
+ req.headers = { 'Content-Type' => 'application/x-www-form-urlencoded' }
217
219
  end.status).to eq(200)
218
220
  end
219
221
  end