castle-rb 5.0.0 → 6.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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +107 -33
  3. data/lib/castle.rb +46 -22
  4. data/lib/castle/api.rb +22 -13
  5. data/lib/castle/api/approve_device.rb +25 -0
  6. data/lib/castle/api/authenticate.rb +34 -0
  7. data/lib/castle/api/end_impersonation.rb +29 -0
  8. data/lib/castle/api/get_device.rb +25 -0
  9. data/lib/castle/api/get_devices_for_user.rb +25 -0
  10. data/lib/castle/api/identify.rb +26 -0
  11. data/lib/castle/api/report_device.rb +25 -0
  12. data/lib/castle/api/review.rb +24 -0
  13. data/lib/castle/api/start_impersonation.rb +29 -0
  14. data/lib/castle/api/track.rb +26 -0
  15. data/lib/castle/client.rb +48 -62
  16. data/lib/castle/{extractors/client_id.rb → client_id/extract.rb} +2 -2
  17. data/lib/castle/commands/approve_device.rb +21 -0
  18. data/lib/castle/commands/authenticate.rb +13 -13
  19. data/lib/castle/commands/end_impersonation.rb +25 -0
  20. data/lib/castle/commands/get_device.rb +21 -0
  21. data/lib/castle/commands/get_devices_for_user.rb +21 -0
  22. data/lib/castle/commands/identify.rb +12 -13
  23. data/lib/castle/commands/report_device.rb +21 -0
  24. data/lib/castle/commands/review.rb +6 -3
  25. data/lib/castle/commands/start_impersonation.rb +25 -0
  26. data/lib/castle/commands/track.rb +12 -13
  27. data/lib/castle/configuration.rb +17 -19
  28. data/lib/castle/context/{default.rb → get_default.rb} +5 -6
  29. data/lib/castle/context/{merger.rb → merge.rb} +3 -3
  30. data/lib/castle/context/prepare.rb +18 -0
  31. data/lib/castle/context/{sanitizer.rb → sanitize.rb} +1 -1
  32. data/lib/castle/core/get_connection.rb +25 -0
  33. data/lib/castle/{api/response.rb → core/process_response.rb} +4 -2
  34. data/lib/castle/core/process_webhook.rb +20 -0
  35. data/lib/castle/core/send_request.rb +50 -0
  36. data/lib/castle/errors.rb +2 -0
  37. data/lib/castle/events.rb +1 -1
  38. data/lib/castle/failover/prepare_response.rb +23 -0
  39. data/lib/castle/failover/strategy.rb +20 -0
  40. data/lib/castle/{extractors/headers.rb → headers/extract.rb} +8 -6
  41. data/lib/castle/headers/filter.rb +37 -0
  42. data/lib/castle/headers/format.rb +24 -0
  43. data/lib/castle/{extractors/ip.rb → ip/extract.rb} +8 -7
  44. data/lib/castle/logger.rb +19 -0
  45. data/lib/castle/payload/prepare.rb +27 -0
  46. data/lib/castle/secure_mode.rb +6 -2
  47. data/lib/castle/session.rb +18 -0
  48. data/lib/castle/singleton_configuration.rb +9 -0
  49. data/lib/castle/utils/clean_invalid_chars.rb +24 -0
  50. data/lib/castle/utils/clone.rb +15 -0
  51. data/lib/castle/utils/deep_symbolize_keys.rb +45 -0
  52. data/lib/castle/utils/get_timestamp.rb +15 -0
  53. data/lib/castle/utils/{merger.rb → merge.rb} +3 -3
  54. data/lib/castle/utils/secure_compare.rb +22 -0
  55. data/lib/castle/validators/not_supported.rb +1 -0
  56. data/lib/castle/validators/present.rb +1 -0
  57. data/lib/castle/verdict.rb +13 -0
  58. data/lib/castle/version.rb +1 -1
  59. data/lib/castle/webhooks/verify.rb +43 -0
  60. data/spec/integration/rails/rails_spec.rb +33 -7
  61. data/spec/integration/rails/support/application.rb +3 -1
  62. data/spec/integration/rails/support/home_controller.rb +47 -5
  63. data/spec/lib/castle/api/approve_device_spec.rb +21 -0
  64. data/spec/lib/castle/api/authenticate_spec.rb +140 -0
  65. data/spec/lib/castle/api/end_impersonation_spec.rb +59 -0
  66. data/spec/lib/castle/api/get_device_spec.rb +19 -0
  67. data/spec/lib/castle/api/get_devices_for_user_spec.rb +19 -0
  68. data/spec/lib/castle/api/identify_spec.rb +68 -0
  69. data/spec/lib/castle/api/report_device_spec.rb +21 -0
  70. data/spec/lib/castle/{review_spec.rb → api/review_spec.rb} +3 -3
  71. data/spec/lib/castle/api/start_impersonation_spec.rb +59 -0
  72. data/spec/lib/castle/api/track_spec.rb +68 -0
  73. data/spec/lib/castle/api_spec.rb +16 -1
  74. data/spec/lib/castle/{extractors/client_id_spec.rb → client_id/extract_spec.rb} +2 -2
  75. data/spec/lib/castle/client_spec.rb +39 -21
  76. data/spec/lib/castle/commands/approve_device_spec.rb +24 -0
  77. data/spec/lib/castle/commands/authenticate_spec.rb +7 -16
  78. data/spec/lib/castle/commands/end_impersonation_spec.rb +82 -0
  79. data/spec/lib/castle/commands/get_device_spec.rb +24 -0
  80. data/spec/lib/castle/commands/get_devices_for_user_spec.rb +24 -0
  81. data/spec/lib/castle/commands/identify_spec.rb +5 -16
  82. data/spec/lib/castle/commands/report_device_spec.rb +24 -0
  83. data/spec/lib/castle/commands/review_spec.rb +1 -1
  84. data/spec/lib/castle/commands/{impersonate_spec.rb → start_impersonation_spec.rb} +7 -32
  85. data/spec/lib/castle/commands/track_spec.rb +5 -16
  86. data/spec/lib/castle/configuration_spec.rb +9 -138
  87. data/spec/lib/castle/context/{default_spec.rb → get_default_spec.rb} +1 -2
  88. data/spec/lib/castle/context/{merger_spec.rb → merge_spec.rb} +1 -1
  89. data/spec/lib/castle/context/prepare_spec.rb +44 -0
  90. data/spec/lib/castle/context/{sanitizer_spec.rb → sanitize_spec.rb} +1 -1
  91. data/spec/lib/castle/{api/connection_spec.rb → core/get_connection_spec.rb} +3 -3
  92. data/spec/lib/castle/{api/response_spec.rb → core/process_response_spec.rb} +56 -1
  93. data/spec/lib/castle/core/process_webhook_spec.rb +46 -0
  94. data/spec/lib/castle/{api/request_spec.rb → core/send_request_spec.rb} +20 -16
  95. data/spec/lib/castle/failover/strategy_spec.rb +12 -0
  96. data/spec/lib/castle/{extractors/headers_spec.rb → headers/extract_spec.rb} +7 -7
  97. data/spec/lib/castle/{headers_filter_spec.rb → headers/filter_spec.rb} +3 -3
  98. data/spec/lib/castle/headers/format_spec.rb +25 -0
  99. data/spec/lib/castle/{extractors/ip_spec.rb → ip/extract_spec.rb} +1 -1
  100. data/spec/lib/castle/logger_spec.rb +42 -0
  101. data/spec/lib/castle/payload/prepare_spec.rb +54 -0
  102. data/spec/lib/castle/{api/session_spec.rb → session_spec.rb} +6 -4
  103. data/spec/lib/castle/singleton_configuration_spec.rb +18 -0
  104. data/spec/lib/castle/utils/clean_invalid_chars_spec.rb +69 -0
  105. data/spec/lib/castle/utils/{cloner_spec.rb → clone_spec.rb} +3 -3
  106. data/spec/lib/castle/utils/deep_symbolize_keys_spec.rb +50 -0
  107. data/spec/lib/castle/utils/{timestamp_spec.rb → get_timestamp_spec.rb} +1 -1
  108. data/spec/lib/castle/utils/{merger_spec.rb → merge_spec.rb} +3 -3
  109. data/spec/lib/castle/verdict_spec.rb +9 -0
  110. data/spec/lib/castle/webhooks/verify_spec.rb +69 -0
  111. data/spec/spec_helper.rb +2 -0
  112. data/spec/support/shared_examples/configuration.rb +129 -0
  113. metadata +129 -57
  114. data/lib/castle/api/connection.rb +0 -24
  115. data/lib/castle/api/request.rb +0 -42
  116. data/lib/castle/api/session.rb +0 -20
  117. data/lib/castle/commands/impersonate.rb +0 -26
  118. data/lib/castle/failover_auth_response.rb +0 -21
  119. data/lib/castle/headers_filter.rb +0 -35
  120. data/lib/castle/headers_formatter.rb +0 -22
  121. data/lib/castle/review.rb +0 -11
  122. data/lib/castle/utils.rb +0 -55
  123. data/lib/castle/utils/cloner.rb +0 -11
  124. data/lib/castle/utils/timestamp.rb +0 -12
  125. data/spec/lib/castle/headers_formatter_spec.rb +0 -25
  126. data/spec/lib/castle/utils_spec.rb +0 -156
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::Context::Default do
3
+ describe Castle::Context::GetDefault do
4
4
  subject { described_class.new(request, nil) }
