castle-rb 8.1.0 → 9.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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +317 -0
  3. data/LICENSE +21 -0
  4. data/README.md +290 -112
  5. data/lib/castle/api/filter.rb +3 -1
  6. data/lib/castle/api/list_items/create_batch.rb +22 -0
  7. data/lib/castle/api/lists/create.rb +1 -1
  8. data/lib/castle/api/log.rb +2 -1
  9. data/lib/castle/api/privacy/delete_data.rb +23 -0
  10. data/lib/castle/api/privacy/request_data.rb +23 -0
  11. data/lib/castle/api/risk.rb +2 -1
  12. data/lib/castle/client.rb +12 -52
  13. data/lib/castle/client_actions/list_items.rb +7 -2
  14. data/lib/castle/client_actions/privacy.rb +20 -0
  15. data/lib/castle/commands/list_items/create_batch.rb +22 -0
  16. data/lib/castle/commands/privacy/delete_data.rb +20 -0
  17. data/lib/castle/commands/privacy/request_data.rb +20 -0
  18. data/lib/castle/core/get_connection.rb +5 -1
  19. data/lib/castle/core/process_response.rb +1 -0
  20. data/lib/castle/core/process_webhook.rb +1 -1
  21. data/lib/castle/core/send_request.rb +2 -1
  22. data/lib/castle/errors.rb +1 -5
  23. data/lib/castle/headers/filter.rb +1 -1
  24. data/lib/castle/version.rb +1 -1
  25. data/lib/castle.rb +8 -17
  26. metadata +34 -218
  27. data/lib/castle/api/approve_device.rb +0 -20
  28. data/lib/castle/api/authenticate.rb +0 -28
  29. data/lib/castle/api/end_impersonation.rb +0 -22
  30. data/lib/castle/api/get_device.rb +0 -20
  31. data/lib/castle/api/get_devices_for_user.rb +0 -20
  32. data/lib/castle/api/report_device.rb +0 -20
  33. data/lib/castle/api/start_impersonation.rb +0 -22
  34. data/lib/castle/api/track.rb +0 -19
  35. data/lib/castle/commands/approve_device.rb +0 -17
  36. data/lib/castle/commands/authenticate.rb +0 -23
  37. data/lib/castle/commands/end_impersonation.rb +0 -25
  38. data/lib/castle/commands/get_device.rb +0 -17
  39. data/lib/castle/commands/get_devices_for_user.rb +0 -17
  40. data/lib/castle/commands/report_device.rb +0 -17
  41. data/lib/castle/commands/start_impersonation.rb +0 -25
  42. data/lib/castle/commands/track.rb +0 -22
  43. data/lib/castle/support/hanami.rb +0 -15
  44. data/lib/castle/support/padrino.rb +0 -19
  45. data/spec/integration/rails/rails_spec.rb +0 -95
  46. data/spec/integration/rails/support/all.rb +0 -6
  47. data/spec/integration/rails/support/application.rb +0 -17
  48. data/spec/integration/rails/support/home_controller.rb +0 -39
  49. data/spec/lib/castle/api/approve_device_spec.rb +0 -17
  50. data/spec/lib/castle/api/authenticate_spec.rb +0 -133
  51. data/spec/lib/castle/api/end_impersonation_spec.rb +0 -59
  52. data/spec/lib/castle/api/filter_spec.rb +0 -5
  53. data/spec/lib/castle/api/get_device_spec.rb +0 -17
  54. data/spec/lib/castle/api/get_devices_for_user_spec.rb +0 -17
  55. data/spec/lib/castle/api/list_items/archive_spec.rb +0 -18
  56. data/spec/lib/castle/api/list_items/count_spec.rb +0 -21
  57. data/spec/lib/castle/api/list_items/create_spec.rb +0 -22
  58. data/spec/lib/castle/api/list_items/get_spec.rb +0 -18
  59. data/spec/lib/castle/api/list_items/query_spec.rb +0 -21
  60. data/spec/lib/castle/api/list_items/unarchive_spec.rb +0 -18
  61. data/spec/lib/castle/api/list_items/update_spec.rb +0 -22
  62. data/spec/lib/castle/api/lists/create_spec.rb +0 -21
  63. data/spec/lib/castle/api/lists/delete_spec.rb +0 -17
  64. data/spec/lib/castle/api/lists/get_all_spec.rb +0 -17
  65. data/spec/lib/castle/api/lists/get_spec.rb +0 -17
  66. data/spec/lib/castle/api/lists/query_spec.rb +0 -21
  67. data/spec/lib/castle/api/lists/update_spec.rb +0 -21
  68. data/spec/lib/castle/api/log_spec.rb +0 -5
  69. data/spec/lib/castle/api/report_device_spec.rb +0 -17
  70. data/spec/lib/castle/api/risk_spec.rb +0 -5
  71. data/spec/lib/castle/api/start_impersonation_spec.rb +0 -59
  72. data/spec/lib/castle/api/track_spec.rb +0 -65
  73. data/spec/lib/castle/api_spec.rb +0 -36
  74. data/spec/lib/castle/client_id/extract_spec.rb +0 -47
  75. data/spec/lib/castle/client_spec.rb +0 -342
  76. data/spec/lib/castle/command_spec.rb +0 -9
  77. data/spec/lib/castle/commands/approve_device_spec.rb +0 -24
  78. data/spec/lib/castle/commands/authenticate_spec.rb +0 -86
  79. data/spec/lib/castle/commands/end_impersonation_spec.rb +0 -72
  80. data/spec/lib/castle/commands/filter_spec.rb +0 -72
  81. data/spec/lib/castle/commands/get_device_spec.rb +0 -24
  82. data/spec/lib/castle/commands/get_devices_for_user_spec.rb +0 -24
  83. data/spec/lib/castle/commands/list_items/archive_spec.rb +0 -21
  84. data/spec/lib/castle/commands/list_items/count_spec.rb +0 -21
  85. data/spec/lib/castle/commands/list_items/create_spec.rb +0 -22
  86. data/spec/lib/castle/commands/list_items/get_spec.rb +0 -21
  87. data/spec/lib/castle/commands/list_items/query_spec.rb +0 -27
  88. data/spec/lib/castle/commands/list_items/unarchive_spec.rb +0 -21
  89. data/spec/lib/castle/commands/list_items/update_spec.rb +0 -21
  90. data/spec/lib/castle/commands/lists/create_spec.rb +0 -33
  91. data/spec/lib/castle/commands/lists/delete_spec.rb +0 -21
  92. data/spec/lib/castle/commands/lists/get_all_spec.rb +0 -11
  93. data/spec/lib/castle/commands/lists/get_spec.rb +0 -21
  94. data/spec/lib/castle/commands/lists/query_spec.rb +0 -27
  95. data/spec/lib/castle/commands/lists/update_spec.rb +0 -29
  96. data/spec/lib/castle/commands/log_spec.rb +0 -73
  97. data/spec/lib/castle/commands/report_device_spec.rb +0 -24
  98. data/spec/lib/castle/commands/risk_spec.rb +0 -73
  99. data/spec/lib/castle/commands/start_impersonation_spec.rb +0 -72
  100. data/spec/lib/castle/commands/track_spec.rb +0 -89
  101. data/spec/lib/castle/configuration_spec.rb +0 -14
  102. data/spec/lib/castle/context/get_default_spec.rb +0 -41
  103. data/spec/lib/castle/context/merge_spec.rb +0 -23
  104. data/spec/lib/castle/context/prepare_spec.rb +0 -42
  105. data/spec/lib/castle/context/sanitize_spec.rb +0 -27
  106. data/spec/lib/castle/core/get_connection_spec.rb +0 -43
  107. data/spec/lib/castle/core/process_response_spec.rb +0 -103
  108. data/spec/lib/castle/core/process_webhook_spec.rb +0 -52
  109. data/spec/lib/castle/core/send_request_spec.rb +0 -97
  110. data/spec/lib/castle/failover/strategy_spec.rb +0 -12
  111. data/spec/lib/castle/headers/extract_spec.rb +0 -103
  112. data/spec/lib/castle/headers/filter_spec.rb +0 -42
  113. data/spec/lib/castle/headers/format_spec.rb +0 -25
  114. data/spec/lib/castle/ips/extract_spec.rb +0 -91
  115. data/spec/lib/castle/logger_spec.rb +0 -39
  116. data/spec/lib/castle/payload/prepare_spec.rb +0 -52
  117. data/spec/lib/castle/secure_mode_spec.rb +0 -7
  118. data/spec/lib/castle/session_spec.rb +0 -61
  119. data/spec/lib/castle/singleton_configuration_spec.rb +0 -14
  120. data/spec/lib/castle/utils/clean_invalid_chars_spec.rb +0 -69
  121. data/spec/lib/castle/utils/clone_spec.rb +0 -19
  122. data/spec/lib/castle/utils/deep_symbolize_keys_spec.rb +0 -50
  123. data/spec/lib/castle/utils/get_timestamp_spec.rb +0 -16
  124. data/spec/lib/castle/utils/merge_spec.rb +0 -13
  125. data/spec/lib/castle/validators/not_supported_spec.rb +0 -19
  126. data/spec/lib/castle/validators/present_spec.rb +0 -25
  127. data/spec/lib/castle/verdict_spec.rb +0 -9
  128. data/spec/lib/castle/version_spec.rb +0 -5
  129. data/spec/lib/castle/webhooks/verify_spec.rb +0 -59
  130. data/spec/lib/castle_spec.rb +0 -58
  131. data/spec/spec_helper.rb +0 -26
  132. data/spec/support/shared_examples/action_request.rb +0 -167
  133. data/spec/support/shared_examples/configuration.rb +0 -99
  134. data/spec/support/shared_examples/list_items.rb +0 -52
  135. data/spec/support/shared_examples/lists.rb +0 -45
