castle-rb 7.1.2 → 8.0.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -159
  3. data/lib/castle/api/authenticate.rb +3 -12
  4. data/lib/castle/api/end_impersonation.rb +1 -3
  5. data/lib/castle/api/filter.rb +2 -10
  6. data/lib/castle/api/log.rb +2 -10
  7. data/lib/castle/api/risk.rb +2 -10
  8. data/lib/castle/api/start_impersonation.rb +1 -3
  9. data/lib/castle/api/track.rb +1 -3
  10. data/lib/castle/client.rb +1 -5
  11. data/lib/castle/commands/log.rb +1 -5
  12. data/lib/castle/commands/risk.rb +1 -5
  13. data/lib/castle/configuration.rb +2 -6
  14. data/lib/castle/core/process_response.rb +25 -2
  15. data/lib/castle/core/process_webhook.rb +4 -7
  16. data/lib/castle/core/send_request.rb +1 -3
  17. data/lib/castle/errors.rb +8 -0
  18. data/lib/castle/headers/extract.rb +1 -3
  19. data/lib/castle/headers/filter.rb +2 -3
  20. data/lib/castle/payload/prepare.rb +1 -2
  21. data/lib/castle/session.rb +1 -1
  22. data/lib/castle/version.rb +1 -1
  23. data/lib/castle.rb +1 -3
  24. data/spec/integration/rails/rails_spec.rb +9 -3
  25. data/spec/integration/rails/support/application.rb +2 -2
  26. data/spec/integration/rails/support/home_controller.rb +4 -30
  27. data/spec/lib/castle/api/approve_device_spec.rb +2 -6
  28. data/spec/lib/castle/api/authenticate_spec.rb +22 -25
  29. data/spec/lib/castle/api/end_impersonation_spec.rb +8 -14
  30. data/spec/lib/castle/api/get_device_spec.rb +1 -3
  31. data/spec/lib/castle/api/get_devices_for_user_spec.rb +1 -3
  32. data/spec/lib/castle/api/report_device_spec.rb +2 -6
  33. data/spec/lib/castle/api/start_impersonation_spec.rb +8 -14
  34. data/spec/lib/castle/api/track_spec.rb +9 -16
  35. data/spec/lib/castle/client_id/extract_spec.rb +2 -9
  36. data/spec/lib/castle/client_spec.rb +37 -78
  37. data/spec/lib/castle/command_spec.rb +3 -3
  38. data/spec/lib/castle/commands/approve_device_spec.rb +2 -2
  39. data/spec/lib/castle/commands/authenticate_spec.rb +17 -24
  40. data/spec/lib/castle/commands/end_impersonation_spec.rb +14 -21
  41. data/spec/lib/castle/commands/filter_spec.rb +15 -15
  42. data/spec/lib/castle/commands/get_device_spec.rb +2 -2
  43. data/spec/lib/castle/commands/get_devices_for_user_spec.rb +2 -2
  44. data/spec/lib/castle/commands/log_spec.rb +15 -15
  45. data/spec/lib/castle/commands/report_device_spec.rb +2 -2
  46. data/spec/lib/castle/commands/risk_spec.rb +15 -15
  47. data/spec/lib/castle/commands/start_impersonation_spec.rb +14 -21
  48. data/spec/lib/castle/commands/track_spec.rb +19 -24
  49. data/spec/lib/castle/configuration_spec.rb +1 -1
  50. data/spec/lib/castle/context/get_default_spec.rb +9 -8
  51. data/spec/lib/castle/context/prepare_spec.rb +3 -4
  52. data/spec/lib/castle/core/process_response_spec.rb +3 -6
  53. data/spec/lib/castle/core/process_webhook_spec.rb +12 -6
  54. data/spec/lib/castle/core/send_request_spec.rb +7 -11
  55. data/spec/lib/castle/failover/strategy_spec.rb +5 -5
  56. data/spec/lib/castle/headers/extract_spec.rb +1 -1
  57. data/spec/lib/castle/headers/filter_spec.rb +6 -3
  58. data/spec/lib/castle/headers/format_spec.rb +5 -5
  59. data/spec/lib/castle/ips/extract_spec.rb +2 -6
  60. data/spec/lib/castle/logger_spec.rb +2 -1
  61. data/spec/lib/castle/payload/prepare_spec.rb +4 -7
  62. data/spec/lib/castle/secure_mode_spec.rb +1 -3
  63. data/spec/lib/castle/session_spec.rb +1 -5
  64. data/spec/lib/castle/singleton_configuration_spec.rb +1 -1
  65. data/spec/lib/castle/utils/clone_spec.rb +1 -1
  66. data/spec/lib/castle/utils/merge_spec.rb +2 -4
  67. data/spec/lib/castle/validators/not_supported_spec.rb +1 -6
  68. data/spec/lib/castle/validators/present_spec.rb +2 -9
  69. data/spec/lib/castle/verdict_spec.rb +3 -3
  70. data/spec/lib/castle/webhooks/verify_spec.rb +12 -6
  71. data/spec/lib/castle_spec.rb +5 -7
  72. data/spec/support/shared_examples/action_request.rb +37 -25
  73. data/spec/support/shared_examples/configuration.rb +14 -16
  74. metadata +48 -48