5
5
 
6
6
  let(:ip) { '1.2.3.4' }
@@ -31,7 +31,6 @@ describe Castle::Context::Default do
31
31
  end
32
32
 
33
33
  it { expect(default_context[:active]).to be_eql(true) }
34
- it { expect(default_context[:origin]).to be_eql('web') }
35
34
  it { expect(default_context[:headers]).to be_eql(result_headers) }
36
35
  it { expect(default_context[:ip]).to be_eql(ip) }
37
36
  it { expect(default_context[:client_id]).to be_eql(client_id) }
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::Context::Merger do
3
+ describe Castle::Context::Merge do
4
4
  let(:first) { { test: { test1: { c: '4' } } } }
5
5
 
6
6
  describe '#call' do
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Castle::Context::Prepare do
4
+ let(:ip) { '1.2.3.4' }
5
+ let(:cookie_id) { 'abcd' }
6
+ let(:ua) { 'Chrome' }
7
+ let(:env) do
8
+ Rack::MockRequest.env_for(
9
+ '/',
10
+ 'HTTP_USER_AGENT' => ua,
11
+ 'HTTP_X_FORWARDED_FOR' => ip,
12
+ 'HTTP_COOKIE' => "__cid=#{cookie_id};other=efgh"
13
+ )
14
+ end
15
+ let(:request) { Rack::Request.new(env) }
16
+ let(:context) do
17
+ {
18
+ client_id: 'abcd',
19
+ active: true,
20
+ user_agent: ua,
21
+ headers: headers,
22
+ ip: ip,
23
+ library: { name: 'castle-rb', version: '6.0.0' }
24
+ }
25
+ end
26
+
27
+ let(:headers) do
28
+ {
29
+ 'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, 'Cookie': true
30
+ }
31
+ end
32
+
33
+ before do
34
+ stub_const('Castle::VERSION', '6.0.0')
35
+ end
36
+
37
+ describe '#call' do
38
+ subject(:generated) { described_class.call(request) }
39
+
40
+ context 'when active true' do
41
+ it { is_expected.to eql(context) }
42
+ end
43
+ end
44
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::Context::Sanitizer do
3
+ describe Castle::Context::Sanitize do
4
4
  let(:paylod) { { test: 'test' } }