@@ -1,97 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Core::SendRequest do
4
- let(:config) { Castle.config }
5
-
6
- describe '#call' do
7
- let(:command) { Castle::Commands::Track.build(event: '$login.succeeded') }
8
- let(:headers) { {} }
9
- let(:request_build) { {} }
10
- let(:expected_headers) { { 'Content-Type' => 'application/json' } }
11
- let(:http) { instance_double(Net::HTTP) }
12
-
13
- context 'without http arg provided' do
14
- subject(:call) { described_class.call(command, headers, nil, config) }
15
-
16
- let(:http) { instance_double(Net::HTTP) }
17
- let(:command) { Castle::Commands::Track.build(event: '$login.succeeded') }
18
- let(:headers) { {} }
19
- let(:request_build) { {} }
20
- let(:expected_headers) { { 'Content-Type' => 'application/json' } }
21
-
22
- before do
23
- allow(Castle::Core::GetConnection).to receive(:call).and_return(http)
24
- allow(http).to receive(:request)
25
- allow(described_class).to receive(:build).and_return(request_build)
26
- call
27
- end
28
-
29
- it { expect(described_class).to have_received(:build).with(command, expected_headers, config) }
30
-
31
- it { expect(http).to have_received(:request).with(request_build) }
32
- end
33
-
34
- context 'with http arg provided' do
35
- subject(:call) { described_class.call(command, headers, http, config) }
36
-
37
- before do
38
- allow(Castle::Core::GetConnection).to receive(:call)
39
- allow(http).to receive(:request)
40
- allow(described_class).to receive(:build).and_return(request_build)
41
- call
42
- end
43
-
44
- it { expect(Castle::Core::GetConnection).not_to have_received(:call) }
45
-
46
- it { expect(described_class).to have_received(:build).with(command, expected_headers, config) }
47
-
48
- it { expect(http).to have_received(:request).with(request_build) }
49
- end
50
- end
51
-
52
- describe '#build' do
53
- subject(:build) { described_class.build(command, headers, config) }
54
-
55
- let(:headers) { { 'SAMPLE-HEADER' => '1' } }
56
- let(:api_secret) { 'secret' }
57
-
58
- context 'when post' do
59
- let(:time) { Time.now.utc.iso8601(3) }
60
- let(:command) { Castle::Commands::Track.build(event: '$login.succeeded', name: "\xC4") }
61
- let(:expected_body) { { event: '$login.succeeded', name: '�', context: {}, sent_at: time } }
62
-
63
- before { allow(Castle::Utils::GetTimestamp).to receive(:call).and_return(time) }
64
-
65
- it { expect(build.body).to eql(expected_body.to_json) }
66
- it { expect(build.method).to eql('POST') }
67
- it { expect(build.path).to eql("/v1/#{command.path}") }
68
- it { expect(build.to_hash).to have_key('authorization') }
69
- it { expect(build.to_hash).to have_key('sample-header') }
70
- it { expect(build.to_hash['sample-header']).to eql(['1']) }
71
- end
72
-
73
- context 'when get' do
74
- let(:time) { Time.now.utc.iso8601(3) }
75
- let(:command) { Castle::Commands::GetDevice.build(device_token: '1') }
76
- let(:expected_body) { {} }
77
-
78
- before { allow(Castle::Utils::GetTimestamp).to receive(:call).and_return(time) }
79
-
80
- it { expect(build.body).to eql(expected_body.to_json) }
81
- it { expect(build.method).to eql('GET') }
82
- it { expect(build.path).to eql("/v1/#{command.path}") }
83
- end
84
-
85
- context 'when put' do
86
- let(:time) { Time.now.utc.iso8601(3) }
87
- let(:command) { Castle::Commands::ApproveDevice.build(device_token: '1') }
88
- let(:expected_body) { {} }
89
-
90
- before { allow(Castle::Utils::GetTimestamp).to receive(:call).and_return(time) }
91
-
92
- it { expect(build.body).to eql(expected_body.to_json) }
93
- it { expect(build.method).to eql('PUT') }
94
- it { expect(build.path).to eql("/v1/#{command.path}") }
95
- end
96
- end
97
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Failover::Strategy do
4
- subject(:strategy) { described_class }
5
-
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
-
11
- it { expect(Castle::Failover::STRATEGIES).to eql(%i[allow deny challenge throw]) }
12
- end
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Headers::Extract do
4
- subject(:extract_call) { described_class.new(formatted_headers).call }
5
-
6
- let(:formatted_headers) do
7
- {
8
- 'Content-Length' => '0',
9
- 'Authorization' => 'Basic 123456',
10
- 'Cookie' => '__cid=abcd;other=efgh',
11
- 'Ok' => 'OK',
12
- 'Accept' => 'application/json',
13
- 'X-Forwarded-For' => '1.2.3.4',
14
- 'User-Agent' => 'Mozilla 1234'
15
- }
16
- end
17
-
18
- after do
19
- Castle.config.allowlisted = %w[]
20
- Castle.config.denylisted = %w[]
21
- end
22
-
23
- context 'when allowlist is not set in the configuration' do
24
- let(:result) do
25
- {
26
- 'Accept' => 'application/json',
27
- 'Authorization' => true,
28
- 'Cookie' => true,
29
- 'Content-Length' => '0',
30
- 'Ok' => 'OK',
31
- 'User-Agent' => 'Mozilla 1234',
32
- 'X-Forwarded-For' => '1.2.3.4'
33
- }
34
- end
35
-
36
- it { expect(extract_call).to eq(result) }
37
- end
38
-
39
- context 'when allowlist is set in the configuration' do
40
- before { Castle.config.allowlisted = %w[Accept OK] }
41
-
42
- let(:result) do
43
- {
44
- 'Accept' => 'application/json',
45
- 'Authorization' => true,
46
- 'Cookie' => true,
47
- 'Content-Length' => true,
48
- 'Ok' => 'OK',
49
- 'User-Agent' => 'Mozilla 1234',
50
- 'X-Forwarded-For' => true
51
- }
52
- end
53
-
54
- it { expect(extract_call).to eq(result) }
55
- end
56
-
57
- context 'when denylist is set in the configuration' do
58
- context 'with a User-Agent' do
59
- let(:result) do
60
- {
61
- 'Accept' => 'application/json',
62
- 'Authorization' => true,
63
- 'Cookie' => true,
64
- 'Content-Length' => '0',
65
- 'Ok' => 'OK',
66
- 'User-Agent' => 'Mozilla 1234',
67
- 'X-Forwarded-For' => '1.2.3.4'
68
- }
69
- end
70
-
71
- before { Castle.config.denylisted = %w[User-Agent] }
72
-
73
- it { expect(extract_call).to eq(result) }
74
- end
75
-
76
- context 'with a different header' do
77
- let(:result) do
78
- {
79
- 'Accept' => true,
80
- 'Authorization' => true,
81
- 'Cookie' => true,
82
- 'Content-Length' => '0',
83
- 'Ok' => 'OK',
84
- 'User-Agent' => 'Mozilla 1234',
85
- 'X-Forwarded-For' => '1.2.3.4'
86
- }
87
- end
88
-
89
- before { Castle.config.denylisted = %w[Accept] }
90
-
91
- it { expect(extract_call).to eq(result) }
92
- end
93
- end
94
-
95
- context 'when a header is both allowlisted and denylisted' do
96
- before do
97
- Castle.config.allowlisted = %w[Accept]
98
- Castle.config.denylisted = %w[Accept]
99
- end
100
-
101
- it { expect(extract_call['Accept']).to be(true) }
102
- end
103
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Headers::Filter do
4
- subject(:filter_call) { described_class.new(request).call }
5
-
6
- let(:env) do
7
- result =
8
- Rack::MockRequest.env_for(
9
- '/',
10
- 'Action-Dispatch.request.content-Type' => 'application/json',
11
- 'HTTP_AUTHORIZATION' => 'Basic 123456',
12
- 'HTTP_COOKIE' => '__cid=abcd;other=efgh',
13
- 'HTTP_ACCEPT' => 'application/json',
14
- 'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
15
- 'HTTP_USER_AGENT' => 'Mozilla 1234',
16
- 'TEST' => '1',
17
- 'REMOTE_ADDR' => '1.2.3.4',
18
- 'HTTP_CONTENT_LENGTH' => '0',
19
- 'http_accept_language.parser' => -> { 'noop' }
20
- )
21
- result[:HTTP_OK] = 'OK'
22
- result
23
- end
24
- let(:filtered) do
25
- {
26
- 'Accept' => 'application/json',
27
- 'Authorization' => 'Basic 123456',
28
- 'Cookie' => '__cid=abcd;other=efgh',
29
- 'Content-Length' => '0',
30
- 'Ok' => 'OK',
31
- 'User-Agent' => 'Mozilla 1234',
32
- 'Remote-Addr' => '1.2.3.4',
33
- 'X-Forwarded-For' => '1.2.3.4',
34
- 'Accept-Language.parser' => start_with('#<Proc')
35
- }
36
- end
37
- let(:request) { Rack::Request.new(env) }
38
-
39
- context 'with list of header' do
40
- it { expect(filter_call).to match(filtered) }
41
- end
42
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Headers::Format do
4
- subject(:format) { described_class }
5
-
6
- it 'removes HTTP_' do
7
- expect(format.call('HTTP_X_TEST')).to eql('X-Test')
8
- end
9
-
10
- it 'capitalizes header' do
11
- expect(format.call('X_TEST')).to eql('X-Test')
12
- end
13
-
14
- it 'ignores letter case and -_ divider' do
15
- expect(format.call('http-X_teST')).to 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 eql('Httpx-Test')
20
- end
21
-
22
- it 'capitalizes' do
23
- expect(format.call(:clearance)).to eql('Clearance')
24
- end
25
- end
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::IPs::Extract do
4
- subject(:extractor) { described_class.new(headers) }
5
-
6
- describe 'ip' do
7
- after do
8
- Castle.config.ip_headers = []
9
- Castle.config.trusted_proxies = []
10
- end
11
-
12
- context 'when regular ip' do
13
- let(:headers) { { 'X-Forwarded-For' => '1.2.3.5' } }
14
-
15
- it { expect(extractor.call).to eql('1.2.3.5') }
16
- end
17
-
18
- context 'when we need to use other ip header' do
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' } }
20
-
21
- context 'with uppercase format' do
22
- before { Castle.config.ip_headers = %w[CF_CONNECTING_IP X-Forwarded-For] }
23
-
24
- it { expect(extractor.call).to eql('1.2.3.4') }
25
- end
26
-
27
- context 'with regular format' do
28
- before { Castle.config.ip_headers = %w[Cf-Connecting-Ip X-Forwarded-For] }
29
-
30
- it { expect(extractor.call).to eql('1.2.3.4') }
31
- end
32
-
33
- context 'with value from trusted proxies it get seconds header' do
34
- before do
35
- Castle.config.ip_headers = %w[Cf-Connecting-Ip X-Forwarded-For]
36
- Castle.config.trusted_proxies = %w[1.2.3.4]
37
- end
38
-
39
- it { expect(extractor.call).to eql('1.2.3.5') }
40
- end
41
- end
42
-
43
- context 'with all the trusted proxies' do
44
- let(:http_x_header) { '127.0.0.1,10.0.0.1,172.31.0.1,192.168.0.1' }
45
-
46
- let(:headers) { { 'Remote-Addr' => '127.0.0.1', 'X-Forwarded-For' => http_x_header } }
47
-
48
- it 'fallbacks to first available header when all headers are marked trusted proxy' do
49
- expect(extractor.call).to eql('127.0.0.1')
50
- end
51
- end
52
-
53
- context 'with trust_proxy_chain option' do
54
- let(:http_x_header) { '6.6.6.6, 2.2.2.3, 6.6.6.5' }
55
-
56
- let(:headers) { { 'Remote-Addr' => '6.6.6.4', 'X-Forwarded-For' => http_x_header } }
57
-
58
- before { Castle.config.trust_proxy_chain = true }
59
-
60
- it 'selects first available header' do
61
- expect(extractor.call).to eql('6.6.6.6')
62
- end
63
- end
64
-
65
- context 'with trusted_proxy_depth option' do
66
- let(:http_x_header) { '6.6.6.6, 2.2.2.3, 6.6.6.5' }
67
-
68
- let(:headers) { { 'Remote-Addr' => '6.6.6.4', 'X-Forwarded-For' => http_x_header } }
69
-
70
- before { Castle.config.trusted_proxy_depth = 1 }
71
-
72
- it 'selects first available header' do
73
- expect(extractor.call).to eql('2.2.2.3')
74
- end
75
- end
76
-
77
- context 'when list of not trusted ips provided in X_FORWARDED_FOR' do
78
- let(:headers) { { 'X-Forwarded-For' => '6.6.6.6, 2.2.2.3, 192.168.0.7', 'Client-Ip' => '6.6.6.6' } }
79
-
80
- it 'does not allow to spoof ip' do
81
- expect(extractor.call).to eql('2.2.2.3')
82
- end
83
-
84
- context 'when marked 2.2.2.3 as trusted proxy' do
85
- before { Castle.config.trusted_proxies = [/^2.2.2.\d$/] }
86
-
87
- it { expect(extractor.call).to eql('6.6.6.6') }
88
- end
89
- end
90
- end
91
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # tmp logger for testing
4
- class TmpLogger
5
- # @param _message [String]
6
- def info(_message)
7
- end
8
- end
9
-
10
- RSpec.describe Castle::Logger do
11
- subject(:log) { described_class.call(message, data) }
12
-
13
- let(:message) { 'https://localhost/test:' }
14
- let(:integration_logger) { TmpLogger.new }
15
- let(:data) { { a: 1 }.to_json }
16
- let(:logger_message) { "[CASTLE] #{message} #{data}" }
17
-
18
- before { allow(integration_logger).to receive(:info).and_call_original }
19
-
20
- describe '.call' do
21
- context 'without logger' do
22
- before do
23
- Castle.config.logger = nil
24
- log
25
- end
26
-
27
- it { expect(integration_logger).not_to have_received(:info) }
28
- end
29
-
30
- context 'with logger' do
31
- before do
32
- Castle.config.logger = integration_logger
33
- log
34
- end
35
-
36
- it { expect(integration_logger).to have_received(:info).with(logger_message) }
37
- end
38
- end
39
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Payload::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
- 'HTTP_CONTENT_LENGTH' => '0'
14
- )
15
- end
16
- let(:request) { Rack::Request.new(env) }
17
-
18
- let(:headers) { { 'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, Cookie: true } }
19
- let(:context) do
20
- {
21
- client_id: 'abcd',
22
- active: true,
23
- user_agent: ua,
24
- headers: headers,
25
- ip: ip,
26
- library: {
27
- name: 'castle-rb',
28
- version: '2.2.0'
29
- }
30
- }
31
- end
32
-
33
- let(:time_now) { Time.now }
34
- let(:time_formatted) { time_now.utc.iso8601(3) }
35
- let(:payload_options) { { user_id: '1234', user_traits: { name: 'Jo' } } }
36
- let(:result) { { user_id: '1234', user_traits: { name: 'Jo' }, timestamp: time_formatted, context: context } }
37
-
38
- before do
39
- Timecop.freeze(time_now)
40
- stub_const('Castle::VERSION', '2.2.0')
41
- end
42
-
43
- after { Timecop.return }
44
-
45
- describe '#call' do
46
- subject(:generated) { described_class.call(payload_options, request) }
47
-
48
- context 'when active true' do
49
- it { is_expected.to eql(result) }
50
- end
51
- end
52
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::SecureMode do
4
- it 'has signature' do
5
- expect(described_class.signature('test')).to eql('0329a06b62cd16b33eb6792be8c60b158d89a2ee3a876fce9a881ebb488c0914')
6
- end
7
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Session do
4
- describe '.call' do
5
- context 'when ssl false' do
6
- let(:localhost) { 'localhost' }
7
- let(:port) { 3002 }
8
-
9
- before do
10
- Castle.config.base_url = 'http://localhost:3002'
11
- stub_request(:get, 'localhost:3002/test').to_return(status: 200, body: '{}', headers: {})
12
- end
13
-
14
- context 'with block' do
15
- let(:api_url) { '/test' }
16
- let(:request) { Net::HTTP::Get.new(api_url) }
17
-
18
- before do
19
- allow(Net::HTTP).to receive(:new).with(localhost, port).and_call_original
20
-
21
- described_class.call { |http| http.request(request) }
22
- end
23
-
24
- it { expect(Net::HTTP).to have_received(:new).with(localhost, port) }
25
-
26
- it { expect(a_request(:get, 'localhost:3002/test')).to have_been_made.once }
27
- end
28
-
29
- context 'without block' do
30
- before { described_class.call }
31
-
32
- it { expect(a_request(:get, 'localhost:3002/test')).not_to have_been_made }
33
- end
34
- end
35
-
36
- context 'when ssl true' do
37
- let(:localhost) { 'localhost' }
38
- let(:port) { 443 }
39
-
40
- before do
41
- Castle.config.base_url = 'https://localhost'
42
- stub_request(:get, 'https://localhost/test').to_return(status: 200, body: '{}', headers: {})
43
- end
44
-
45
- context 'with block' do
46
- let(:api_url) { '/test' }
47
- let(:request) { Net::HTTP::Get.new(api_url) }
48
-
49
- before do
50
- allow(Net::HTTP).to receive(:new).with(localhost, port).and_call_original
51
-
52
- allow(Net::HTTP).to receive(:start)
53
-
54
- described_class.call { |http| http.request(request) }
55
- end
56
-
57
- it { expect(Net::HTTP).to have_received(:new).with(localhost, port) }
58
- end
59
- end
60
- end
61
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::SingletonConfiguration do
4
- subject(:config) { described_class.instance }
5
-
6
- it_behaves_like 'configuration_host'
7
- it_behaves_like 'configuration_request_timeout'
8
- it_behaves_like 'configuration_allowlisted'
9
- it_behaves_like 'configuration_denylisted'
10
- it_behaves_like 'configuration_failover_strategy'
11
- it_behaves_like 'configuration_api_secret'
12
-
13
- it { expect(config.api_secret).to eql('secret') }
14
- end
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Utils::CleanInvalidChars do
4
- describe '::call' do
5
- subject { described_class.call(input) }
6
-
7
- context 'when input is a string' do
8
- let(:input) { '1234' }
9
-
10
- it { is_expected.to eq input }
11
- end
12
-
13
- context 'when input is an array' do
14
- let(:input) { [1, 2, 3, '4'] }
15
-
16
- it { is_expected.to eq input }
17
- end
18
-
19
- context 'when input is a hash' do
20
- let(:input) { { user_id: 1 } }
21
-
22
- it { is_expected.to eq input }
23
- end
24
-
25
- context 'when input is nil' do
26
- let(:input) { nil }
27
-
28
- it { is_expected.to eq input }
29
- end
30
-
31
- context 'when input is a nested hash' do
32
- let(:input) { { user: { id: 1 } } }
33
-
34
- it { is_expected.to eq input }
35
- end
36
-
37
- context 'with invalid UTF-8 characters' do
38
- context 'when input is a hash' do
39
- let(:input) { { user_id: "inv\xC4lid" } }
40
-
41
- it { is_expected.to eq(user_id: 'inv�lid') }
42
- end
43
-
44
- context 'when input is a nested hash' do
45
- let(:input) { { user: { id: "inv\xC4lid" } } }
46
-
47
- it { is_expected.to eq(user: { id: 'inv�lid' }) }
48
- end
49
-
50
- context 'when input is an array of hashes' do
51
- let(:input) { [{ user: "inv\xC4lid" }] * 2 }
52
-
53
- it { is_expected.to eq([{ user: 'inv�lid' }, { user: 'inv�lid' }]) }
54
- end
55
-
56
- context 'when input is an array' do
57
- let(:input) { ["inv\xC4lid"] * 2 }
58
-
59
- it { is_expected.to eq(%w[inv�lid inv�lid]) }
60
- end
61
-
62
- context 'when input is a hash with array in key' do
63
- let(:input) { { items: ["inv\xC4lid"] * 2 } }
64
-
65
- it { is_expected.to eq(items: %w[inv�lid inv�lid]) }
66
- end
67
- end
68
- end
69
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Utils::Clone do
4
- subject(:clone) { described_class }
5
-
6
- describe 'call' do
7
- let(:nested) { { c: '3' } }
8
- let(:first) { { test: { test1: { c: '4' }, test2: nested, a: '1', b: '2' } } }
9
- let(:result) { { test: { test1: { c: '4' }, test2: { c: '3' }, a: '1', b: '2' } } }
10
- let(:cloned) { clone.call(first) }
11
-
12
- before { cloned }
13
-
14
- it do
15
- nested[:test] = 'sample'
16
- expect(cloned).to eql(result)
17
- end
18
- end
19
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Castle::Utils::DeepSymbolizeKeys do
4
- let(:nested_strings) { { 'a' => { 'b' => { 'c' => 3 } } } }
5
- let(:nested_symbols) { { a: { b: { c: 3 } } } }
6
- let(:nested_mixed) { { 'a' => { b: { 'c' => 3 } } } }
7
- let(:string_array_of_hashes) { { 'a' => [{ 'b' => 2 }, { 'c' => 3 }, 4] } }
8
- let(:symbol_array_of_hashes) { { a: [{ b: 2 }, { c: 3 }, 4] } }
9
- let(:mixed_array_of_hashes) { { a: [{ b: 2 }, { 'c' => 3 }, 4] } }
10
-
11
- describe '::call' do
12
- subject { described_class.call(hash) }
13
-
14
- context 'when nested_symbols' do
15
- let(:hash) { nested_symbols }
16
-
17
- it { is_expected.to eq(nested_symbols) }
18
- end
19
-
20
- context 'when nested_strings' do
21
- let(:hash) { nested_strings }
22
-
23
- it { is_expected.to eq(nested_symbols) }
24
- end
25
-
26
- context 'when nested_mixed' do
27
- let(:hash) { nested_mixed }
28
-
29
- it { is_expected.to eq(nested_symbols) }
30
- end
31
-
32
- context 'when string_array_of_hashes' do
33
- let(:hash) { string_array_of_hashes }
34
-
35
- it { is_expected.to eq(symbol_array_of_hashes) }
36
- end
37
-
38
- context 'when symbol_array_of_hashes' do
39
- let(:hash) { symbol_array_of_hashes }
40
-
41
- it { is_expected.to eq(symbol_array_of_hashes) }
42
- end
43
-
44
- context 'when mixed_array_of_hashes' do
45
- let(:hash) { mixed_array_of_hashes }
46
-
47
- it { is_expected.to eq(symbol_array_of_hashes) }
48
- end
49
- end
50
- end