@@ -8,12 +8,12 @@ describe Castle::Core::SendRequest do
8
8
  let(:headers) { {} }
9
9
  let(:request_build) { {} }
10
10
  let(:expected_headers) { { 'Content-Type' => 'application/json' } }
11
- let(:http) { instance_double('Net::HTTP') }
11
+ let(:http) { instance_double(Net::HTTP) }
12
12
 
13
13
  context 'without http arg provided' do
14
14
  subject(:call) { described_class.call(command, headers, nil, config) }
15
15
 
16
- let(:http) { instance_double('Net::HTTP') }
16
+ let(:http) { instance_double(Net::HTTP) }
17
17
  let(:command) { Castle::Commands::Track.build(event: '$login.succeeded') }
18
18
  let(:headers) { {} }
19
19
  let(:request_build) { {} }
@@ -26,9 +26,7 @@ describe Castle::Core::SendRequest do
26
26
  call
27
27
  end
28
28
 
29
- it do
30
- expect(described_class).to have_received(:build).with(command, expected_headers, config)
31
- end
29
+ it { expect(described_class).to have_received(:build).with(command, expected_headers, config) }
32
30
 
33
31
  it { expect(http).to have_received(:request).with(request_build) }
34
32
  end
@@ -45,9 +43,7 @@ describe Castle::Core::SendRequest do
45
43
 
46
44
  it { expect(Castle::Core::GetConnection).not_to have_received(:call) }
47
45
 
48
- it do
49
- expect(described_class).to have_received(:build).with(command, expected_headers, config)
50
- end
46
+ it { expect(described_class).to have_received(:build).with(command, expected_headers, config) }
51
47
 
52
48
  it { expect(http).to have_received(:request).with(request_build) }
53
49
  end
@@ -66,7 +62,7 @@ describe Castle::Core::SendRequest do
66
62
 
67
63
  before { allow(Castle::Utils::GetTimestamp).to receive(:call).and_return(time) }
68
64
 
69
- it { expect(build.body).to be_eql(expected_body.to_json) }
65
+ it { expect(build.body).to eql(expected_body.to_json) }
70
66
  it { expect(build.method).to eql('POST') }
71
67
  it { expect(build.path).to eql("/v1/#{command.path}") }
72
68
  it { expect(build.to_hash).to have_key('authorization') }
@@ -81,7 +77,7 @@ describe Castle::Core::SendRequest do
81
77
 
82
78
  before { allow(Castle::Utils::GetTimestamp).to receive(:call).and_return(time) }
83
79
 
84
- it { expect(build.body).to be_eql(expected_body.to_json) }
80
+ it { expect(build.body).to eql(expected_body.to_json) }
85
81
  it { expect(build.method).to eql('GET') }
86
82
  it { expect(build.path).to eql("/v1/#{command.path}") }
87
83
  end