5
5
 
6
6
  describe '#call' do
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::API::Connection do
3
+ describe Castle::Core::GetConnection do
4
4
  describe '.call' do
5
5
  subject(:class_call) { described_class.call }
6
6
 
@@ -10,7 +10,7 @@ describe Castle::API::Connection do
10
10
  let(:api_url) { '/test' }
11
11
 
12
12
  before do
13
- Castle.config.url = 'http://localhost:3002'
13
+ Castle.config.base_url = 'http://localhost:3002'
14
14
 
15
15
  allow(Net::HTTP)
16
16
  .to receive(:new)
@@ -36,7 +36,7 @@ describe Castle::API::Connection do
36
36
  let(:port) { 443 }
37
37
 
38
38
  before do
39
- Castle.config.url = 'https://localhost'
39
+ Castle.config.base_url = 'https://localhost'
40
40
  end
41
41
 
42
42
  context 'with block' do
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::API::Response do
3
+ describe Castle::Core::ProcessResponse do
4
4
  describe '#call' do
5
5
  subject(:call) { described_class.call(response) }
6
6
 
@@ -10,6 +10,61 @@ describe Castle::API::Response do
10
10
  it { expect(call).to eql(user: 1) }
11
11
  end
12
12
 
13
+ describe 'authenticate' do
14
+ context 'when allow without any additional props' do
15
+ let(:response) { OpenStruct.new(body: '{"action":"allow","user_id":"12345"}', code: 200) }
16
+
17
+ it { expect(call).to eql({ action: 'allow', user_id: '12345' }) }
18
+ end
19
+
20
+ context 'when allow with additional props' do
21
+ let(:response) do
22
+ OpenStruct.new(body: '{"action":"allow","user_id":"12345","internal":{}}', code: 200)
23
+ end
24
+
25
+ it { expect(call).to eql({ action: 'allow', user_id: '12345', internal: {} }) }
26
+ end
27
+
28
+ context 'when deny without risk policy' do
29
+ let(:response) do
30
+ OpenStruct.new(body: '{"action":"deny","user_id":"1","device_token":"abc"}', code: 200)
31
+ end
32
+
33
+ it { expect(call).to eql({ action: 'deny', user_id: '1', device_token: 'abc' }) }
34
+ end
35
+
36
+ context 'when deny with risk policy' do
37
+ let(:body) do
38
+ '{"action":"deny","user_id":"1","device_token":"abc",
39
+ "risk_policy":{"id":"123","revision_id":"abc","name":"def","type":"bot"}}'
40
+ end
41
+ let(:response) do
42
+ OpenStruct.new(
43
+ {
44
+ body: body,
45
+ code: 200
46
+ }
47
+ )
48
+ end
49
+
50
+ let(:result) do
51
+ {
52
+ action: 'deny',
53
+ user_id: '1',
54
+ device_token: 'abc',
55
+ risk_policy: {
56
+ id: '123',
57
+ revision_id: 'abc',
58
+ name: 'def',
59
+ type: 'bot'
60
+ }
61
+ }
62
+ end
63
+
64
+ it { expect(call).to eql(result) }
65
+ end
66
+ end
67
+
13
68
  context 'when response empty' do
