dhc 2.2.1 → 2.3.0

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
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