dhc 2.2.1 → 2.3.0

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
2
  SHA256:
3
- metadata.gz: 0f70dd2da0d8ec740cf21499fc95ba815a73730c2e1c6a4b8cfef6ff18eef0ce
4
- data.tar.gz: b0773620c07f30f040439d1c56c7a144ee2f144eb0d987d885aec2b940367b6a
3
+ metadata.gz: 674d43c54e6a69f47876b85ef1cc08fdd015002ac96f59fada268959d970d356
4
+ data.tar.gz: 1e9babbad39edeeedde2269d93108a2a0f604ff56cd7f66de5c960de68328bf8
5
5
  SHA512:
6
- metadata.gz: 3c652d89a8d1dcbeadf72472322881ce136692d1b51630c61f4cf0b058ff96d9ded1345c80238fa5d46599d494328ebaecc007a915283eae1971efe89de8cea6
7
- data.tar.gz: 9f71766d909205e3771cd2cfd65130458ac6a73bf35119bd6edf83f1de1ecba418611b66544affd4572b4b275641875d6ae6507fd4a4d07ad1609ae263ff1694
6
+ metadata.gz: 2f29a2c073127d45a6fcd88fab98b8b82b27f3e64aa40a71eab788af580d972d0df7d2dba16e7ba528a28e21a59bf44bfb7d15a93f13bacfd03b1e6d7a0bf78b
7
+ data.tar.gz: 42aadb278b925b63b2c947616ae7c1c6f6d1c7b54487287303c8b3c0b59b54ed0f7b45de501615b8ab854bd73d9e125218ac7c8c205b033566ada8747766ae06
data/README.md CHANGED
@@ -471,6 +471,27 @@ Adds the following header to the request:
471
471
 
472
472
  Assuming the method `access_token` responds on runtime of the request with `123456`.
473
473
 
474
+ ###### Refresh Bearer Authentication
475
+
476
+ If you configure `expires_at` and `refresh` proc in addition to `bearer`, DHC will refresh the bearer token using the defined `refresh` proc in two cases:
477
+
478
+ 1. before the request if `expires_at` < `DateTime.now + 1.minute`
479
+ 2. if the request fails and `refresh(response)` responds to true
480
+
481
+ ```ruby
482
+ refresh = ->(response = nil){
483
+ if response
484
+ if response.code == 401 && response.data && response.data.error_code == 'ACCESS_TOKEN_EXPIRED'
485
+ session[:access_token] = new_access_token
486
+ end
487
+ else
488
+ session[:access_token] = new_access_token
489
+ end
490
+ }
491
+
492
+ DHC.get('http://depay.fi', auth: { bearer: -> { session[:access_token] }, refresh: refresh, expires_at: DateTime.now + 1.day })
493
+ ```
494
+
474
495
  ##### Basic Authentication
475
496
 
