castle-rb 8.0.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 (133) 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/archive.rb +23 -0
  7. data/lib/castle/api/list_items/count.rb +22 -0
  8. data/lib/castle/api/list_items/create.rb +22 -0
  9. data/lib/castle/api/list_items/create_batch.rb +22 -0
  10. data/lib/castle/api/list_items/get.rb +22 -0
  11. data/lib/castle/api/list_items/query.rb +22 -0
  12. data/lib/castle/api/list_items/unarchive.rb +22 -0
  13. data/lib/castle/api/list_items/update.rb +22 -0
  14. data/lib/castle/api/lists/create.rb +23 -0
  15. data/lib/castle/api/lists/delete.rb +22 -0
  16. data/lib/castle/api/lists/get.rb +22 -0
  17. data/lib/castle/api/lists/get_all.rb +22 -0
  18. data/lib/castle/api/lists/query.rb +22 -0
  19. data/lib/castle/api/lists/update.rb +22 -0
  20. data/lib/castle/api/log.rb +2 -1
  21. data/lib/castle/api/privacy/delete_data.rb +23 -0
  22. data/lib/castle/api/privacy/request_data.rb +23 -0
  23. data/lib/castle/api/risk.rb +2 -1
  24. data/lib/castle/client.rb +15 -52
  25. data/lib/castle/client_actions/list_items.rb +49 -0
  26. data/lib/castle/client_actions/lists.rb +39 -0
  27. data/lib/castle/client_actions/privacy.rb +20 -0
  28. data/lib/castle/commands/list_items/archive.rb +24 -0
  29. data/lib/castle/commands/list_items/count.rb +23 -0
  30. data/lib/castle/commands/list_items/create.rb +22 -0
  31. data/lib/castle/commands/list_items/create_batch.rb +22 -0
  32. data/lib/castle/commands/list_items/get.rb +23 -0
  33. data/lib/castle/commands/list_items/query.rb +24 -0
  34. data/lib/castle/commands/list_items/unarchive.rb +23 -0
  35. data/lib/castle/commands/list_items/update.rb +22 -0
  36. data/lib/castle/commands/lists/create.rb +21 -0
  37. data/lib/castle/commands/lists/delete.rb +20 -0
  38. data/lib/castle/commands/lists/get.rb +20 -0
  39. data/lib/castle/commands/lists/get_all.rb +17 -0
  40. data/lib/castle/commands/lists/query.rb +21 -0
  41. data/lib/castle/commands/lists/update.rb +22 -0
  42. data/lib/castle/commands/privacy/delete_data.rb +20 -0
  43. data/lib/castle/commands/privacy/request_data.rb +20 -0
  44. data/lib/castle/core/get_connection.rb +5 -1
  45. data/lib/castle/core/process_response.rb +1 -0
  46. data/lib/castle/core/process_webhook.rb +1 -1
  47. data/lib/castle/core/send_request.rb +2 -1
  48. data/lib/castle/errors.rb +1 -5
  49. data/lib/castle/headers/filter.rb +1 -1
  50. data/lib/castle/version.rb +1 -1
  51. data/lib/castle.rb +36 -17
  52. metadata +62 -162
  53. data/lib/castle/api/approve_device.rb +0 -20
  54. data/lib/castle/api/authenticate.rb +0 -28
  55. data/lib/castle/api/end_impersonation.rb +0 -22
  56. data/lib/castle/api/get_device.rb +0 -20
  57. data/lib/castle/api/get_devices_for_user.rb +0 -20
  58. data/lib/castle/api/report_device.rb +0 -20
  59. data/lib/castle/api/start_impersonation.rb +0 -22
  60. data/lib/castle/api/track.rb +0 -19
  61. data/lib/castle/commands/approve_device.rb +0 -17
  62. data/lib/castle/commands/authenticate.rb +0 -23
  63. data/lib/castle/commands/end_impersonation.rb +0 -25
  64. data/lib/castle/commands/get_device.rb +0 -17
  65. data/lib/castle/commands/get_devices_for_user.rb +0 -17
  66. data/lib/castle/commands/report_device.rb +0 -17
  67. data/lib/castle/commands/start_impersonation.rb +0 -25
  68. data/lib/castle/commands/track.rb +0 -22
  69. data/lib/castle/support/hanami.rb +0 -15
  70. data/lib/castle/support/padrino.rb +0 -19
  71. data/spec/integration/rails/rails_spec.rb +0 -95
  72. data/spec/integration/rails/support/all.rb +0 -6
  73. data/spec/integration/rails/support/application.rb +0 -17
  74. data/spec/integration/rails/support/home_controller.rb +0 -39
  75. data/spec/lib/castle/api/approve_device_spec.rb +0 -17
  76. data/spec/lib/castle/api/authenticate_spec.rb +0 -133
  77. data/spec/lib/castle/api/end_impersonation_spec.rb +0 -59
  78. data/spec/lib/castle/api/filter_spec.rb +0 -5
  79. data/spec/lib/castle/api/get_device_spec.rb +0 -17
  80. data/spec/lib/castle/api/get_devices_for_user_spec.rb +0 -17
  81. data/spec/lib/castle/api/log_spec.rb +0 -5
  82. data/spec/lib/castle/api/report_device_spec.rb +0 -17
  83. data/spec/lib/castle/api/risk_spec.rb +0 -5
  84. data/spec/lib/castle/api/start_impersonation_spec.rb +0 -59
  85. data/spec/lib/castle/api/track_spec.rb +0 -65
  86. data/spec/lib/castle/api_spec.rb +0 -36
  87. data/spec/lib/castle/client_id/extract_spec.rb +0 -47
  88. data/spec/lib/castle/client_spec.rb +0 -337
  89. data/spec/lib/castle/command_spec.rb +0 -9
  90. data/spec/lib/castle/commands/approve_device_spec.rb +0 -24
  91. data/spec/lib/castle/commands/authenticate_spec.rb +0 -86
  92. data/spec/lib/castle/commands/end_impersonation_spec.rb +0 -72
  93. data/spec/lib/castle/commands/filter_spec.rb +0 -72
  94. data/spec/lib/castle/commands/get_device_spec.rb +0 -24
  95. data/spec/lib/castle/commands/get_devices_for_user_spec.rb +0 -24
  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 -24
  132. data/spec/support/shared_examples/action_request.rb +0 -167
  133. data/spec/support/shared_examples/configuration.rb +0 -99
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API::GetDevice do
4
- before do
5
- stub_request(:any, /api.castle.io/).with(basic_auth: ['', 'secret']).to_return(status: 200, body: '{}', headers: {})
6
- end
7
-
8
- describe '.call' do
9
- subject(:retrieve) { described_class.call(device_token: device_token) }
10
-
11
- let(:device_token) { '1234' }
12
-
13
- before { retrieve }
14
-
15
- it { assert_requested :get, "https://api.castle.io/v1/devices/#{device_token}", times: 1 }
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API::GetDevicesForUser do
4
- before do
5
- stub_request(:any, /api.castle.io/).with(basic_auth: ['', 'secret']).to_return(status: 200, body: '{}', headers: {})
6
- end
7
-
8
- describe '.call' do
9
- subject(:retrieve) { described_class.call(user_id: user_id) }
10
-
11
- let(:user_id) { '1234' }
12
-
13
- before { retrieve }
14
-
15
- it { assert_requested :get, "https://api.castle.io/v1/users/#{user_id}/devices", times: 1 }
16
- end
17
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API::Log do
4
- pending
5
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API::ReportDevice do
4
- before do
5
- stub_request(:any, /api.castle.io/).with(basic_auth: ['', 'secret']).to_return(status: 200, body: '{}', headers: {})
6
- end
7
-
8
- describe '.call' do
9
- subject(:retrieve) { described_class.call(device_token: device_token) }
10
-
11
- let(:device_token) { '1234' }
12
-
13
- before { retrieve }
14
-
15
- it { assert_requested :put, "https://api.castle.io/v1/devices/#{device_token}/report", times: 1 }
16
- end
17
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API::Risk do
4
- pending
5
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API::StartImpersonation do
4
- subject(:call) { described_class.call(options) }
5
-
6
- let(:ip) { '1.2.3.4' }
7
- let(:cookie_id) { 'abcd' }
8
- let(:ua) { 'Chrome' }
9
- let(:env) do
10
- Rack::MockRequest.env_for(
11
- '/',
12
- 'HTTP_USER_AGENT' => ua,
13
- 'HTTP_X_FORWARDED_FOR' => ip,
14
- 'HTTP_COOKIE' => "__cid=#{cookie_id};other=efgh"
15
- )
16
- end
17
- let(:request) { Rack::Request.new(env) }
18
- let(:context) { Castle::Context::Prepare.call(request) }
19
- let(:time_now) { Time.now }
20
- let(:time_auto) { time_now.utc.iso8601(3) }
21
-
22
- before do
23
- Timecop.freeze(time_now)
24
- stub_const('Castle::VERSION', '2.2.0')
25
- stub_request(:any, /api.castle.io/).with(basic_auth: ['', 'secret']).to_return(
26
- status: 200,
27
- body: response_body,
28
- headers: {
29
- }
30
- )
31
- end
32
-
33
- after { Timecop.return }
34
-
35
- describe 'call' do
36
- let(:impersonator) { 'test@castle.io' }
37
- let(:request_body) do
38
- { user_id: '1234', sent_at: time_auto, properties: { impersonator: impersonator }, context: context }
39
- end
40
- let(:response_body) { { success: true }.to_json }
41
- let(:options) { { user_id: '1234', properties: { impersonator: impersonator }, context: context } }
42
-
43
- context 'when used with symbol keys' do
44
- before { call }
45
-
46
- it do
47
- assert_requested :post, 'https://api.castle.io/v1/impersonate', times: 1 do |req|
48
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
49
- end
50
- end
51
- end
52
-
53
- context 'when request is not successful' do
54
- let(:response_body) { {}.to_json }
55
-
56
- it { expect { call }.to raise_error(Castle::ImpersonationFailed) }
57
- end
58
- end
59
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API::Track do
4
- subject(:call) { described_class.call(options) }
5
-
6
- let(:ip) { '1.2.3.4' }
7
- let(:cookie_id) { 'abcd' }
8
- let(:ua) { 'Chrome' }
9
- let(:env) do
10
- Rack::MockRequest.env_for(
11
- '/',
12
- 'HTTP_USER_AGENT' => ua,
13
- 'HTTP_X_FORWARDED_FOR' => ip,
14
- 'HTTP_COOKIE' => "__cid=#{cookie_id};other=efgh"
15
- )
16
- end
17
- let(:request) { Rack::Request.new(env) }
18
- let(:context) { Castle::Context::Prepare.call(request) }
19
- let(:time_now) { Time.now }
20
- let(:time_auto) { time_now.utc.iso8601(3) }
21
- let(:time_user) { (Time.now - 10_000).utc.iso8601(3) }
22
- let(:response_body) { {}.to_json }
23
-
24
- before do
25
- Timecop.freeze(time_now)
26
- stub_const('Castle::VERSION', '2.2.0')
27
- stub_request(:any, /api.castle.io/).with(basic_auth: ['', 'secret']).to_return(
28
- status: 200,
29
- body: response_body,
30
- headers: {
31
- }
32
- )
33
- end
34
-
35
- after { Timecop.return }
36
-
37
- describe 'track' do
38
- let(:request_body) { { event: '$login.succeeded', context: context, user_id: '1234', sent_at: time_auto } }
39
-
40
- before { call }
41
-
42
- context 'when used with symbol keys' do
43
- let(:options) { { event: '$login.succeeded', user_id: '1234', context: context } }
44
-
45
- it do
46
- assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
47
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
48
- end
49
- end
50
-
51
- context 'when passed timestamp in options and no defined timestamp' do
52
- let(:options) { { event: '$login.succeeded', user_id: '1234', timestamp: time_user, context: context } }
53
- let(:request_body) do
54
- { event: '$login.succeeded', user_id: '1234', context: context, timestamp: time_user, sent_at: time_auto }
55
- end
56
-
57
- it do
58
- assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
59
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
60
- end
61
- end
62
- end
63
- end
64
- end
65
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::API do
4
- subject(:call) { described_class.call(command) }
5
-
6
- let(:command) { Castle::Commands::Track.build(event: '$login.succeeded') }
7
-
8
- context 'when request timeouts' do
9
- before { stub_request(:any, /api.castle.io/).to_timeout }
10
-
11
- it { expect { call }.to raise_error(Castle::RequestError) }
12
- end
13
-
14
- context 'when non-OK response code' do
15
- before { stub_request(:any, /api.castle.io/).to_return(status: 400) }
16
-
17
- it { expect { call }.to raise_error(Castle::BadRequestError) }
18
- end
19
-
20
- context 'when no api_secret' do
21
- before { allow(Castle.config).to receive(:api_secret).and_return('') }
22
-
23
- it { expect { call }.to raise_error(Castle::ConfigurationError) }
24
- end
25
-
26
- context 'when custom config' do
27
- let(:config) { Castle::Configuration.new }
28
-
29
- before do
30
- config.api_secret = 'test'
31
- stub_request(:any, /api.castle.io/)
32
- end
33
-
34
- it { expect { call }.not_to raise_error }
35
- end
36
- end
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::ClientId::Extract do
4
- subject(:extractor) { described_class.new(formatted_headers, cookies) }
5
-
6
- let(:formatted_headers) { Castle::Headers::Filter.new(request).call }
7
- let(:client_id_cookie) { 'abcd' }
8
- let(:client_id_header) { 'abcde' }
9
- let(:cookies) { request.cookies }
10
- let(:request) { Rack::Request.new(env) }
11
- let(:env) { Rack::MockRequest.env_for('/', headers) }
12
-
13
- context 'with client_id' do
14
- let(:headers) { { 'HTTP_X_FORWARDED_FOR' => '1.2.3.4', 'HTTP_COOKIE' => "__cid=#{client_id_cookie};other=efgh" } }
15
-
16
- it { expect(extractor.call).to eql(client_id_cookie) }
17
- end
18
-
19
- context 'with X-Castle-Client-Id header' do
20
- let(:headers) { { 'HTTP_X_FORWARDED_FOR' => '1.2.3.4', 'HTTP_X_CASTLE_CLIENT_ID' => client_id_header } }
21
-
22
- it 'appends the client_id' do
23
- expect(extractor.call).to eql(client_id_header)
24
- end
25
- end
26
-
27
- context 'when cookies undefined' do
28
- let(:cookies) { nil }
29
- let(:headers) { {} }
30
-
31
- it { expect(extractor.call).to eql('') }
32
- end
33
-
34
- context 'with X-Castle-Client-Id header and cookies client' do
35
- let(:headers) do
36
- {
37
- 'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
38
- 'HTTP_X_CASTLE_CLIENT_ID' => client_id_header,
39
- 'HTTP_COOKIE' => "__cid=#{client_id_cookie};other=efgh"
40
- }
41
- end
42
-
43
- it 'appends the client_id' do
44
- expect(extractor.call).to eql(client_id_header)
45
- end
46
- end
47
- end
@@ -1,337 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::Client 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
- let(:client) { described_class.from_request(request) }
18
- let(:request_to_context) { Castle::Context::Prepare.call(request) }
19
- let(:client_with_user_timestamp) { described_class.new(context: request_to_context, timestamp: time_user) }
20
- let(:client_with_no_timestamp) { described_class.new(context: request_to_context) }
21
-
22
- let(:headers) { { 'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, Cookie: true } }
23
- let(:context) do
24
- {
25
- client_id: 'abcd',
26
- active: true,
27
- user_agent: ua,
28
- headers: headers,
29
- ip: ip,
30
- library: {
31
- name: 'castle-rb',
32
- version: '2.2.0'
33
- }
34
- }
35
- end
36
-
37
- let(:time_now) { Time.now }
38
- let(:time_auto) { time_now.utc.iso8601(3) }
39
- let(:time_user) { (Time.now - 10_000).utc.iso8601(3) }
40
- let(:response_body) { {}.to_json }
41
- let(:response_code) { 200 }
42
-
43
- let(:stub_response) do
44
- stub_request(:any, /api.castle.io/).with(basic_auth: ['', 'secret']).to_return(
45
- status: response_code,
46
- body: response_body,
47
- headers: {
48
- }
49
- )
50
- end
51
-
52
- before do
53
- Timecop.freeze(time_now)
54
- stub_const('Castle::VERSION', '2.2.0')
55
- stub_response
56
- end
57
-
58
- after { Timecop.return }
59
-
60
- describe 'parses the request' do
61
- before { allow(Castle::API).to receive(:send_request).and_call_original }
62
-
63
- it do
64
- client.authenticate(event: '$login.succeeded', user_id: '1234')
65
- expect(Castle::API).to have_received(:send_request)
66
- end
67
- end
68
-
69
- describe 'end impersonation' do
70
- let(:impersonator) { 'test@castle.io' }
71
- let(:request_body) do
72
- {
73
- user_id: '1234',
74
- timestamp: time_auto,
75
- sent_at: time_auto,
76
- properties: {
77
- impersonator: impersonator
78
- },
79
- context: context
80
- }
81
- end
82
- let(:response_body) { { success: true }.to_json }
83
- let(:options) { { user_id: '1234', properties: { impersonator: impersonator } } }
84
-
85
- context 'when used with symbol keys' do
86
- before { client.end_impersonation(options) }
87
-
88
- it do
89
- assert_requested :delete, 'https://api.castle.io/v1/impersonate', times: 1 do |req|
90
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
91
- end
92
- end
93
- end
94
-
95
- context 'when request is not successful' do
96
- let(:response_body) { {}.to_json }
97
-
98
- it { expect { client.end_impersonation(options) }.to raise_error(Castle::ImpersonationFailed) }
99
- end
100
- end
101
-
102
- describe 'start impersonation' do
103
- let(:impersonator) { 'test@castle.io' }
104
- let(:request_body) do
105
- {
106
- user_id: '1234',
107
- timestamp: time_auto,
108
- sent_at: time_auto,
109
- properties: {
110
- impersonator: impersonator
111
- },
112
- context: context
113
- }
114
- end
115
- let(:response_body) { { success: true }.to_json }
116
- let(:options) { { user_id: '1234', properties: { impersonator: impersonator } } }
117
-
118
- context 'when used with symbol keys' do
119
- before { client.start_impersonation(options) }
120
-
121
- it do
122
- assert_requested :post, 'https://api.castle.io/v1/impersonate', times: 1 do |req|
123
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
124
- end
125
- end
126
- end
127
-
128
- context 'when request is not successful' do
129
- let(:response_body) { {}.to_json }
130
-
131
- it { expect { client.start_impersonation(options) }.to raise_error(Castle::ImpersonationFailed) }
132
- end
133
- end
134
-
135
- describe 'authenticate' do
136
- let(:options) { { event: '$login.succeeded', user_id: '1234' } }
137
- let(:request_response) { client.authenticate(options) }
138
- let(:request_body) do
139
- { event: '$login.succeeded', user_id: '1234', context: context, timestamp: time_auto, sent_at: time_auto }
140
- end
141
-
142
- context 'when used with symbol keys' do
143
- before { request_response }
144
-
145
- it do
146
- assert_requested :post, 'https://api.castle.io/v1/authenticate', times: 1 do |req|
147
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
148
- end
149
- end
150
-
151
- context 'when passed timestamp in options and no defined timestamp' do
152
- let(:client) { client_with_no_timestamp }
153
- let(:options) { { event: '$login.succeeded', user_id: '1234', timestamp: time_user } }
154
- let(:request_body) do
155
- { event: '$login.succeeded', user_id: '1234', context: context, timestamp: time_user, sent_at: time_auto }
156
- end
157
-
158
- it do
159
- assert_requested :post, 'https://api.castle.io/v1/authenticate', times: 1 do |req|
160
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
161
- end
162
- end
163
- end
164
-
165
- context 'with client initialized with timestamp' do
166
- let(:client) { client_with_user_timestamp }
167
- let(:request_body) do
168
- { event: '$login.succeeded', user_id: '1234', context: context, timestamp: time_user, sent_at: time_auto }
169
- end
170
-
171
- it do
172
- assert_requested :post, 'https://api.castle.io/v1/authenticate', times: 1 do |req|
173
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
174
- end
175
- end
176
- end
177
- end
178
-
179
- context 'when used with string keys' do
180
- let(:options) { { 'event' => '$login.succeeded', 'user_id' => '1234' } }
181
-
182
- before { request_response }
183
-
184
- it do
185
- assert_requested :post, 'https://api.castle.io/v1/authenticate', times: 1 do |req|
186
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
187
- end
188
- end
189
- end
190
-
191
- context 'when tracking enabled' do
192
- before { request_response }
193
-
194
- it do
195
- assert_requested :post, 'https://api.castle.io/v1/authenticate', times: 1 do |req|
196
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
197
- end
198
- end
199
-
200
- it { expect(request_response[:failover]).to be false }
201
- it { expect(request_response[:failover_reason]).to be_nil }
202
- end
203
-
204
- context 'when tracking disabled' do
205
- before do
206
- client.disable_tracking
207
- request_response
208
- end
209
-
210
- it { assert_not_requested :post, 'https://api.castle.io/v1/authenticate' }
211
- it { expect(request_response[:policy][:action]).to eql(Castle::Verdict::ALLOW) }
212
- it { expect(request_response[:action]).to eql(Castle::Verdict::ALLOW) }
213
- it { expect(request_response[:user_id]).to eql('1234') }
214
- it { expect(request_response[:failover]).to be true }
215
- it { expect(request_response[:failover_reason]).to eql('Castle is set to do not track.') }
216
- end
217
-
218
- context 'when request with fail' do
219
- before { allow(Castle::API).to receive(:send_request).and_raise(Castle::RequestError.new(Timeout::Error)) }
220
-
221
- context 'with request error and throw strategy' do
222
- before { allow(Castle.config).to receive(:failover_strategy).and_return(:throw) }
223
-
224
- it { expect { request_response }.to raise_error(Castle::RequestError) }
225
- end
226
-
227
- context 'with request error and not throw on eg deny strategy' do
228
- it { assert_not_requested :post, 'https://:secret@api.castle.io/v1/authenticate' }
229
- it { expect(request_response[:policy][:action]).to eql('allow') }
230
- it { expect(request_response[:action]).to eql('allow') }
231
- it { expect(request_response[:user_id]).to eql('1234') }
232
- it { expect(request_response[:failover]).to be true }
233
- it { expect(request_response[:failover_reason]).to eql('Castle::RequestError') }
234
- end
235
- end
236
-
237
- context 'when request is internal server error' do
238
- before { allow(Castle::API).to receive(:send_request).and_raise(Castle::InternalServerError) }
239
-
240
- describe 'throw strategy' do
241
- before { allow(Castle.config).to receive(:failover_strategy).and_return(:throw) }
242
-
243
- it { expect { request_response }.to raise_error(Castle::InternalServerError) }
244
- end
245
-
246
- describe 'not throw on eg deny strategy' do
247
- it { assert_not_requested :post, 'https://:secret@api.castle.io/v1/authenticate' }
248
- it { expect(request_response[:policy][:action]).to eql('allow') }
249
- it { expect(request_response[:action]).to eql('allow') }
250
- it { expect(request_response[:user_id]).to eql('1234') }
251
- it { expect(request_response[:failover]).to be true }
252
- it { expect(request_response[:failover_reason]).to eql('Castle::InternalServerError') }
253
- end
254
- end
255
- end
256
-
257
- describe 'track' do
258
- let(:request_body) do
259
- { event: '$login.succeeded', context: context, user_id: '1234', timestamp: time_auto, sent_at: time_auto }
260
- end
261
-
262
- before { client.track(options) }
263
-
264
- context 'when used with symbol keys' do
265
- let(:options) { { event: '$login.succeeded', user_id: '1234' } }
266
-
267
- it do
268
- assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
269
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
270
- end
271
- end
272
-
273
- context 'when passed timestamp in options and no defined timestamp' do
274
- let(:client) { client_with_no_timestamp }
275
- let(:options) { { event: '$login.succeeded', user_id: '1234', timestamp: time_user } }
276
- let(:request_body) do
277
- { event: '$login.succeeded', user_id: '1234', context: context, timestamp: time_user, sent_at: time_auto }
278
- end
279
-
280
- it do
281
- assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
282
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
283
- end
284
- end
285
- end
286
-
287
- context 'with client initialized with timestamp' do
288
- let(:client) { client_with_user_timestamp }
289
- let(:request_body) do
290
- { event: '$login.succeeded', context: context, user_id: '1234', timestamp: time_user, sent_at: time_auto }
291
- end
292
-
293
- it do
294
- assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
295
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
296
- end
297
- end
298
- end
299
- end
300
-
301
- context 'when used with string keys' do
302
- let(:options) { { 'event' => '$login.succeeded', 'user_id' => '1234' } }
303
-
304
- it do
305
- assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
306
- JSON.parse(req.body) == JSON.parse(request_body.to_json)
307
- end
308
- end
309
- end
310
- end
311
-
312
- describe 'tracked?' do
313
- context 'when off' do
314
- before { client.disable_tracking }
315
-
316
- it { expect(client).not_to be_tracked }
317
- end
318
-
319
- context 'when on' do
320
- before { client.enable_tracking }
321
-
322
- it { expect(client).to be_tracked }
323
- end
324
- end
325
-
326
- describe 'filter' do
327
- it_behaves_like 'action request', :filter
328
- end
329
-
330
- describe 'risk' do
331
- it_behaves_like 'action request', :risk
332
- end
333
-
334
- describe 'log' do
335
- it_behaves_like 'action request', :log
336
- end
337
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::Command do
4
- subject(:command) { described_class.new('go', { id: '1' }, :post) }
5
-
6
- it { expect(command.path).to eql('go') }
7
- it { expect(command.data).to eql(id: '1') }
8
- it { expect(command.method).to be(:post) }
9
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::Commands::ApproveDevice do
4
- subject(:instance) { described_class }
5
-
6
- let(:context) { {} }
7
- let(:device_token) { '1234' }
8
-
9
- describe '.build' do
10
- subject(:command) { instance.build(device_token: device_token) }
11
-
12
- context 'without device_token' do
13
- let(:device_token) { '' }
14
-
15
- it { expect { command }.to raise_error(Castle::InvalidParametersError) }
16
- end
17
-
18
- context 'with device_token' do
19
- it { expect(command.method).to be(:put) }
20
- it { expect(command.path).to eql("devices/#{device_token}/approve") }
21
- it { expect(command.data).to be_nil }
22
- end
23
- end
24
- end