castle-rb 5.0.0 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +113 -39
- data/lib/castle.rb +49 -29
- data/lib/castle/api.rb +20 -16
- data/lib/castle/api/approve_device.rb +20 -0
- data/lib/castle/api/authenticate.rb +37 -0
- data/lib/castle/api/end_impersonation.rb +24 -0
- data/lib/castle/api/filter.rb +37 -0
- data/lib/castle/api/get_device.rb +20 -0
- data/lib/castle/api/get_devices_for_user.rb +20 -0
- data/lib/castle/api/log.rb +37 -0
- data/lib/castle/api/report_device.rb +20 -0
- data/lib/castle/api/risk.rb +37 -0
- data/lib/castle/api/start_impersonation.rb +24 -0
- data/lib/castle/api/track.rb +21 -0
- data/lib/castle/client.rb +74 -68
- data/lib/castle/{extractors/client_id.rb → client_id/extract.rb} +2 -2
- data/lib/castle/commands/approve_device.rb +17 -0
- data/lib/castle/commands/authenticate.rb +13 -13
- data/lib/castle/commands/end_impersonation.rb +25 -0
- data/lib/castle/commands/filter.rb +22 -0
- data/lib/castle/commands/get_device.rb +17 -0
- data/lib/castle/commands/get_devices_for_user.rb +17 -0
- data/lib/castle/commands/log.rb +22 -0
- data/lib/castle/commands/report_device.rb +17 -0
- data/lib/castle/commands/risk.rb +22 -0
- data/lib/castle/commands/start_impersonation.rb +25 -0
- data/lib/castle/commands/track.rb +12 -13
- data/lib/castle/configuration.rb +31 -23
- data/lib/castle/context/{default.rb → get_default.rb} +5 -6
- data/lib/castle/context/{merger.rb → merge.rb} +3 -3
- data/lib/castle/context/prepare.rb +18 -0
- data/lib/castle/context/{sanitizer.rb → sanitize.rb} +1 -1
- data/lib/castle/core/get_connection.rb +27 -0
- data/lib/castle/{api/response.rb → core/process_response.rb} +8 -3
- data/lib/castle/core/process_webhook.rb +25 -0
- data/lib/castle/core/send_request.rb +42 -0
- data/lib/castle/errors.rb +38 -12
- data/lib/castle/failover/prepare_response.rb +28 -0
- data/lib/castle/failover/strategy.rb +23 -0
- data/lib/castle/{extractors/headers.rb → headers/extract.rb} +8 -6
- data/lib/castle/headers/filter.rb +40 -0
- data/lib/castle/headers/format.rb +24 -0
- data/lib/castle/{extractors/ip.rb → ips/extract.rb} +11 -7
- data/lib/castle/logger.rb +19 -0
- data/lib/castle/payload/prepare.rb +26 -0
- data/lib/castle/secure_mode.rb +7 -2
- data/lib/castle/session.rb +18 -0
- data/lib/castle/singleton_configuration.rb +9 -0
- data/lib/castle/support/hanami.rb +2 -6
- data/lib/castle/support/rails.rb +1 -3
- data/lib/castle/utils/clean_invalid_chars.rb +22 -0
- data/lib/castle/utils/clone.rb +15 -0
- data/lib/castle/utils/deep_symbolize_keys.rb +45 -0
- data/lib/castle/utils/get_timestamp.rb +15 -0
- data/lib/castle/utils/{merger.rb → merge.rb} +3 -3
- data/lib/castle/utils/secure_compare.rb +22 -0
- data/lib/castle/validators/not_supported.rb +1 -0
- data/lib/castle/validators/present.rb +1 -0
- data/lib/castle/verdict.rb +15 -0
- data/lib/castle/version.rb +1 -1
- data/lib/castle/webhooks/verify.rb +45 -0
- data/spec/integration/rails/rails_spec.rb +42 -14
- data/spec/integration/rails/support/application.rb +3 -1
- data/spec/integration/rails/support/home_controller.rb +50 -6
- data/spec/lib/castle/api/approve_device_spec.rb +21 -0
- data/spec/lib/castle/api/authenticate_spec.rb +136 -0
- data/spec/lib/castle/api/end_impersonation_spec.rb +65 -0
- data/spec/lib/castle/api/filter_spec.rb +5 -0
- data/spec/lib/castle/api/get_device_spec.rb +19 -0
- data/spec/lib/castle/api/get_devices_for_user_spec.rb +19 -0
- data/spec/lib/castle/api/log_spec.rb +5 -0
- data/spec/lib/castle/api/report_device_spec.rb +21 -0
- data/spec/lib/castle/api/risk_spec.rb +5 -0
- data/spec/lib/castle/api/start_impersonation_spec.rb +65 -0
- data/spec/lib/castle/api/track_spec.rb +72 -0
- data/spec/lib/castle/api_spec.rb +14 -15
- data/spec/lib/castle/{extractors/client_id_spec.rb → client_id/extract_spec.rb} +6 -15
- data/spec/lib/castle/client_spec.rb +110 -92
- data/spec/lib/castle/commands/approve_device_spec.rb +24 -0
- data/spec/lib/castle/commands/authenticate_spec.rb +15 -31
- data/spec/lib/castle/commands/end_impersonation_spec.rb +79 -0
- data/spec/lib/castle/commands/filter_spec.rb +72 -0
- data/spec/lib/castle/commands/get_device_spec.rb +24 -0
- data/spec/lib/castle/commands/{review_spec.rb → get_devices_for_user_spec.rb} +7 -7
- data/spec/lib/castle/commands/log_spec.rb +73 -0
- data/spec/lib/castle/commands/report_device_spec.rb +24 -0
- data/spec/lib/castle/commands/risk_spec.rb +73 -0
- data/spec/lib/castle/commands/{impersonate_spec.rb → start_impersonation_spec.rb} +13 -41
- data/spec/lib/castle/commands/track_spec.rb +14 -34
- data/spec/lib/castle/configuration_spec.rb +8 -141
- data/spec/lib/castle/context/{default_spec.rb → get_default_spec.rb} +9 -10
- data/spec/lib/castle/context/{merger_spec.rb → merge_spec.rb} +1 -1
- data/spec/lib/castle/context/prepare_spec.rb +43 -0
- data/spec/lib/castle/context/{sanitizer_spec.rb → sanitize_spec.rb} +1 -1
- data/spec/lib/castle/core/get_connection_spec.rb +43 -0
- data/spec/lib/castle/{api/response_spec.rb → core/process_response_spec.rb} +49 -1
- data/spec/lib/castle/core/process_webhook_spec.rb +46 -0
- data/spec/lib/castle/{api/request_spec.rb → core/send_request_spec.rb} +16 -37
- data/spec/lib/castle/failover/strategy_spec.rb +12 -0
- data/spec/lib/castle/{extractors/headers_spec.rb → headers/extract_spec.rb} +7 -9
- data/spec/lib/castle/headers/filter_spec.rb +39 -0
- data/spec/lib/castle/headers/format_spec.rb +25 -0
- data/spec/lib/castle/{extractors/ip_spec.rb → ips/extract_spec.rb} +5 -14
- data/spec/lib/castle/logger_spec.rb +38 -0
- data/spec/lib/castle/payload/prepare_spec.rb +55 -0
- data/spec/lib/castle/session_spec.rb +65 -0
- data/spec/lib/castle/singleton_configuration_spec.rb +14 -0
- data/spec/lib/castle/utils/clean_invalid_chars_spec.rb +69 -0
- data/spec/lib/castle/utils/{cloner_spec.rb → clone_spec.rb} +3 -3
- data/spec/lib/castle/utils/deep_symbolize_keys_spec.rb +50 -0
- data/spec/lib/castle/utils/{timestamp_spec.rb → get_timestamp_spec.rb} +1 -1
- data/spec/lib/castle/utils/merge_spec.rb +15 -0
- data/spec/lib/castle/validators/present_spec.rb +5 -6
- data/spec/lib/castle/verdict_spec.rb +9 -0
- data/spec/lib/castle/webhooks/verify_spec.rb +53 -0
- data/spec/lib/castle_spec.rb +4 -10
- data/spec/spec_helper.rb +3 -3
- data/spec/support/shared_examples/action_request.rb +155 -0
- data/spec/support/shared_examples/configuration.rb +101 -0
- metadata +144 -67
- data/lib/castle/api/connection.rb +0 -24
- data/lib/castle/api/request.rb +0 -42
- data/lib/castle/api/session.rb +0 -20
- data/lib/castle/commands/identify.rb +0 -23
- data/lib/castle/commands/impersonate.rb +0 -26
- data/lib/castle/commands/review.rb +0 -14
- data/lib/castle/events.rb +0 -49
- data/lib/castle/failover_auth_response.rb +0 -21
- data/lib/castle/headers_filter.rb +0 -35
- data/lib/castle/headers_formatter.rb +0 -22
- data/lib/castle/review.rb +0 -11
- data/lib/castle/utils.rb +0 -55
- data/lib/castle/utils/cloner.rb +0 -11
- data/lib/castle/utils/timestamp.rb +0 -12
- data/spec/lib/castle/api/connection_spec.rb +0 -59
- data/spec/lib/castle/api/session_spec.rb +0 -86
- data/spec/lib/castle/commands/identify_spec.rb +0 -88
- data/spec/lib/castle/events_spec.rb +0 -5
- data/spec/lib/castle/headers_filter_spec.rb +0 -38
- data/spec/lib/castle/headers_formatter_spec.rb +0 -25
- data/spec/lib/castle/review_spec.rb +0 -19
- data/spec/lib/castle/utils/merger_spec.rb +0 -13
- data/spec/lib/castle/utils_spec.rb +0 -156
data/spec/lib/castle/api_spec.rb
CHANGED
@@ -3,35 +3,34 @@
|
|
3
3
|
describe Castle::API do
|
4
4
|
subject(:call) { described_class.call(command) }
|
5
5
|
|
6
|
-
let(:command) { Castle::Commands::Track.
|
6
|
+
let(:command) { Castle::Commands::Track.build(event: '$login.succeeded') }
|
7
7
|
|
8
8
|
context 'when request timeouts' do
|
9
9
|
before { stub_request(:any, /api.castle.io/).to_timeout }
|
10
10
|
|
11
|
-
it
|
12
|
-
expect do
|
13
|
-
call
|
14
|
-
end.to raise_error(Castle::RequestError)
|
15
|
-
end
|
11
|
+
it { expect { call }.to raise_error(Castle::RequestError) }
|
16
12
|
end
|
17
13
|
|
18
14
|
context 'when non-OK response code' do
|
19
15
|
before { stub_request(:any, /api.castle.io/).to_return(status: 400) }
|
20
16
|
|
21
|
-
it
|
22
|
-
expect do
|
23
|
-
call
|
24
|
-
end.to raise_error(Castle::BadRequestError)
|
25
|
-
end
|
17
|
+
it { expect { call }.to raise_error(Castle::BadRequestError) }
|
26
18
|
end
|
27
19
|
|
28
20
|
context 'when no api_secret' do
|
29
21
|
before { allow(Castle.config).to receive(:api_secret).and_return('') }
|
30
22
|
|
31
|
-
it
|
32
|
-
|
33
|
-
|
34
|
-
|
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/)
|
35
32
|
end
|
33
|
+
|
34
|
+
it { expect { call }.not_to raise_error }
|
36
35
|
end
|
37
36
|
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
describe Castle::
|
3
|
+
describe Castle::ClientId::Extract do
|
4
4
|
subject(:extractor) { described_class.new(formatted_headers, cookies) }
|
5
5
|
|
6
|
-
let(:formatted_headers) { Castle::
|
6
|
+
let(:formatted_headers) { Castle::Headers::Filter.new(request).call }
|
7
7
|
let(:client_id_cookie) { 'abcd' }
|
8
8
|
let(:client_id_header) { 'abcde' }
|
9
9
|
let(:cookies) { request.cookies }
|
10
10
|
let(:request) { Rack::Request.new(env) }
|
11
|
-
let(:env)
|
12
|
-
Rack::MockRequest.env_for('/', headers)
|
13
|
-
end
|
11
|
+
let(:env) { Rack::MockRequest.env_for('/', headers) }
|
14
12
|
|
15
13
|
context 'with client_id' do
|
16
14
|
let(:headers) do
|
@@ -20,17 +18,12 @@ describe Castle::Extractors::ClientId do
|
|
20
18
|
}
|
21
19
|
end
|
22
20
|
|
23
|
-
it
|
24
|
-
expect(extractor.call).to eql(client_id_cookie)
|
25
|
-
end
|
21
|
+
it { expect(extractor.call).to eql(client_id_cookie) }
|
26
22
|
end
|
27
23
|
|
28
24
|
context 'with X-Castle-Client-Id header' do
|
29
25
|
let(:headers) do
|
30
|
-
{
|
31
|
-
'HTTP_X_FORWARDED_FOR' => '1.2.3.4',
|
32
|
-
'HTTP_X_CASTLE_CLIENT_ID' => client_id_header
|
33
|
-
}
|
26
|
+
{ 'HTTP_X_FORWARDED_FOR' => '1.2.3.4', 'HTTP_X_CASTLE_CLIENT_ID' => client_id_header }
|
34
27
|
end
|
35
28
|
|
36
29
|
it 'appends the client_id' do
|
@@ -42,9 +35,7 @@ describe Castle::Extractors::ClientId do
|
|
42
35
|
let(:cookies) { nil }
|
43
36
|
let(:headers) { {} }
|
44
37
|
|
45
|
-
it
|
46
|
-
expect(extractor.call).to eql('')
|
47
|
-
end
|
38
|
+
it { expect(extractor.call).to eql('') }
|
48
39
|
end
|
49
40
|
|
50
41
|
context 'with X-Castle-Client-Id header and cookies client' do
|
@@ -14,26 +14,26 @@ describe Castle::Client do
|
|
14
14
|
end
|
15
15
|
let(:request) { Rack::Request.new(env) }
|
16
16
|
let(:client) { described_class.from_request(request) }
|
17
|
-
let(:request_to_context) {
|
17
|
+
let(:request_to_context) { Castle::Context::Prepare.call(request) }
|
18
18
|
let(:client_with_user_timestamp) do
|
19
|
-
described_class.new(request_to_context, timestamp: time_user)
|
19
|
+
described_class.new(context: request_to_context, timestamp: time_user)
|
20
20
|
end
|
21
|
-
let(:client_with_no_timestamp) { described_class.new(request_to_context) }
|
21
|
+
let(:client_with_no_timestamp) { described_class.new(context: request_to_context) }
|
22
22
|
|
23
23
|
let(:headers) do
|
24
|
-
{
|
25
|
-
'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, 'Cookie': true
|
26
|
-
}
|
24
|
+
{ 'Content-Length': '0', 'User-Agent': ua, 'X-Forwarded-For': ip.to_s, 'Cookie': true }
|
27
25
|
end
|
28
26
|
let(:context) do
|
29
27
|
{
|
30
28
|
client_id: 'abcd',
|
31
29
|
active: true,
|
32
|
-
origin: 'web',
|
33
30
|
user_agent: ua,
|
34
31
|
headers: headers,
|
35
32
|
ip: ip,
|
36
|
-
library: {
|
33
|
+
library: {
|
34
|
+
name: 'castle-rb',
|
35
|
+
version: '2.2.0'
|
36
|
+
}
|
37
37
|
}
|
38
38
|
end
|
39
39
|
|
@@ -45,53 +45,43 @@ describe Castle::Client do
|
|
45
45
|
before do
|
46
46
|
Timecop.freeze(time_now)
|
47
47
|
stub_const('Castle::VERSION', '2.2.0')
|
48
|
-
stub_request(:any, /api.castle.io/)
|
49
|
-
basic_auth: ['', 'secret']
|
50
|
-
|
48
|
+
stub_request(:any, /api.castle.io/)
|
49
|
+
.with(basic_auth: ['', 'secret'])
|
50
|
+
.to_return(status: 200, body: response_body, headers: {})
|
51
51
|
end
|
52
52
|
|
53
53
|
after { Timecop.return }
|
54
54
|
|
55
55
|
describe 'parses the request' do
|
56
|
-
before
|
57
|
-
allow(Castle::API).to receive(:request).and_call_original
|
58
|
-
end
|
56
|
+
before { allow(Castle::API).to receive(:send_request).and_call_original }
|
59
57
|
|
60
58
|
it do
|
61
59
|
client.authenticate(event: '$login.succeeded', user_id: '1234')
|
62
|
-
expect(Castle::API).to have_received(:
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
describe 'to_context' do
|
67
|
-
it do
|
68
|
-
expect(described_class.to_context(request)).to eql(context)
|
60
|
+
expect(Castle::API).to have_received(:send_request)
|
69
61
|
end
|
70
62
|
end
|
71
63
|
|
72
|
-
describe '
|
73
|
-
let(:options) { { user_id: '1234', user_traits: { name: 'Jo' } } }
|
74
|
-
let(:result) { { user_id: '1234', user_traits: { name: 'Jo' }, timestamp: time_auto } }
|
75
|
-
|
76
|
-
it do
|
77
|
-
expect(described_class.to_options(options)).to eql(result)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe 'impersonate' do
|
64
|
+
describe 'end impersonation' do
|
82
65
|
let(:impersonator) { 'test@castle.io' }
|
83
66
|
let(:request_body) do
|
84
|
-
{
|
85
|
-
|
67
|
+
{
|
68
|
+
user_id: '1234',
|
69
|
+
timestamp: time_auto,
|
70
|
+
sent_at: time_auto,
|
71
|
+
properties: {
|
72
|
+
impersonator: impersonator
|
73
|
+
},
|
74
|
+
context: context
|
75
|
+
}
|
86
76
|
end
|
87
77
|
let(:response_body) { { success: true }.to_json }
|
88
78
|
let(:options) { { user_id: '1234', properties: { impersonator: impersonator } } }
|
89
79
|
|
90
80
|
context 'when used with symbol keys' do
|
91
|
-
before { client.
|
81
|
+
before { client.end_impersonation(options) }
|
92
82
|
|
93
83
|
it do
|
94
|
-
assert_requested :
|
84
|
+
assert_requested :delete, 'https://api.castle.io/v1/impersonate', times: 1 do |req|
|
95
85
|
JSON.parse(req.body) == JSON.parse(request_body.to_json)
|
96
86
|
end
|
97
87
|
end
|
@@ -100,64 +90,43 @@ describe Castle::Client do
|
|
100
90
|
context 'when request is not successful' do
|
101
91
|
let(:response_body) { {}.to_json }
|
102
92
|
|
103
|
-
it
|
93
|
+
it do
|
94
|
+
expect { client.end_impersonation(options) }.to raise_error(Castle::ImpersonationFailed)
|
95
|
+
end
|
104
96
|
end
|
105
97
|
end
|
106
98
|
|
107
|
-
describe '
|
99
|
+
describe 'start impersonation' do
|
100
|
+
let(:impersonator) { 'test@castle.io' }
|
108
101
|
let(:request_body) do
|
109
|
-
{
|
110
|
-
|
102
|
+
{
|
103
|
+
user_id: '1234',
|
104
|
+
timestamp: time_auto,
|
105
|
+
sent_at: time_auto,
|
106
|
+
properties: {
|
107
|
+
impersonator: impersonator
|
108
|
+
},
|
109
|
+
context: context
|
110
|
+
}
|
111
111
|
end
|
112
|
-
|
113
|
-
|
112
|
+
let(:response_body) { { success: true }.to_json }
|
113
|
+
let(:options) { { user_id: '1234', properties: { impersonator: impersonator } } }
|
114
114
|
|
115
115
|
context 'when used with symbol keys' do
|
116
|
-
|
116
|
+
before { client.start_impersonation(options) }
|
117
117
|
|
118
118
|
it do
|
119
|
-
assert_requested :post, 'https://api.castle.io/v1/
|
119
|
+
assert_requested :post, 'https://api.castle.io/v1/impersonate', times: 1 do |req|
|
120
120
|
JSON.parse(req.body) == JSON.parse(request_body.to_json)
|
121
121
|
end
|
122
122
|
end
|
123
|
-
|
124
|
-
context 'when passed timestamp in options and no defined timestamp' do
|
125
|
-
let(:client) { client_with_no_timestamp }
|
126
|
-
let(:options) { { user_id: '1234', user_traits: { name: 'Jo' }, timestamp: time_user } }
|
127
|
-
let(:request_body) do
|
128
|
-
{ user_id: '1234', user_traits: { name: 'Jo' }, context: context,
|
129
|
-
timestamp: time_user, sent_at: time_auto }
|
130
|
-
end
|
131
|
-
|
132
|
-
it do
|
133
|
-
assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
|
134
|
-
JSON.parse(req.body) == JSON.parse(request_body.to_json)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
context 'with client initialized with timestamp' do
|
140
|
-
let(:client) { client_with_user_timestamp }
|
141
|
-
let(:request_body) do
|
142
|
-
{ user_id: '1234', timestamp: time_user, sent_at: time_auto,
|
143
|
-
context: context, user_traits: { name: 'Jo' } }
|
144
|
-
end
|
145
|
-
|
146
|
-
it do
|
147
|
-
assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
|
148
|
-
JSON.parse(req.body) == JSON.parse(request_body.to_json)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
123
|
end
|
153
124
|
|
154
|
-
context 'when
|
155
|
-
let(:
|
125
|
+
context 'when request is not successful' do
|
126
|
+
let(:response_body) { {}.to_json }
|
156
127
|
|
157
128
|
it do
|
158
|
-
|
159
|
-
JSON.parse(req.body) == JSON.parse(request_body.to_json)
|
160
|
-
end
|
129
|
+
expect { client.start_impersonation(options) }.to raise_error(Castle::ImpersonationFailed)
|
161
130
|
end
|
162
131
|
end
|
163
132
|
end
|
@@ -166,8 +135,13 @@ describe Castle::Client do
|
|
166
135
|
let(:options) { { event: '$login.succeeded', user_id: '1234' } }
|
167
136
|
let(:request_response) { client.authenticate(options) }
|
168
137
|
let(:request_body) do
|
169
|
-
{
|
170
|
-
|
138
|
+
{
|
139
|
+
event: '$login.succeeded',
|
140
|
+
user_id: '1234',
|
141
|
+
context: context,
|
142
|
+
timestamp: time_auto,
|
143
|
+
sent_at: time_auto
|
144
|
+
}
|
171
145
|
end
|
172
146
|
|
173
147
|
context 'when used with symbol keys' do
|
@@ -183,8 +157,13 @@ describe Castle::Client do
|
|
183
157
|
let(:client) { client_with_no_timestamp }
|
184
158
|
let(:options) { { event: '$login.succeeded', user_id: '1234', timestamp: time_user } }
|
185
159
|
let(:request_body) do
|
186
|
-
{
|
187
|
-
|
160
|
+
{
|
161
|
+
event: '$login.succeeded',
|
162
|
+
user_id: '1234',
|
163
|
+
context: context,
|
164
|
+
timestamp: time_user,
|
165
|
+
sent_at: time_auto
|
166
|
+
}
|
188
167
|
end
|
189
168
|
|
190
169
|
it do
|
@@ -197,8 +176,13 @@ describe Castle::Client do
|
|
197
176
|
context 'with client initialized with timestamp' do
|
198
177
|
let(:client) { client_with_user_timestamp }
|
199
178
|
let(:request_body) do
|
200
|
-
{
|
201
|
-
|
179
|
+
{
|
180
|
+
event: '$login.succeeded',
|
181
|
+
user_id: '1234',
|
182
|
+
context: context,
|
183
|
+
timestamp: time_user,
|
184
|
+
sent_at: time_auto
|
185
|
+
}
|
202
186
|
end
|
203
187
|
|
204
188
|
it do
|
@@ -241,7 +225,8 @@ describe Castle::Client do
|
|
241
225
|
end
|
242
226
|
|
243
227
|
it { assert_not_requested :post, 'https://api.castle.io/v1/authenticate' }
|
244
|
-
it { expect(request_response[:action]).to be_eql(
|
228
|
+
it { expect(request_response[:policy][:action]).to be_eql(Castle::Verdict::ALLOW) }
|
229
|
+
it { expect(request_response[:action]).to be_eql(Castle::Verdict::ALLOW) }
|
245
230
|
it { expect(request_response[:user_id]).to be_eql('1234') }
|
246
231
|
it { expect(request_response[:failover]).to be true }
|
247
232
|
it { expect(request_response[:failover_reason]).to be_eql('Castle is set to do not track.') }
|
@@ -249,7 +234,9 @@ describe Castle::Client do
|
|
249
234
|
|
250
235
|
context 'when request with fail' do
|
251
236
|
before do
|
252
|
-
allow(Castle::API).to receive(:
|
237
|
+
allow(Castle::API).to receive(:send_request).and_raise(
|
238
|
+
Castle::RequestError.new(Timeout::Error)
|
239
|
+
)
|
253
240
|
end
|
254
241
|
|
255
242
|
context 'with request error and throw strategy' do
|
@@ -260,6 +247,7 @@ describe Castle::Client do
|
|
260
247
|
|
261
248
|
context 'with request error and not throw on eg deny strategy' do
|
262
249
|
it { assert_not_requested :post, 'https://:secret@api.castle.io/v1/authenticate' }
|
250
|
+
it { expect(request_response[:policy][:action]).to be_eql('allow') }
|
263
251
|
it { expect(request_response[:action]).to be_eql('allow') }
|
264
252
|
it { expect(request_response[:user_id]).to be_eql('1234') }
|
265
253
|
it { expect(request_response[:failover]).to be true }
|
@@ -268,7 +256,9 @@ describe Castle::Client do
|
|
268
256
|
end
|
269
257
|
|
270
258
|
context 'when request is internal server error' do
|
271
|
-
before
|
259
|
+
before do
|
260
|
+
allow(Castle::API).to receive(:send_request).and_raise(Castle::InternalServerError)
|
261
|
+
end
|
272
262
|
|
273
263
|
describe 'throw strategy' do
|
274
264
|
before { allow(Castle.config).to receive(:failover_strategy).and_return(:throw) }
|
@@ -278,6 +268,7 @@ describe Castle::Client do
|
|
278
268
|
|
279
269
|
describe 'not throw on eg deny strategy' do
|
280
270
|
it { assert_not_requested :post, 'https://:secret@api.castle.io/v1/authenticate' }
|
271
|
+
it { expect(request_response[:policy][:action]).to be_eql('allow') }
|
281
272
|
it { expect(request_response[:action]).to be_eql('allow') }
|
282
273
|
it { expect(request_response[:user_id]).to be_eql('1234') }
|
283
274
|
it { expect(request_response[:failover]).to be true }
|
@@ -288,8 +279,13 @@ describe Castle::Client do
|
|
288
279
|
|
289
280
|
describe 'track' do
|
290
281
|
let(:request_body) do
|
291
|
-
{
|
292
|
-
|
282
|
+
{
|
283
|
+
event: '$login.succeeded',
|
284
|
+
context: context,
|
285
|
+
user_id: '1234',
|
286
|
+
timestamp: time_auto,
|
287
|
+
sent_at: time_auto
|
288
|
+
}
|
293
289
|
end
|
294
290
|
|
295
291
|
before { client.track(options) }
|
@@ -307,8 +303,13 @@ describe Castle::Client do
|
|
307
303
|
let(:client) { client_with_no_timestamp }
|
308
304
|
let(:options) { { event: '$login.succeeded', user_id: '1234', timestamp: time_user } }
|
309
305
|
let(:request_body) do
|
310
|
-
{
|
311
|
-
|
306
|
+
{
|
307
|
+
event: '$login.succeeded',
|
308
|
+
user_id: '1234',
|
309
|
+
context: context,
|
310
|
+
timestamp: time_user,
|
311
|
+
sent_at: time_auto
|
312
|
+
}
|
312
313
|
end
|
313
314
|
|
314
315
|
it do
|
@@ -321,8 +322,13 @@ describe Castle::Client do
|
|
321
322
|
context 'with client initialized with timestamp' do
|
322
323
|
let(:client) { client_with_user_timestamp }
|
323
324
|
let(:request_body) do
|
324
|
-
{
|
325
|
-
|
325
|
+
{
|
326
|
+
event: '$login.succeeded',
|
327
|
+
context: context,
|
328
|
+
user_id: '1234',
|
329
|
+
timestamp: time_user,
|
330
|
+
sent_at: time_auto
|
331
|
+
}
|
326
332
|
end
|
327
333
|
|
328
334
|
it do
|
@@ -357,4 +363,16 @@ describe Castle::Client do
|
|
357
363
|
it { expect(client).to be_tracked }
|
358
364
|
end
|
359
365
|
end
|
366
|
+
|
367
|
+
describe 'filter' do
|
368
|
+
it_behaves_like 'action request', :filter
|
369
|
+
end
|
370
|
+
|
371
|
+
describe 'risk' do
|
372
|
+
it_behaves_like 'action request', :risk
|
373
|
+
end
|
374
|
+
|
375
|
+
describe 'log' do
|
376
|
+
it_behaves_like 'action request', :log
|
377
|
+
end
|
360
378
|
end
|
@@ -0,0 +1,24 @@
|
|
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_eql(:put) }
|
20
|
+
it { expect(command.path).to be_eql("devices/#{device_token}/approve") }
|
21
|
+
it { expect(command.data).to be_nil }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|