@@ -93,7 +89,7 @@ describe Castle::Core::SendRequest do
93
89
 
94
90
  before { allow(Castle::Utils::GetTimestamp).to receive(:call).and_return(time) }
95
91
 
96
- it { expect(build.body).to be_eql(expected_body.to_json) }
92
+ it { expect(build.body).to eql(expected_body.to_json) }
97
93
  it { expect(build.method).to eql('PUT') }
98
94
  it { expect(build.path).to eql("/v1/#{command.path}") }
99
95
  end
@@ -3,10 +3,10 @@
3
3
  describe Castle::Failover::Strategy do
4
4
  subject(:strategy) { described_class }
5
5
 
6
- it { expect(strategy::ALLOW).to be_eql(:allow) }
7
- it { expect(strategy::DENY).to be_eql(:deny) }
8
- it { expect(strategy::CHALLENGE).to be_eql(:challenge) }
9
- it { expect(strategy::THROW).to be_eql(:throw) }
6
+ it { expect(strategy::ALLOW).to be(:allow) }
7
+ it { expect(strategy::DENY).to be(:deny) }
8
+ it { expect(strategy::CHALLENGE).to be(:challenge) }
9
+ it { expect(strategy::THROW).to be(:throw) }
10
10
 
11
- it { expect(Castle::Failover::STRATEGIES).to be_eql(%i[allow deny challenge throw]) }
11
+ it { expect(Castle::Failover::STRATEGIES).to eql(%i[allow deny challenge throw]) }
12
12
  end
@@ -98,6 +98,6 @@ describe Castle::Headers::Extract do
98
98
  Castle.config.denylisted = %w[Accept]
99
99
  end
100
100
 
101
- it { expect(extract_call['Accept']).to eq(true) }
101
+ it { expect(extract_call['Accept']).to be(true) }
102
102
  end
103
103
  end
@@ -14,7 +14,9 @@ describe Castle::Headers::Filter do
14
14
  'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
15
15
  'HTTP_USER_AGENT' => 'Mozilla 1234',
16
16
  'TEST' => '1',
17
- 'REMOTE_ADDR' => '1.2.3.4'
17
+ 'REMOTE_ADDR' => '1.2.3.4',
18
+ 'HTTP_CONTENT_LENGTH' => '0',
19
+ 'http_accept_language.parser' => -> { 'noop' }
18
20
  )
19
21
  result[:HTTP_OK] = 'OK'
20
22
  result
@@ -28,12 +30,13 @@ describe Castle::Headers::Filter do
28
30
  'Ok' => 'OK',
29
31
  'User-Agent' => 'Mozilla 1234',
30
32
  'Remote-Addr' => '1.2.3.4',
31
- 'X-Forwarded-For' => '1.2.3.4'
33
+ 'X-Forwarded-For' => '1.2.3.4',
34
+ 'Accept-Language.parser' => start_with('#<Proc')
32
35
  }
33
36
  end
34
37
  let(:request) { Rack::Request.new(env) }
35
38
 
36
39
  context 'with list of header' do
37
- it { expect(filter_call).to eq(filtered) }
40
+ it { expect(filter_call).to match(filtered) }
38
41
  end
39
42
  end
@@ -4,22 +4,22 @@ describe Castle::Headers::Format do
4
4
  subject(:format) { described_class }
5
5
 
6
6
  it 'removes HTTP_' do
7
- expect(format.call('HTTP_X_TEST')).to be_eql('X-Test')
7
+ expect(format.call('HTTP_X_TEST')).to eql('X-Test')
8
8
  end
9
9
 
10
10
  it 'capitalizes header' do
11
- expect(format.call('X_TEST')).to be_eql('X-Test')
11
+ expect(format.call('X_TEST')).to eql('X-Test')
12
12
  end
13
13
 
14
14
  it 'ignores letter case and -_ divider' do
15
- expect(format.call('http-X_teST')).to be_eql('X-Test')
15
+ expect(format.call('http-X_teST')).to eql('X-Test')
16
16
  end
17
17
 
18
18
  it 'does not remove http if there is no _- char' do