476
497
  ```ruby
@@ -6,6 +6,7 @@ class DHC::Auth < DHC::Interceptor
6
6
 
7
7
  def before_init
8
8
  body_authentication! if auth_options[:body]
9
+ auth_options[:refresh].call if refresh_bearer?
9
10
  end
10
11
 
11
12
  def before_request
@@ -14,13 +15,23 @@ class DHC::Auth < DHC::Interceptor
14
15
  end
15
16
 
16
17
  def after_response
17
- return unless configuration_correct?
18
- return unless reauthenticate?
19
- reauthenticate!
18
+ reauthenticate! if configuration_correct? && reauthenticate?
19
+ retry_with_refreshed_token! if retry_with_refreshed_token?
20
20
  end
21
21
 
22
22
  private
23
23
 
24
+ def refresh_bearer?
25
+ auth_options[:bearer] &&
26
+ auth_options[:refresh].is_a?(Proc) &&
27
+ bearer_expired?(auth_options[:expires_at])
28
+ end
29
+
30
+ def bearer_expired?(expires_at)
31
+ expires_at = DateTime.parse(expires_at) if expires_at.is_a?(String)
32
+ expires_at < DateTime.now + 1.minute
33
+ end
34
+
24
35
  def body_authentication!
25
36
  auth = auth_options[:body]
26
37
  request.options[:body] = (request.options[:body] || {}).merge(auth)
@@ -65,6 +76,19 @@ class DHC::Auth < DHC::Interceptor
65
76
  DHC::Error.find(response) == DHC::Unauthorized
66
77
  end
67
78
 
79
+ def retry_with_refreshed_token!
80
+ bearer_authentication!
81
+ new_options = request.options.dup
82
+ new_options = new_options.merge(retry: { max: 1 })
83
+ request.options = new_options
84
+ end
85
+
86
+ def retry_with_refreshed_token?
87
+ auth_options[:bearer] &&
88
+ auth_options[:refresh].is_a?(Proc) &&
89
+ auth_options[:refresh].call(response)
90
+ end
91
+
68
92
  def bearer_header_present?
69
93
  @has_bearer_header ||= request.headers['Authorization'] =~ /^Bearer .+$/i
70
94
  end
@@ -28,7 +28,7 @@ class DHC::Rollbar < DHC::Interceptor
28
28
  }.merge additional_params
29
29
  begin
30
30
  Rollbar.warning("Status: #{response.code} URL: #{request.url}", data)
31
- rescue Encoding::UndefinedConversionError
31
+ rescue JSON::GeneratorError
32
32
  sanitized_data = data.deep_transform_values { |value| self.class.fix_invalid_encoding(value) }
33
33
  Rollbar.warning("Status: #{response.code} URL: #{request.url}", sanitized_data)
34
34
  end
data/lib/dhc/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DHC
4
- VERSION ||= '2.2.1'
4
+ VERSION ||= '2.3.0'
5
5
  end
@@ -15,7 +15,7 @@ describe DHC::Error do
15
15
  expect { "#{valid} #{invalid}" }.to raise_error Encoding::CompatibilityError
16
16
  end
17
17
  it 'to_json on an array raises an error' do
18
- expect { [valid, invalid].to_json }.to raise_error Encoding::UndefinedConversionError
18
+ expect { [valid, invalid].to_json }.to raise_error JSON::GeneratorError
19
19
  end
20
20
 
21
21
  it 'to_s on a hash does not raise an error' do
@@ -23,7 +23,7 @@ describe DHC::Error do
23
23
  end
24
24
 
25
25
  it 'to_json on a hash does raise an error' do
26
- expect { { valid: valid, invalid: invalid }.to_json }.to raise_error Encoding::UndefinedConversionError
26
+ expect { { valid: valid, invalid: invalid }.to_json }.to raise_error JSON::GeneratorError
27
27
  end
28
28
  end
29
29
 
@@ -3,17 +3,61 @@
3
3
  require 'rails_helper'
4
4
 
5
5
  describe DHC::Auth do
6
- before(:each) do
7
- DHC.config.interceptors = [DHC::Auth]
6
+ context 'simple bearer token authentication' do
7
+ before(:each) do
8
+ DHC.config.interceptors = [DHC::Auth]
9
+ end
10
+
11
+ it 'adds the bearer token to every request' do
12
+ def bearer_token
13
+ '123456'
14
+ end
15
+ options = { bearer: -> { bearer_token } }
16
+ DHC.config.endpoint(:local, 'http://depay.fi', auth: options)
17
+ stub_request(:get, 'http://depay.fi').with(headers: { 'Authorization' => 'Bearer 123456' })
18
+ DHC.get(:local)
19
+ end
8
20
  end
9
21
 
10
- it 'adds the bearer token to every request' do
11
- def bearer_token
12
- '123456'
22
+ context 'refresh' do
23
+ before(:each) do
24
+ DHC.config.interceptors = [DHC::Auth, DHC::Retry]
25
+ end
26
+
27
+ let(:first_access_token) { '1_ACCESS_TOKEN' }
28
+ let(:second_access_token) { '2_ACCESS_TOKEN' }
29
+ let(:third_access_token) { '3_ACCESS_TOKEN' }
30
+
31
+ let :session do
32
+ {
33
+ access_token: first_access_token
34
+ }
35
+ end
36
+
37
+ refresh = -> {}
38
+
39
+ before do
40
+ refresh = ->(response = nil) {
41
+ if response
42
+ if response.code == 401 && response.data && response.data.error_code == 'ACCESS_TOKEN_EXPIRED'
43
+ session[:access_token] = third_access_token
44
+ end
45
+ else
46
+ session[:access_token] = second_access_token
47
+ end
48
+ }
49
+ end
50
+
51
+ it 'refreshes the bearer if it expired' do
52
+ stub_request(:get, 'http://depay.fi/').with(headers: { 'Authorization' => 'Bearer 2_ACCESS_TOKEN' })
53
+ DHC.get('http://depay.fi', auth: { bearer: -> { session[:access_token] }, refresh: refresh, expires_at: (DateTime.now - 1.minute).to_s })
54
+ end
55
+
56
+ it 'can evaluate response errors (like unauthorized) inside the refresh proc' do
57
+ stub_request(:get, 'http://depay.fi/').with(headers: { 'Authorization' => 'Bearer 2_ACCESS_TOKEN' })
58
+ .to_return(status: 401, body: { "error_code": 'ACCESS_TOKEN_EXPIRED' }.to_json)
59
+ stub_request(:get, 'http://depay.fi/').with(headers: { 'Authorization' => 'Bearer 3_ACCESS_TOKEN' })
60
+ DHC.get('http://depay.fi', auth: { bearer: -> { session[:access_token] }, refresh: refresh, expires_at: (DateTime.now - 1.minute).to_s })
13
61
  end
14
- options = { bearer: -> { bearer_token } }
15
- DHC.config.endpoint(:local, 'http://depay.fi', auth: options)
16
- stub_request(:get, 'http://depay.fi').with(headers: { 'Authorization' => 'Bearer 123456' })
17
- DHC.get(:local)
18
62
  end
19
63
  end
@@ -14,7 +14,7 @@ describe DHC::Rollbar do
14
14
  class Rollbar; end
15
15
  ::Rollbar.stub(:warning) do
16
16
  call_counter += 1
17
- raise Encoding::UndefinedConversionError if call_counter == 1
17
+ raise JSON::GeneratorError if call_counter == 1
18
18
  end
19
19
 
20
20
  # the response for the caller is still DHC::BadRequest
@@ -24,7 +24,7 @@ describe DHC::Rollbar do
24
24
  let(:invalid) { (+"in\xc3lid").force_encoding('ASCII-8BIT') }
25
25
  let(:valid) { described_class.fix_invalid_encoding(invalid) }
26
26
 
27
- it 'calls fix_invalid_encoding incase a Encoding::UndefinedConversionError was encountered' do
27
+ it 'calls fix_invalid_encoding incase a JSON::GeneratorError was encountered' do
28
28
  expect(described_class).to have_received(:fix_invalid_encoding).with(invalid)
29
29
  end
30
30
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dhc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - https://github.com/DePayFi/dhc/contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-23 00:00:00.000000000 Z
11
+ date: 2023-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -399,7 +399,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
399
399
  version: '0'
400
400
  requirements:
401
401
  - Ruby >= 2.0.0
402
- rubygems_version: 3.2.22
402
+ rubygems_version: 3.4.1
403
403
  signing_key:
404
404
  specification_version: 4
405
405
  summary: Advanced HTTP Client for Ruby, fueled with interceptors