14
69
  let(:response) { OpenStruct.new(body: '', code: 200) }
15
70
 
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Castle::Core::ProcessWebhook do
4
+ describe '#call' do
5
+ subject(:call) { described_class.call(webhook) }
6
+
7
+ let(:webhook_body) do
8
+ {
9
+ api_version: 'v1',
10
+ app_id: '12345',
11
+ type: '$incident.confirmed',
12
+ created_at: '2020-12-18T12:55:21.779Z',
13
+ data: {
14
+ id: 'test',
15
+ device_token: 'token',
16
+ user_id: '',
17
+ trigger: '$login.succeeded',
18
+ context: {},
19
+ location: {},
20
+ user_agent: {}
21
+ },
22
+ user_traits: {},
23
+ properties: {},
24
+ policy: {}
25
+ }.to_json
26
+ end
27
+
28
+ let(:webhook) { OpenStruct.new(body: StringIO.new(webhook_body)) }
29
+
30
+ context 'when success' do
31
+ it { expect(call).to eql(webhook_body) }
32
+ end
33
+
34
+ context 'when webhook empty' do
35
+ let(:webhook) { OpenStruct.new(body: StringIO.new('')) }
36
+
37
+ it { expect { call }.to raise_error(Castle::ApiError, 'Invalid webhook from Castle API') }
38
+ end
39
+
40
+ context 'when webhook nil' do
41
+ let(:webhook) { OpenStruct.new(body: StringIO.new) }
42
+
43
+ it { expect { call }.to raise_error(Castle::ApiError, 'Invalid webhook from Castle API') }
44
+ end
45
+ end
46
+ end
@@ -1,52 +1,56 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::API::Request do
3
+ describe Castle::Core::SendRequest do
4
+ let(:config) { Castle.config }
5
+
4
6
  describe '#call' do
5
- let(:command) { Castle::Commands::Track.new({}).build(event: '$login.succeeded') }
7
+ let(:command) { Castle::Commands::Track.build(event: '$login.succeeded') }
6
8
  let(:headers) { {} }
7
- let(:api_secret) { 'secret' }
8
9
  let(:request_build) { {} }
9
10
  let(:expected_headers) { { 'Content-Type' => 'application/json' } }
10
11
  let(:http) { instance_double('Net::HTTP') }
11
12
 
12
13
  context 'without http arg provided' do
13
- subject(:call) { described_class.call(command, api_secret, headers) }
14
+ subject(:call) { described_class.call(command, headers, nil, config) }
14
15
 
15
16
  let(:http) { instance_double('Net::HTTP') }