19
- expect(format.call('httpX_teST')).to be_eql('Httpx-Test')
19
+ expect(format.call('httpX_teST')).to eql('Httpx-Test')
20
20
  end
21
21
 
22
22
  it 'capitalizes' do
23
- expect(format.call(:clearance)).to be_eql('Clearance')
23
+ expect(format.call(:clearance)).to eql('Clearance')
24
24
  end
25
25
  end
@@ -16,9 +16,7 @@ describe Castle::IPs::Extract do
16
16
  end
17
17
 
18
18
  context 'when we need to use other ip header' do
19
- let(:headers) do
20
- { 'Cf-Connecting-Ip' => '1.2.3.4', 'X-Forwarded-For' => '1.1.1.1, 1.2.2.2, 1.2.3.5' }
21
- end
19
+ let(:headers) { { 'Cf-Connecting-Ip' => '1.2.3.4', 'X-Forwarded-For' => '1.1.1.1, 1.2.2.2, 1.2.3.5' } }
22
20
 
23
21
  context 'with uppercase format' do
24
22
  before { Castle.config.ip_headers = %w[CF_CONNECTING_IP X-Forwarded-For] }
@@ -77,9 +75,7 @@ describe Castle::IPs::Extract do
77
75
  end
78
76
 
79
77
  context 'when list of not trusted ips provided in X_FORWARDED_FOR' do
80
- let(:headers) do
81
- { 'X-Forwarded-For' => '6.6.6.6, 2.2.2.3, 192.168.0.7', 'Client-Ip' => '6.6.6.6' }
82
- end
78
+ let(:headers) { { 'X-Forwarded-For' => '6.6.6.6, 2.2.2.3, 192.168.0.7', 'Client-Ip' => '6.6.6.6' } }
83
79
 
84
80
  it 'does not allow to spoof ip' do
85
81
  expect(extractor.call).to eql('2.2.2.3')
@@ -3,7 +3,8 @@
3
3
  # tmp logger for testing
4
4
  class TmpLogger
5
5
  # @param _message [String]
6
- def info(_message); end
6
+ def info(_message)
7
+ end
7
8
  end
8
9
 
9
10
  describe Castle::Logger do
@@ -9,14 +9,13 @@ describe Castle::Payload::Prepare do
9
9
  '/',
10
10
  'HTTP_USER_AGENT' => ua,
11
11
  'HTTP_X_FORWARDED_FOR' => ip,
12
- 'HTTP_COOKIE' => "__cid=#{cookie_id};other=efgh"
12
+ 'HTTP_COOKIE' => "__cid=#{cookie_id};other=efgh",
13
+ 'HTTP_CONTENT_LENGTH' => '0'
13
14
  )
14
15
  end
15
16
  let(:request) { Rack::Request.new(env) }
16
17
 
