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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -8
  3. data/lib/castle.rb +7 -11
  4. data/lib/castle/api.rb +7 -12
  5. data/lib/castle/api/approve_device.rb +1 -6
  6. data/lib/castle/api/authenticate.rb +10 -7
  7. data/lib/castle/api/end_impersonation.rb +3 -8
  8. data/lib/castle/api/filter.rb +37 -0
  9. data/lib/castle/api/get_device.rb +1 -6
  10. data/lib/castle/api/get_devices_for_user.rb +1 -6
  11. data/lib/castle/api/log.rb +37 -0
  12. data/lib/castle/api/report_device.rb +1 -6
  13. data/lib/castle/api/risk.rb +37 -0
  14. data/lib/castle/api/start_impersonation.rb +3 -8
  15. data/lib/castle/api/track.rb +1 -6
  16. data/lib/castle/client.rb +36 -16
  17. data/lib/castle/commands/approve_device.rb +1 -5
  18. data/lib/castle/commands/end_impersonation.rb +1 -1
  19. data/lib/castle/commands/filter.rb +23 -0
  20. data/lib/castle/commands/get_device.rb +1 -5
  21. data/lib/castle/commands/get_devices_for_user.rb +1 -5
  22. data/lib/castle/commands/{identify.rb → log.rb} +4 -3
  23. data/lib/castle/commands/report_device.rb +1 -5
  24. data/lib/castle/commands/risk.rb +23 -0
  25. data/lib/castle/commands/start_impersonation.rb +1 -1
  26. data/lib/castle/configuration.rb +18 -8
  27. data/lib/castle/core/get_connection.rb +3 -1
  28. data/lib/castle/core/process_response.rb +5 -2
  29. data/lib/castle/core/process_webhook.rb +10 -5
  30. data/lib/castle/core/send_request.rb +8 -16
  31. data/lib/castle/errors.rb +37 -13
  32. data/lib/castle/failover/prepare_response.rb +2 -7
  33. data/lib/castle/failover/strategy.rb +3 -0
  34. data/lib/castle/headers/extract.rb +4 -4
  35. data/lib/castle/headers/filter.rb +9 -6
  36. data/lib/castle/ips/extract.rb +4 -2
  37. data/lib/castle/logger.rb +3 -3
  38. data/lib/castle/payload/prepare.rb +3 -4
  39. data/lib/castle/secure_mode.rb +3 -2
  40. data/lib/castle/support/hanami.rb +2 -6
  41. data/lib/castle/support/rails.rb +1 -3
  42. data/lib/castle/utils/clean_invalid_chars.rb +1 -3
  43. data/lib/castle/verdict.rb +2 -0
  44. data/lib/castle/version.rb +1 -1
  45. data/lib/castle/webhooks/verify.rb +9 -7
  46. data/spec/integration/rails/rails_spec.rb +9 -7
  47. data/spec/integration/rails/support/home_controller.rb +26 -24
  48. data/spec/lib/castle/api/approve_device_spec.rb +3 -3
  49. data/spec/lib/castle/api/authenticate_spec.rb +20 -24
  50. data/spec/lib/castle/api/end_impersonation_spec.rb +11 -5
  51. data/spec/lib/castle/api/filter_spec.rb +5 -0
  52. data/spec/lib/castle/api/get_device_spec.rb +3 -3
  53. data/spec/lib/castle/api/get_devices_for_user_spec.rb +3 -3
  54. data/spec/lib/castle/api/log_spec.rb +5 -0
  55. data/spec/lib/castle/api/report_device_spec.rb +3 -3
  56. data/spec/lib/castle/api/risk_spec.rb +5 -0
  57. data/spec/lib/castle/api/start_impersonation_spec.rb +11 -5
  58. data/spec/lib/castle/api/track_spec.rb +11 -7
  59. data/spec/lib/castle/api_spec.rb +4 -20
  60. data/spec/lib/castle/client_id/extract_spec.rb +4 -13
  61. data/spec/lib/castle/client_spec.rb +81 -84
  62. data/spec/lib/castle/commands/authenticate_spec.rb +8 -15
  63. data/spec/lib/castle/commands/end_impersonation_spec.rb +6 -9
  64. data/spec/lib/castle/commands/{identify_spec.rb → filter_spec.rb} +41 -19
  65. data/spec/lib/castle/commands/log_spec.rb +100 -0
  66. data/spec/lib/castle/commands/risk_spec.rb +100 -0
  67. data/spec/lib/castle/commands/start_impersonation_spec.rb +6 -9
  68. data/spec/lib/castle/commands/track_spec.rb +9 -18
  69. data/spec/lib/castle/configuration_spec.rb +2 -6
  70. data/spec/lib/castle/context/get_default_spec.rb +8 -8
  71. data/spec/lib/castle/context/prepare_spec.rb +6 -7
  72. data/spec/lib/castle/core/get_connection_spec.rb +6 -22
  73. data/spec/lib/castle/core/process_response_spec.rb +1 -8
  74. data/spec/lib/castle/core/send_request_spec.rb +4 -29
  75. data/spec/lib/castle/headers/extract_spec.rb +1 -3
  76. data/spec/lib/castle/headers/filter_spec.rb +12 -11
  77. data/spec/lib/castle/ips/extract_spec.rb +4 -13
  78. data/spec/lib/castle/logger_spec.rb +2 -6
  79. data/spec/lib/castle/payload/prepare_spec.rb +5 -4
  80. data/spec/lib/castle/session_spec.rb +13 -36
  81. data/spec/lib/castle/singleton_configuration_spec.rb +2 -6
  82. data/spec/lib/castle/utils/clean_invalid_chars_spec.rb +2 -2
  83. data/spec/lib/castle/utils/merge_spec.rb +3 -1
  84. data/spec/lib/castle/validators/present_spec.rb +5 -6
  85. data/spec/lib/castle/webhooks/verify_spec.rb +8 -24
  86. data/spec/lib/castle_spec.rb +4 -10
  87. data/spec/spec_helper.rb +1 -3
  88. data/spec/support/shared_examples/action_request.rb +152 -0
  89. data/spec/support/shared_examples/configuration.rb +14 -42
  90. metadata +23 -18
  91. data/lib/castle/api/identify.rb +0 -26
  92. data/lib/castle/api/review.rb +0 -24
  93. data/lib/castle/commands/review.rb +0 -17
  94. data/lib/castle/events.rb +0 -49
  95. data/spec/lib/castle/api/identify_spec.rb +0 -68
  96. data/spec/lib/castle/api/review_spec.rb +0 -19
  97. data/spec/lib/castle/commands/review_spec.rb +0 -24
  98. data/spec/lib/castle/events_spec.rb +0 -5
@@ -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
@@ -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
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Castle::Events do
4
- it { expect(described_class::LOGIN_SUCCEEDED).to eq('$login.succeeded') }
5
- end