16
- let(:command) { Castle::Commands::Track.new({}).build(event: '$login.succeeded') }
17
+ let(:command) { Castle::Commands::Track.build(event: '$login.succeeded') }
17
18
  let(:headers) { {} }
18
- let(:api_secret) { 'secret' }
19
19
  let(:request_build) { {} }
20
20
  let(:expected_headers) { { 'Content-Type' => 'application/json' } }
21
21
 
22
22
  before do
23
- allow(Castle::API::Connection).to receive(:call).and_return(http)
23
+ allow(Castle::Core::GetConnection).to receive(:call).and_return(http)
24
24
  allow(http).to receive(:request)
25
25
  allow(described_class).to receive(:build).and_return(request_build)
26
26
  call
27
27
  end
28
28
 
29
29
  it do
30
- expect(described_class).to have_received(:build).with(command, expected_headers, api_secret)
30
+ expect(described_class).to have_received(:build).with(
31
+ command, expected_headers, config
32
+ )
31
33
  end
32
34
 
33
35
  it { expect(http).to have_received(:request).with(request_build) }
34
36
  end
35
37
 
36
38
  context 'with http arg provided' do
37
- subject(:call) { described_class.call(command, api_secret, headers, http) }
39
+ subject(:call) { described_class.call(command, headers, http, config) }
38
40
 
39
41
  before do
40
- allow(Castle::API::Connection).to receive(:call)
42
+ allow(Castle::Core::GetConnection).to receive(:call)
41
43
  allow(http).to receive(:request)
42
44
  allow(described_class).to receive(:build).and_return(request_build)
43
45
  call
44
46
  end
45
47
 
46
- it { expect(Castle::API::Connection).not_to have_received(:call) }
48
+ it { expect(Castle::Core::GetConnection).not_to have_received(:call) }
47
49
 
48
50
  it do
49
- expect(described_class).to have_received(:build).with(command, expected_headers, api_secret)
51
+ expect(described_class).to have_received(:build).with(
52
+ command, expected_headers, config
53
+ )
50
54
  end
51
55
 
52
56
  it { expect(http).to have_received(:request).with(request_build) }
@@ -54,13 +58,13 @@ describe Castle::API::Request do
54
58
  end
55
59
 
56
60
  describe '#build' do
57
- subject(:build) { described_class.build(command, headers, api_secret) }
61
+ subject(:build) { described_class.build(command, headers, config) }
58
62
 
59
63
  let(:headers) { { 'SAMPLE-HEADER' => '1' } }
60
64
  let(:api_secret) { 'secret' }
61
65
 
62
66
  context 'when get' do
63
- let(:command) { Castle::Commands::Review.build(review_id) }
67
+ let(:command) { Castle::Commands::Review.build({ review_id: review_id }) }
64
68
  let(:review_id) { SecureRandom.uuid }
65
69
 
66
70
  it { expect(build.body).to be_nil }
@@ -74,7 +78,7 @@ describe Castle::API::Request do
74
78
  context 'when post' do
75
79
  let(:time) { Time.now.utc.iso8601(3) }
76
80
  let(:command) do
77
- Castle::Commands::Track.new({}).build(event: '$login.succeeded', name: "\xC4")
81
+ Castle::Commands::Track.build(event: '$login.succeeded', name: "\xC4")
78
82
  end
79
83
  let(:expected_body) do
80
84
  {
@@ -85,7 +89,7 @@ describe Castle::API::Request do
85
89
  }
86
90
  end
87
91
 
88
- before { allow(Castle::Utils::Timestamp).to receive(:call).and_return(time) }
92
+ before { allow(Castle::Utils::GetTimestamp).to receive(:call).and_return(time) }
89
93
 
90
94
  it { expect(build.body).to be_eql(expected_body.to_json) }
91
95
  it { expect(build.method).to eql('POST') }
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Castle::Failover::Strategy do
4
+ subject(:strategy) { described_class }
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) }
10
+
11
+ it { expect(Castle::Failover::STRATEGIES).to be_eql(%i[allow deny challenge throw]) }
12
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::Extractors::Headers do
4
- subject(:headers) { described_class.new(formatted_headers).call }
3
+ describe Castle::Headers::Extract do
4
+ subject(:extract_call) { described_class.new(formatted_headers).call }
5
5
 
6
6
  let(:formatted_headers) do
7
7
  {
@@ -33,7 +33,7 @@ describe Castle::Extractors::Headers do
33
33
  }
