castle-rb 6.0.1 → 7.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.
- checksums.yaml +4 -4
- data/README.md +8 -8
- data/lib/castle.rb +7 -11
- data/lib/castle/api.rb +7 -12
- data/lib/castle/api/approve_device.rb +1 -6
- data/lib/castle/api/authenticate.rb +10 -7
- data/lib/castle/api/end_impersonation.rb +3 -8
- data/lib/castle/api/filter.rb +37 -0
- data/lib/castle/api/get_device.rb +1 -6
- data/lib/castle/api/get_devices_for_user.rb +1 -6
- data/lib/castle/api/log.rb +37 -0
- data/lib/castle/api/report_device.rb +1 -6
- data/lib/castle/api/risk.rb +37 -0
- data/lib/castle/api/start_impersonation.rb +3 -8
- data/lib/castle/api/track.rb +1 -6
- data/lib/castle/client.rb +36 -16
- data/lib/castle/commands/approve_device.rb +1 -5
- data/lib/castle/commands/end_impersonation.rb +1 -1
- data/lib/castle/commands/filter.rb +23 -0
- data/lib/castle/commands/get_device.rb +1 -5
- data/lib/castle/commands/get_devices_for_user.rb +1 -5
- data/lib/castle/commands/{identify.rb → log.rb} +4 -3
- data/lib/castle/commands/report_device.rb +1 -5
- data/lib/castle/commands/risk.rb +23 -0
- data/lib/castle/commands/start_impersonation.rb +1 -1
- data/lib/castle/configuration.rb +18 -8
- data/lib/castle/core/get_connection.rb +3 -1
- data/lib/castle/core/process_response.rb +5 -2
- data/lib/castle/core/process_webhook.rb +10 -5
- data/lib/castle/core/send_request.rb +8 -16
- data/lib/castle/errors.rb +37 -13
- data/lib/castle/failover/prepare_response.rb +2 -7
- data/lib/castle/failover/strategy.rb +3 -0
- data/lib/castle/headers/extract.rb +4 -4
- data/lib/castle/headers/filter.rb +9 -6
- data/lib/castle/ips/extract.rb +4 -2
- data/lib/castle/logger.rb +3 -3
- data/lib/castle/payload/prepare.rb +3 -4
- data/lib/castle/secure_mode.rb +3 -2
- data/lib/castle/support/hanami.rb +2 -6
- data/lib/castle/support/rails.rb +1 -3
- data/lib/castle/utils/clean_invalid_chars.rb +1 -3
- data/lib/castle/verdict.rb +2 -0
- data/lib/castle/version.rb +1 -1
- data/lib/castle/webhooks/verify.rb +9 -7
- data/spec/integration/rails/rails_spec.rb +9 -7
- data/spec/integration/rails/support/home_controller.rb +26 -24
- data/spec/lib/castle/api/approve_device_spec.rb +3 -3
- data/spec/lib/castle/api/authenticate_spec.rb +20 -24
- data/spec/lib/castle/api/end_impersonation_spec.rb +11 -5
- data/spec/lib/castle/api/filter_spec.rb +5 -0
- data/spec/lib/castle/api/get_device_spec.rb +3 -3
- data/spec/lib/castle/api/get_devices_for_user_spec.rb +3 -3
- data/spec/lib/castle/api/log_spec.rb +5 -0
- data/spec/lib/castle/api/report_device_spec.rb +3 -3
- data/spec/lib/castle/api/risk_spec.rb +5 -0
- data/spec/lib/castle/api/start_impersonation_spec.rb +11 -5
- data/spec/lib/castle/api/track_spec.rb +11 -7
- data/spec/lib/castle/api_spec.rb +4 -20
- data/spec/lib/castle/client_id/extract_spec.rb +4 -13
- data/spec/lib/castle/client_spec.rb +81 -84
- data/spec/lib/castle/commands/authenticate_spec.rb +8 -15
- data/spec/lib/castle/commands/end_impersonation_spec.rb +6 -9
- data/spec/lib/castle/commands/{identify_spec.rb → filter_spec.rb} +41 -19
- data/spec/lib/castle/commands/log_spec.rb +100 -0
- data/spec/lib/castle/commands/risk_spec.rb +100 -0
- data/spec/lib/castle/commands/start_impersonation_spec.rb +6 -9
- data/spec/lib/castle/commands/track_spec.rb +9 -18
- data/spec/lib/castle/configuration_spec.rb +2 -6
- data/spec/lib/castle/context/get_default_spec.rb +8 -8
- data/spec/lib/castle/context/prepare_spec.rb +6 -7
- data/spec/lib/castle/core/get_connection_spec.rb +6 -22
- data/spec/lib/castle/core/process_response_spec.rb +1 -8
- data/spec/lib/castle/core/send_request_spec.rb +4 -29
- data/spec/lib/castle/headers/extract_spec.rb +1 -3
- data/spec/lib/castle/headers/filter_spec.rb +12 -11
- data/spec/lib/castle/ips/extract_spec.rb +4 -13
- data/spec/lib/castle/logger_spec.rb +2 -6
- data/spec/lib/castle/payload/prepare_spec.rb +5 -4
- data/spec/lib/castle/session_spec.rb +13 -36
- data/spec/lib/castle/singleton_configuration_spec.rb +2 -6
- data/spec/lib/castle/utils/clean_invalid_chars_spec.rb +2 -2
- data/spec/lib/castle/utils/merge_spec.rb +3 -1
- data/spec/lib/castle/validators/present_spec.rb +5 -6
- data/spec/lib/castle/webhooks/verify_spec.rb +8 -24
- data/spec/lib/castle_spec.rb +4 -10
- data/spec/spec_helper.rb +1 -3
- data/spec/support/shared_examples/action_request.rb +152 -0
- data/spec/support/shared_examples/configuration.rb +14 -42
- metadata +23 -18
- data/lib/castle/api/identify.rb +0 -26
- data/lib/castle/api/review.rb +0 -24
- data/lib/castle/commands/review.rb +0 -17
- data/lib/castle/events.rb +0 -49
- data/spec/lib/castle/api/identify_spec.rb +0 -68
- data/spec/lib/castle/api/review_spec.rb +0 -19
- data/spec/lib/castle/commands/review_spec.rb +0 -24
- data/spec/lib/castle/events_spec.rb +0 -5
data/lib/castle/api/identify.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Castle
|
4
|
-
module API
|
5
|
-
module Identify
|
6
|
-
class << self
|
7
|
-
# @param options [Hash]
|
8
|
-
def call(options = {})
|
9
|
-
unless options[:no_symbolize]
|
10
|
-
options = Castle::Utils::DeepSymbolizeKeys.call(options || {})
|
11
|
-
end
|
12
|
-
options.delete(:no_symbolize)
|
13
|
-
http = options.delete(:http)
|
14
|
-
config = options.delete(:config) || Castle.config
|
15
|
-
|
16
|
-
Castle::API.call(
|
17
|
-
Castle::Commands::Identify.build(options),
|
18
|
-
{},
|
19
|
-
http,
|
20
|
-
config
|
21
|
-
)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/castle/api/review.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Castle
|
4
|
-
module API
|
5
|
-
module Review
|
6
|
-
class << self
|
7
|
-
# @param options [Hash]
|
8
|
-
# return [Hash]
|
9
|
-
def call(options = {})
|
10
|
-
options = Castle::Utils::DeepSymbolizeKeys.call(options || {})
|
11
|
-
http = options.delete(:http)
|
12
|
-
config = options.delete(:config) || Castle.config
|
13
|
-
|
14
|
-
Castle::API.call(
|
15
|
-
Castle::Commands::Review.build(options),
|
16
|
-
{},
|
17
|
-
http,
|
18
|
-
config
|
19
|
-
)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Castle
|
4
|
-
module Commands
|
5
|
-
# Generates the payload for the GET reviews/#{review_id} request
|
6
|
-
class Review
|
7
|
-
class << self
|
8
|
-
# @param options [Hash]
|
9
|
-
# @return [Castle::Command]
|
10
|
-
def build(options = {})
|
11
|
-
Castle::Validators::Present.call(options, %i[review_id])
|
12
|
-
Castle::Command.new("reviews/#{options[:review_id]}", nil, :get)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/castle/events.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Castle
|
4
|
-
# list of events based on https://docs.castle.io/api_reference/#list-of-recognized-events
|
5
|
-
module Events
|
6
|
-
# Record when a user successfully logs in.
|
7
|
-
LOGIN_SUCCEEDED = '$login.succeeded'
|
8
|
-
# Record when a user failed to log in.
|
9
|
-
LOGIN_FAILED = '$login.failed'
|
10
|
-
# Record when a user logs out.
|
11
|
-
LOGOUT_SUCCEEDED = '$logout.succeeded'
|
12
|
-
# Record when a user updated their profile (including password, email, phone, etc).
|
13
|
-
PROFILE_UPDATE_SUCCEEDED = '$profile_update.succeeded'
|
14
|
-
# Record errors when updating profile.
|
15
|
-
PROFILE_UPDATE_FAILED = '$profile_update.failed'
|
16
|
-
# Capture account creation, both when a user signs up as well as when created manually
|
17
|
-
# by an administrator.
|
18
|
-
REGISTRATION_SUCCEEDED = '$registration.succeeded'
|
19
|
-
# Record when an account failed to be created.
|
20
|
-
REGISTRATION_FAILED = '$registration.failed'
|
21
|
-
# The user completed all of the steps in the password reset process and the password was
|
22
|
-
# successfully reset.Password resets do not required knowledge of the current password.
|
23
|
-
PASSWORD_RESET_SUCCEEDED = '$password_reset.succeeded'
|
24
|
-
# Use to record when a user failed to reset their password.
|
25
|
-
PASSWORD_RESET_FAILED = '$password_reset.failed'
|
26
|
-
# The user successfully requested a password reset.
|
27
|
-
PASSWORD_RESET_REQUEST_SUCCCEEDED = '$password_reset_request.succeeded'
|
28
|
-
# The user failed to request a password reset.
|
29
|
-
PASSWORD_RESET_REQUEST_FAILED = '$password_reset_request.failed'
|
30
|
-
# User account has been reset.
|
31
|
-
INCIDENT_MITIGATED = '$incident.mitigated'
|
32
|
-
# User confirmed malicious activity.
|
33
|
-
REVIEW_ESCALATED = '$review.escalated'
|
34
|
-
# User confirmed safe activity.
|
35
|
-
REVIEW_RESOLVED = '$review.resolved'
|
36
|
-
# Record when a user is prompted with additional verification, such as two-factor
|
37
|
-
# authentication or a captcha.
|
38
|
-
CHALLENGE_REQUESTED = '$challenge.requested'
|
39
|
-
# Record when additional verification was successful.
|
40
|
-
CHALLENGE_SUCCEEDED = '$challenge.succeeded'
|
41
|
-
# Record when additional verification failed.
|
42
|
-
CHALLENGE_FAILED = '$challenge.failed'
|
43
|
-
# Record when a user attempts an in-app transaction, such as a purchase or withdrawal.
|
44
|
-
TRANSACTION_ATTEMPTED = '$transaction.attempted'
|
45
|
-
# Record when a user session is extended, or use any time you want
|
46
|
-
# to re-authenticate a user mid-session.
|
47
|
-
SESSION_EXTENDED = '$session.extended'
|
48
|
-
end
|
49
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Castle::API::Identify 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(
|
28
|
-
basic_auth: ['', 'secret']
|
29
|
-
).to_return(status: 200, body: response_body, headers: {})
|
30
|
-
end
|
31
|
-
|
32
|
-
after { Timecop.return }
|
33
|
-
|
34
|
-
describe '.call' do
|
35
|
-
let(:request_body) do
|
36
|
-
{ event: '$login.succeeded', context: context, user_id: '1234',
|
37
|
-
sent_at: time_auto }
|
38
|
-
end
|
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/identify', 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) do
|
53
|
-
{ event: '$login.succeeded', user_id: '1234', timestamp: time_user, context: context }
|
54
|
-
end
|
55
|
-
let(:request_body) do
|
56
|
-
{ event: '$login.succeeded', user_id: '1234', context: context,
|
57
|
-
timestamp: time_user, sent_at: time_auto }
|
58
|
-
end
|
59
|
-
|
60
|
-
it do
|
61
|
-
assert_requested :post, 'https://api.castle.io/v1/identify', times: 1 do |req|
|
62
|
-
JSON.parse(req.body) == JSON.parse(request_body.to_json)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Castle::API::Review do
|
4
|
-
before do
|
5
|
-
stub_request(:any, /api.castle.io/).with(
|
6
|
-
basic_auth: ['', 'secret']
|
7
|
-
).to_return(status: 200, body: '{}', headers: {})
|
8
|
-
end
|
9
|
-
|
10
|
-
describe '.call' do
|
11
|
-
subject(:retrieve) { described_class.call(review_id: review_id) }
|
12
|
-
|
13
|
-
let(:review_id) { '1234' }
|
14
|
-
|
15
|
-
before { retrieve }
|
16
|
-
|
17
|
-
it { assert_requested :get, "https://api.castle.io/v1/reviews/#{review_id}", times: 1 }
|
18
|
-
end
|
19
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
describe Castle::Commands::Review do
|
4
|
-
subject(:instance) { described_class }
|
5
|
-
|
6
|
-
let(:context) { {} }
|
7
|
-
let(:review_id) { '1234' }
|
8
|
-
|
9
|
-
describe '.build' do
|
10
|
-
subject(:command) { instance.build(review_id: review_id) }
|
11
|
-
|
12
|
-
context 'without review_id' do
|
13
|
-
let(:review_id) { '' }
|
14
|
-
|
15
|
-
it { expect { command }.to raise_error(Castle::InvalidParametersError) }
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'with review_id' do
|
19
|
-
it { expect(command.method).to be_eql(:get) }
|
20
|
-
it { expect(command.path).to be_eql("reviews/#{review_id}") }
|
21
|
-
it { expect(command.data).to be_nil }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|