17
- let(:headers) do
18
- { 'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, 'Cookie': true }
19
- end
18
+ let(:headers) { { 'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, Cookie: true } }
20
19
  let(:context) do
21
20
  {
22
21
  client_id: 'abcd',
@@ -34,9 +33,7 @@ describe Castle::Payload::Prepare do
34
33
  let(:time_now) { Time.now }
35
34
  let(:time_formatted) { time_now.utc.iso8601(3) }
36
35
  let(:payload_options) { { user_id: '1234', user_traits: { name: 'Jo' } } }
37
- let(:result) do
38
- { user_id: '1234', user_traits: { name: 'Jo' }, timestamp: time_formatted, context: context }
39
- end
36
+ let(:result) { { user_id: '1234', user_traits: { name: 'Jo' }, timestamp: time_formatted, context: context } }
40
37
 
41
38
  before do
42
39
  Timecop.freeze(time_now)
@@ -2,8 +2,6 @@
2
2
 
3
3
  describe Castle::SecureMode do
4
4
  it 'has signature' do
5
- expect(described_class.signature('test')).to eql(
6
- '0329a06b62cd16b33eb6792be8c60b158d89a2ee3a876fce9a881ebb488c0914'
7
- )
5
+ expect(described_class.signature('test')).to eql('0329a06b62cd16b33eb6792be8c60b158d89a2ee3a876fce9a881ebb488c0914')
8
6
  end
9
7
  end
@@ -39,11 +39,7 @@ describe Castle::Session do
39
39
 
40
40
  before do
41
41
  Castle.config.base_url = 'https://localhost'
42
- stub_request(:get, 'https://localhost/test').to_return(
43
- status: 200,
44
- body: '{}',
45
- headers: {}
46
- )
42
+ stub_request(:get, 'https://localhost/test').to_return(status: 200, body: '{}', headers: {})
47
43
  end
48
44
 
49
45
  context 'with block' do
@@ -10,5 +10,5 @@ describe Castle::SingletonConfiguration do
10
10
  it_behaves_like 'configuration_failover_strategy'
11
11
  it_behaves_like 'configuration_api_secret'
12
12
 
13
- it { expect(config.api_secret).to be_eql('secret') }
13
+ it { expect(config.api_secret).to eql('secret') }
14
14
  end
@@ -13,7 +13,7 @@ describe Castle::Utils::Clone do
13
13
 
14
14
  it do
15
15
  nested[:test] = 'sample'
16
- expect(cloned).to be_eql(result)
16
+ expect(cloned).to eql(result)
17
17
  end
18
18
  end
19
19
  end
@@ -5,11 +5,9 @@ describe Castle::Utils::Merge do
5
5
 
6
6
  describe 'call' do
7
7
  let(:first) { { test: { test1: { c: '4' }, test2: { c: '3' }, a: '1', b: '2' } } }
8
- let(:second) do
9
- { test2: '2', test: { 'test1' => { d: '5' }, :test2 => '6', :a => nil, :b => '3' } }
10
- end
8
+ let(:second) { { test2: '2', test: { 'test1' => { d: '5' }, :test2 => '6', :a => nil, :b => '3' } } }
11
9
  let(:result) { { test2: '2', test: { test1: { c: '4', d: '5' }, test2: '6', b: '3' } } }
12
10
 
13
- it { expect(merge.call(first, second)).to be_eql(result) }
11
+ it { expect(merge.call(first, second)).to eql(result) }
14
12
  end
15
13
  end
@@ -7,12 +7,7 @@ describe Castle::Validators::NotSupported do
7
7
  context 'when keys is present' do
8
8
  let(:keys) { %i[first second] }
9
9
 
10
- it do
11
- expect { call }.to raise_error(
12
- Castle::InvalidParametersError,
13
- 'first is/are not supported'
14
- )
15
- end
10
+ it { expect { call }.to raise_error(Castle::InvalidParametersError, 'first is/are not supported') }
16
11
  end
17
12
 
18
13
  context 'when key is not present' do
@@ -7,20 +7,13 @@ describe Castle::Validators::Present do
7
7
  context 'when keys is not present' do
8
8
  let(:keys) { %i[second third] }
9
9
 
10
- it do
11
- expect { call }.to raise_error(Castle::InvalidParametersError, 'third is missing or empty')
12
- end
10
+ it { expect { call }.to raise_error(Castle::InvalidParametersError, 'third is missing or empty') }
13
11
  end
14
12
 
15
13
  context 'when keys is empty' do
16
14
  let(:keys) { %i[second invalid] }
17
15
 
18
- it do
19
- expect { call }.to raise_error(
20
- Castle::InvalidParametersError,
21
- 'invalid is missing or empty'
22
- )
23
- end
16
+ it { expect { call }.to raise_error(Castle::InvalidParametersError, 'invalid is missing or empty') }
24
17
  end
25
18
 
26
19
  context 'when key is present' do
@@ -3,7 +3,7 @@
3
3
  describe Castle::Verdict do
4
4
  subject(:verdict) { described_class }
5
5
 
6
- it { expect(verdict::ALLOW).to be_eql('allow') }
7
- it { expect(verdict::DENY).to be_eql('deny') }
8
- it { expect(verdict::CHALLENGE).to be_eql('challenge') }
6
+ it { expect(verdict::ALLOW).to eql('allow') }
7
+ it { expect(verdict::DENY).to eql('deny') }
8
+ it { expect(verdict::CHALLENGE).to eql('challenge') }
9
9
  end
@@ -19,13 +19,19 @@ describe Castle::Webhooks::Verify do
19
19
  device_token: 'token',
20
20
  user_id: user_id,
21
21
  trigger: '$login.succeeded',
22
- context: {},
23
- location: {},
24
- user_agent: {}
22
+ context: {
23
+ },
24
+ location: {
25
+ },
26
+ user_agent: {
27
+ }
25
28
  },
26
- user_traits: {},
27
- properties: {},
28
- policy: {}
29
+ user_traits: {
30
+ },
31
+ properties: {
32
+ },
33
+ policy: {
34
+ }
29
35
  }.to_json
30
36
  end
31
37
 
@@ -4,7 +4,7 @@ describe Castle do
4
4
  subject(:castle) { described_class }
5
5
 
6
6
  describe 'config' do
7
- it { expect(castle.config).to be_kind_of(Castle::Configuration) }
7
+ it { expect(castle.config).to be_a(Castle::Configuration) }
8
8
  end
9
9
 
10
10
  describe 'api_secret setter' do
@@ -12,7 +12,7 @@ describe Castle do
12
12
 
13
13
  before { castle.api_secret = value }
14
14
 
15
- it { expect(castle.config.api_secret).to be_eql(value) }
15
+ it { expect(castle.config.api_secret).to eql(value) }
16
16
  end
17
17
 
18
18
  describe 'configure' do
@@ -20,8 +20,8 @@ describe Castle do
20
20
  let(:timeout) { 60 }
21
21
 
22
22
  shared_examples 'config_setup' do
23
- it { expect(castle.config.api_secret).to be_eql(value) }
24
- it { expect(castle.config.request_timeout).to be_eql(timeout) }
23
+ it { expect(castle.config.api_secret).to eql(value) }
24
+ it { expect(castle.config.request_timeout).to eql(timeout) }
25
25
  end
26
26
 
27
27
  context 'with block' do
@@ -52,9 +52,7 @@ describe Castle do
52
52
  let(:value) { 'new_secret' }
53
53
 
54
54
  it do
55
- expect { castle.configure { |config| config.wrong_config = value } }.to raise_error(
56
- Castle::ConfigurationError
57
- )
55
+ expect { castle.configure { |config| config.wrong_config = value } }.to raise_error(Castle::ConfigurationError)
58
56
  end
59
57
  end
60
58
  end
@@ -4,14 +4,7 @@ RSpec.shared_examples_for 'action request' do |action|
4
4
  subject(:request_response) { client.send(action.to_sym, options) }
5
5
 
6
6
  let(:options) do
7
- {
8
- request_token: request_token,
9
- event: event,
10
- status: status,
11
- user: user,
12
- context: context,
13
- properties: properties
14
- }
7
+ { request_token: request_token, event: event, status: status, user: user, context: context, properties: properties }
15
8
  end
16
9
  let(:request_token) { '7e51335b-f4bc-4bc7-875d-b713fb61eb23-bf021a3022a1a302' }
17
10
  let(:event) { '$login' }
@@ -104,19 +97,15 @@ RSpec.shared_examples_for 'action request' do |action|
104
97
  end
105
98
 
106
99
  it { assert_not_requested :post, "https://api.castle.io/v1/#{action}" }
107
- it { expect(request_response[:policy][:action]).to be_eql(Castle::Verdict::ALLOW) }
108
- it { expect(request_response[:action]).to be_eql(Castle::Verdict::ALLOW) }
109
- it { expect(request_response[:user_id]).to be_eql('1234') }
100
+ it { expect(request_response[:policy][:action]).to eql(Castle::Verdict::ALLOW) }
101
+ it { expect(request_response[:action]).to eql(Castle::Verdict::ALLOW) }
102
+ it { expect(request_response[:user_id]).to eql('1234') }
110
103
  it { expect(request_response[:failover]).to be true }
111
- it { expect(request_response[:failover_reason]).to be_eql('Castle is set to do not track.') }
104
+ it { expect(request_response[:failover_reason]).to eql('Castle is set to do not track.') }
112
105
  end
113
106
 
114
107
  context 'when request with fail' do
115
- before do
116
- allow(Castle::API).to receive(:send_request).and_raise(
117
- Castle::RequestError.new(Timeout::Error)
118
- )
119
- end
108
+ before { allow(Castle::API).to receive(:send_request).and_raise(Castle::RequestError.new(Timeout::Error)) }
120
109
 
121
110
  context 'with request error and throw strategy' do
122
111
  before { allow(Castle.config).to receive(:failover_strategy).and_return(:throw) }
@@ -126,11 +115,11 @@ RSpec.shared_examples_for 'action request' do |action|
126
115
 
127
116
  context 'with request error and not throw on eg deny strategy' do
128
117
  it { assert_not_requested :post, "https:/:secret@api.castle.io/v1/#{action}" }
129
- it { expect(request_response[:policy][:action]).to be_eql('allow') }
130
- it { expect(request_response[:action]).to be_eql('allow') }
131
- it { expect(request_response[:user_id]).to be_eql('1234') }
118
+ it { expect(request_response[:policy][:action]).to eql('allow') }
119
+ it { expect(request_response[:action]).to eql('allow') }
120
+ it { expect(request_response[:user_id]).to eql('1234') }
132
121
  it { expect(request_response[:failover]).to be true }
133
- it { expect(request_response[:failover_reason]).to be_eql('Castle::RequestError') }
122
+ it { expect(request_response[:failover_reason]).to eql('Castle::RequestError') }
134
123
  end
135
124
  end
136
125
 
@@ -145,11 +134,34 @@ RSpec.shared_examples_for 'action request' do |action|
145
134
 
146
135
  describe 'not throw on eg deny strategy' do
147
136
  it { assert_not_requested :post, "https:/:secret@api.castle.io/v1/#{action}" }
148
- it { expect(request_response[:policy][:action]).to be_eql('allow') }
149
- it { expect(request_response[:action]).to be_eql('allow') }
150
- it { expect(request_response[:user_id]).to be_eql('1234') }
137
+ it { expect(request_response[:policy][:action]).to eql('allow') }
138
+ it { expect(request_response[:action]).to eql('allow') }
139
+ it { expect(request_response[:user_id]).to eql('1234') }
151
140
  it { expect(request_response[:failover]).to be true }
152
- it { expect(request_response[:failover_reason]).to be_eql('Castle::InternalServerError') }
141
+ it { expect(request_response[:failover_reason]).to eql('Castle::InternalServerError') }
142
+ end
143
+ end
144
+
145
+ context 'when request is 422' do
146
+ describe 'throw InvalidParametersError' do
147
+ let(:response_body) { { type: 'bad_request', message: 'wrong params' }.to_json }
148
+ let(:response_code) { 422 }
149
+
150
+ it { expect { request_response }.to raise_error(Castle::InvalidParametersError, 'wrong params') }
151
+ end
152
+
153
+ describe 'throw InvalidParametersError for legacy endpoints' do
154
+ let(:response_body) { {}.to_json }
155
+ let(:response_code) { 422 }
156
+
157
+ it { expect { request_response }.to raise_error(Castle::InvalidParametersError) }
158
+ end
159
+
160
+ describe 'throw InvalidRequestTokenError' do
161
+ let(:response_body) { { type: 'invalid_request_token', message: 'invalid token' }.to_json }
162
+ let(:response_code) { 422 }
163
+
164
+ it { expect { request_response }.to raise_error(Castle::InvalidRequestTokenError, 'invalid token') }
153
165
  end
154
166
  end
155
167
  end
@@ -3,69 +3,67 @@
3
3
  shared_examples 'configuration_host' do
4
4
  describe 'host' do
5
5
  context 'with default' do
6
- it { expect(config.base_url.host).to be_eql('api.castle.io') }
6
+ it { expect(config.base_url.host).to eql('api.castle.io') }
7
7
  end
8
8
 
9
9
  context 'with setter' do
10
10
  before { config.base_url = 'http://api.castle.dev/v2' }
11
11
 
12
- it { expect(config.base_url.host).to be_eql('api.castle.dev') }
12
+ it { expect(config.base_url.host).to eql('api.castle.dev') }
13
13
  end
14
14
  end
15
15
  end
16
16
 
17
17
  shared_examples 'configuration_request_timeout' do
18
18
  describe 'request_timeout' do
19
- it { expect(config.request_timeout).to be_eql(1000) }
19
+ it { expect(config.request_timeout).to be(1000) }
20
20
 
21
21
  context 'with setter' do
22
22
  let(:value) { 50.0 }
23
23
 
24
24
  before { config.request_timeout = value }
25
25
 
26
- it { expect(config.request_timeout).to be_eql(value) }
26
+ it { expect(config.request_timeout).to eql(value) }
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
31
  shared_examples 'configuration_allowlisted' do
32
32
  describe 'allowlisted' do
33
- it { expect(config.allowlisted.size).to be_eql(0) }
33
+ it { expect(config.allowlisted.size).to be(0) }
34
34
 
35
35
  context 'with setter' do
36
36
  before { config.allowlisted = ['header'] }
37
37
 
38
- it { expect(config.allowlisted).to be_eql(['Header']) }
38
+ it { expect(config.allowlisted).to eql(['Header']) }
39
39
  end
40
40
  end
41
41
  end
42
42
 
43
43
  shared_examples 'configuration_denylisted' do
44
44
  describe 'denylisted' do
45
- it { expect(config.denylisted.size).to be_eql(0) }
45
+ it { expect(config.denylisted.size).to be(0) }
46
46
 
47
47
  context 'with setter' do
48
48
  before { config.denylisted = ['header'] }
49
49
 
50
- it { expect(config.denylisted).to be_eql(['Header']) }
50
+ it { expect(config.denylisted).to eql(['Header']) }
51
51
  end
52
52
  end
53
53
  end
54
54
 
55
55
  shared_examples 'configuration_failover_strategy' do
56
56
  describe 'failover_strategy' do
57
- it { expect(config.failover_strategy).to be_eql(Castle::Failover::Strategy::ALLOW) }
57
+ it { expect(config.failover_strategy).to eql(Castle::Failover::Strategy::ALLOW) }
58
58
 
59
59
  context 'with setter' do
60
60
  before { config.failover_strategy = Castle::Failover::Strategy::DENY }
61
61
 
62
- it { expect(config.failover_strategy).to be_eql(Castle::Failover::Strategy::DENY) }
62
+ it { expect(config.failover_strategy).to eql(Castle::Failover::Strategy::DENY) }
63
63
  end
64
64
 
65
65
  context 'when broken' do
66
- it do
67
- expect { config.failover_strategy = :unicorn }.to raise_error(Castle::ConfigurationError)
68
- end
66
+ it { expect { config.failover_strategy = :unicorn }.to raise_error(Castle::ConfigurationError) }
69
67
  end
70
68
  end
71
69
  end
@@ -81,12 +79,12 @@ shared_examples 'configuration_api_secret' do
81
79
  config.reset
82
80
  end
83
81
 
84
- it { expect(config.api_secret).to be_eql(secret_key_env) }
82
+ it { expect(config.api_secret).to eql(secret_key_env) }
85
83
 
86
84
  context 'when key is overwritten' do
87
85
  before { config.api_secret = secret_key }
88
86
 
89
- it { expect(config.api_secret).to be_eql(secret_key) }
87
+ it { expect(config.api_secret).to eql(secret_key) }
90
88
  end
91
89
  end
92
90
 
@@ -95,7 +93,7 @@ shared_examples 'configuration_api_secret' do
95
93
 
96
94
  before { config.api_secret = value }
97
95
 
98
- it { expect(config.api_secret).to be_eql(value) }
96
+ it { expect(config.api_secret).to eql(value) }
99
97
  end
100
98
  end
101
99
  end