34
34
  end
35
35
 
36
- it { expect(headers).to eq(result) }
36
+ it { expect(extract_call).to eq(result) }
37
37
  end
38
38
 
39
39
  context 'when allowlist is set in the configuration' do
@@ -51,7 +51,7 @@ describe Castle::Extractors::Headers do
51
51
  }
52
52
  end
53
53
 
54
- it { expect(headers).to eq(result) }
54
+ it { expect(extract_call).to eq(result) }
55
55
  end
56
56
 
57
57
  context 'when denylist is set in the configuration' do
@@ -70,7 +70,7 @@ describe Castle::Extractors::Headers do
70
70
 
71
71
  before { Castle.config.denylisted = %w[User-Agent] }
72
72
 
73
- it { expect(headers).to eq(result) }
73
+ it { expect(extract_call).to eq(result) }
74
74
  end
75
75
 
76
76
  context 'with a different header' do
@@ -88,7 +88,7 @@ describe Castle::Extractors::Headers do
88
88
 
89
89
  before { Castle.config.denylisted = %w[Accept] }
90
90
 
91
- it { expect(headers).to eq(result) }
91
+ it { expect(extract_call).to eq(result) }
92
92
  end
93
93
  end
94
94
 
@@ -99,7 +99,7 @@ describe Castle::Extractors::Headers do
99
99
  end
100
100
 
101
101
  it do
102
- expect(headers['Accept']).to eq(true)
102
+ expect(extract_call['Accept']).to eq(true)
103
103
  end
104
104
  end
105
105
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::HeadersFilter do
4
- subject(:headers) { described_class.new(request).call }
3
+ describe Castle::Headers::Filter do
4
+ subject(:filter_call) { described_class.new(request).call }
5
5
 
6
6
  let(:env) do
7
7
  result = Rack::MockRequest.env_for(
@@ -33,6 +33,6 @@ describe Castle::HeadersFilter do
33
33
  let(:request) { Rack::Request.new(env) }
34
34
 
35
35
  context 'with list of header' do
36
- it { expect(headers).to eq(filtered) }
36
+ it { expect(filter_call).to eq(filtered) }
37
37
  end
38
38
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Castle::Headers::Format do
4
+ subject(:format) { described_class }
5
+
6
+ it 'removes HTTP_' do
7
+ expect(format.call('HTTP_X_TEST')).to be_eql('X-Test')
8
+ end
9
+
10
+ it 'capitalizes header' do
11
+ expect(format.call('X_TEST')).to be_eql('X-Test')
12
+ end
13
+
14
+ it 'ignores letter case and -_ divider' do
15
+ expect(format.call('http-X_teST')).to be_eql('X-Test')
16
+ end
17
+
18
+ it 'does not remove http if there is no _- char' do
19
+ expect(format.call('httpX_teST')).to be_eql('Httpx-Test')
20
+ end
21
+
22
+ it 'capitalizes' do
23
+ expect(format.call(:clearance)).to be_eql('Clearance')
24
+ end
25
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- describe Castle::Extractors::IP do
3
+ describe Castle::IP::Extract do
4
4
  subject(:extractor) { described_class.new(headers) }
5
5
 
6
6
  describe 'ip' do
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # tmp logger for testing
4
+ class TmpLogger
5
+ # @param _message [String]
6
+ def info(_message); end
7
+ end
8
+
9
+ describe Castle::Logger do
10
+ subject(:log) do
11
+ described_class.call(message, data)
12
+ end
13
+
14
+ let(:message) { 'https://localhost/test:' }
15
+ let(:integration_logger) { TmpLogger.new }
16
+ let(:data) { { a: 1 }.to_json }
17
+ let(:logger_message) { "[CASTLE] #{message} #{data}" }
18
+
19
+ before do
20
+ allow(integration_logger).to receive(:info).and_call_original
21
+ end
22
+
23
+ describe '.call' do
24
+ context 'without logger' do
25
+ before do
26
+ Castle.config.logger = nil
27
+ log
28
+ end
29
+
30
+ it { expect(integration_logger).not_to have_received(:info) }
31
+ end
32
+
33
+ context 'with logger' do
34
+ before do
35
+ Castle.config.logger = integration_logger
36
+ log
37
+ end
38
+
39
+ it { expect(integration_logger).to have_received(:info).with(logger_message) }
40
+ end
41
+ end
42
+ end