castle-rb 5.0.0 → 7.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +113 -39
  3. data/lib/castle.rb +49 -29
  4. data/lib/castle/api.rb +20 -16
  5. data/lib/castle/api/approve_device.rb +20 -0
  6. data/lib/castle/api/authenticate.rb +37 -0
  7. data/lib/castle/api/end_impersonation.rb +24 -0
  8. data/lib/castle/api/filter.rb +37 -0
  9. data/lib/castle/api/get_device.rb +20 -0
  10. data/lib/castle/api/get_devices_for_user.rb +20 -0
  11. data/lib/castle/api/log.rb +37 -0
  12. data/lib/castle/api/report_device.rb +20 -0
  13. data/lib/castle/api/risk.rb +37 -0
  14. data/lib/castle/api/start_impersonation.rb +24 -0
  15. data/lib/castle/api/track.rb +21 -0
  16. data/lib/castle/client.rb +74 -68
  17. data/lib/castle/{extractors/client_id.rb → client_id/extract.rb} +2 -2
  18. data/lib/castle/commands/approve_device.rb +17 -0
  19. data/lib/castle/commands/authenticate.rb +13 -13
  20. data/lib/castle/commands/end_impersonation.rb +25 -0
  21. data/lib/castle/commands/filter.rb +22 -0
  22. data/lib/castle/commands/get_device.rb +17 -0
  23. data/lib/castle/commands/get_devices_for_user.rb +17 -0
  24. data/lib/castle/commands/log.rb +22 -0
  25. data/lib/castle/commands/report_device.rb +17 -0
  26. data/lib/castle/commands/risk.rb +22 -0
  27. data/lib/castle/commands/start_impersonation.rb +25 -0
  28. data/lib/castle/commands/track.rb +12 -13
  29. data/lib/castle/configuration.rb +31 -23
  30. data/lib/castle/context/{default.rb → get_default.rb} +5 -6
  31. data/lib/castle/context/{merger.rb → merge.rb} +3 -3
  32. data/lib/castle/context/prepare.rb +18 -0
  33. data/lib/castle/context/{sanitizer.rb → sanitize.rb} +1 -1
  34. data/lib/castle/core/get_connection.rb +27 -0
  35. data/lib/castle/{api/response.rb → core/process_response.rb} +8 -3
  36. data/lib/castle/core/process_webhook.rb +25 -0
  37. data/lib/castle/core/send_request.rb +42 -0
  38. data/lib/castle/errors.rb +38 -12
  39. data/lib/castle/failover/prepare_response.rb +28 -0
  40. data/lib/castle/failover/strategy.rb +23 -0
  41. data/lib/castle/{extractors/headers.rb → headers/extract.rb} +8 -6
  42. data/lib/castle/headers/filter.rb +40 -0
  43. data/lib/castle/headers/format.rb +24 -0
  44. data/lib/castle/{extractors/ip.rb → ips/extract.rb} +11 -7
  45. data/lib/castle/logger.rb +19 -0
  46. data/lib/castle/payload/prepare.rb +26 -0
  47. data/lib/castle/secure_mode.rb +7 -2
  48. data/lib/castle/session.rb +18 -0
  49. data/lib/castle/singleton_configuration.rb +9 -0
  50. data/lib/castle/support/hanami.rb +2 -6
  51. data/lib/castle/support/rails.rb +1 -3
  52. data/lib/castle/utils/clean_invalid_chars.rb +22 -0
  53. data/lib/castle/utils/clone.rb +15 -0
  54. data/lib/castle/utils/deep_symbolize_keys.rb +45 -0
  55. data/lib/castle/utils/get_timestamp.rb +15 -0
  56. data/lib/castle/utils/{merger.rb → merge.rb} +3 -3
  57. data/lib/castle/utils/secure_compare.rb +22 -0
  58. data/lib/castle/validators/not_supported.rb +1 -0
  59. data/lib/castle/validators/present.rb +1 -0
  60. data/lib/castle/verdict.rb +15 -0
  61. data/lib/castle/version.rb +1 -1
  62. data/lib/castle/webhooks/verify.rb +45 -0
  63. data/spec/integration/rails/rails_spec.rb +42 -14
  64. data/spec/integration/rails/support/application.rb +3 -1
  65. data/spec/integration/rails/support/home_controller.rb +50 -6
  66. data/spec/lib/castle/api/approve_device_spec.rb +21 -0
  67. data/spec/lib/castle/api/authenticate_spec.rb +136 -0
  68. data/spec/lib/castle/api/end_impersonation_spec.rb +65 -0
  69. data/spec/lib/castle/api/filter_spec.rb +5 -0
  70. data/spec/lib/castle/api/get_device_spec.rb +19 -0
  71. data/spec/lib/castle/api/get_devices_for_user_spec.rb +19 -0
  72. data/spec/lib/castle/api/log_spec.rb +5 -0
  73. data/spec/lib/castle/api/report_device_spec.rb +21 -0
  74. data/spec/lib/castle/api/risk_spec.rb +5 -0
  75. data/spec/lib/castle/api/start_impersonation_spec.rb +65 -0
  76. data/spec/lib/castle/api/track_spec.rb +72 -0
  77. data/spec/lib/castle/api_spec.rb +14 -15
  78. data/spec/lib/castle/{extractors/client_id_spec.rb → client_id/extract_spec.rb} +6 -15
  79. data/spec/lib/castle/client_spec.rb +110 -92
  80. data/spec/lib/castle/commands/approve_device_spec.rb +24 -0
  81. data/spec/lib/castle/commands/authenticate_spec.rb +15 -31
  82. data/spec/lib/castle/commands/end_impersonation_spec.rb +79 -0
  83. data/spec/lib/castle/commands/filter_spec.rb +72 -0
  84. data/spec/lib/castle/commands/get_device_spec.rb +24 -0
  85. data/spec/lib/castle/commands/{review_spec.rb → get_devices_for_user_spec.rb} +7 -7
  86. data/spec/lib/castle/commands/log_spec.rb +73 -0
  87. data/spec/lib/castle/commands/report_device_spec.rb +24 -0
  88. data/spec/lib/castle/commands/risk_spec.rb +73 -0
  89. data/spec/lib/castle/commands/{impersonate_spec.rb → start_impersonation_spec.rb} +13 -41
  90. data/spec/lib/castle/commands/track_spec.rb +14 -34
  91. data/spec/lib/castle/configuration_spec.rb +8 -141
  92. data/spec/lib/castle/context/{default_spec.rb → get_default_spec.rb} +9 -10
  93. data/spec/lib/castle/context/{merger_spec.rb → merge_spec.rb} +1 -1
  94. data/spec/lib/castle/context/prepare_spec.rb +43 -0
  95. data/spec/lib/castle/context/{sanitizer_spec.rb → sanitize_spec.rb} +1 -1
  96. data/spec/lib/castle/core/get_connection_spec.rb +43 -0
  97. data/spec/lib/castle/{api/response_spec.rb → core/process_response_spec.rb} +49 -1
  98. data/spec/lib/castle/core/process_webhook_spec.rb +46 -0
  99. data/spec/lib/castle/{api/request_spec.rb → core/send_request_spec.rb} +16 -37
  100. data/spec/lib/castle/failover/strategy_spec.rb +12 -0
  101. data/spec/lib/castle/{extractors/headers_spec.rb → headers/extract_spec.rb} +7 -9
  102. data/spec/lib/castle/headers/filter_spec.rb +39 -0
  103. data/spec/lib/castle/headers/format_spec.rb +25 -0
  104. data/spec/lib/castle/{extractors/ip_spec.rb → ips/extract_spec.rb} +5 -14
  105. data/spec/lib/castle/logger_spec.rb +38 -0
  106. data/spec/lib/castle/payload/prepare_spec.rb +55 -0
  107. data/spec/lib/castle/session_spec.rb +65 -0
  108. data/spec/lib/castle/singleton_configuration_spec.rb +14 -0
  109. data/spec/lib/castle/utils/clean_invalid_chars_spec.rb +69 -0
  110. data/spec/lib/castle/utils/{cloner_spec.rb → clone_spec.rb} +3 -3
  111. data/spec/lib/castle/utils/deep_symbolize_keys_spec.rb +50 -0
  112. data/spec/lib/castle/utils/{timestamp_spec.rb → get_timestamp_spec.rb} +1 -1
  113. data/spec/lib/castle/utils/merge_spec.rb +15 -0
  114. data/spec/lib/castle/validators/present_spec.rb +5 -6
  115. data/spec/lib/castle/verdict_spec.rb +9 -0
  116. data/spec/lib/castle/webhooks/verify_spec.rb +53 -0
  117. data/spec/lib/castle_spec.rb +4 -10
  118. data/spec/spec_helper.rb +3 -3
  119. data/spec/support/shared_examples/action_request.rb +155 -0
  120. data/spec/support/shared_examples/configuration.rb +101 -0
  121. metadata +144 -67
  122. data/lib/castle/api/connection.rb +0 -24
  123. data/lib/castle/api/request.rb +0 -42
  124. data/lib/castle/api/session.rb +0 -20
  125. data/lib/castle/commands/identify.rb +0 -23
  126. data/lib/castle/commands/impersonate.rb +0 -26
  127. data/lib/castle/commands/review.rb +0 -14
  128. data/lib/castle/events.rb +0 -49
  129. data/lib/castle/failover_auth_response.rb +0 -21
  130. data/lib/castle/headers_filter.rb +0 -35
  131. data/lib/castle/headers_formatter.rb +0 -22
  132. data/lib/castle/review.rb +0 -11
  133. data/lib/castle/utils.rb +0 -55
  134. data/lib/castle/utils/cloner.rb +0 -11
  135. data/lib/castle/utils/timestamp.rb +0 -12
  136. data/spec/lib/castle/api/connection_spec.rb +0 -59
  137. data/spec/lib/castle/api/session_spec.rb +0 -86
  138. data/spec/lib/castle/commands/identify_spec.rb +0 -88
  139. data/spec/lib/castle/events_spec.rb +0 -5
  140. data/spec/lib/castle/headers_filter_spec.rb +0 -38
  141. data/spec/lib/castle/headers_formatter_spec.rb +0 -25
  142. data/spec/lib/castle/review_spec.rb +0 -19
  143. data/spec/lib/castle/utils/merger_spec.rb +0 -13
  144. data/spec/lib/castle/utils_spec.rb +0 -156
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 441cbae1aed67e419bff1683c41183abb10c3890d5a159f3365c0b4bd3855f0b
4
- data.tar.gz: 6ef7663b21e2de6b1ef833917dd4b62ee1891f017e33f88a1cb57252e5c3bcc4
3
+ metadata.gz: 774cdc6663639d2a96b9a9a0010bc34bea827edd6b7a42d2f72bb87f94573026
4
+ data.tar.gz: ab2d684474508d1e20fce26dabe1f7594cf255b8682e8b3b1d9b52289d5bab39
5
5
  SHA512:
6
- metadata.gz: b54200b206ea055878d2e4a6b46f82960cda186c4b57009765c7e4c8cce28c7f00c66ad216840f8fa5412a7ed876224f285a18388620bf7df9201425a0efb055
7
- data.tar.gz: cf9f8b5019377138fe5e61ced02b6323aa27464dc117c521fe560a6832115416bbd7e92a64a4710b96939adcd49af12feb538f3d24392d9654b14a21a48021a5
6
+ metadata.gz: 9810ca259c0e26cf3195c8ddc1ca1409256011a89584585dd806ddd6b98efac526de25371b33a7cd122a08f271b0d99c61fe68a8da53714483e85fdc065367db
7
+ data.tar.gz: c89c84e1748f1c8bf06e480d5273bfa8c5003da08b01b74f40d588fc1b0567d3828ea4e0b277d3526fe9a179836e5d86606cd88723cd5e70ecb40b23b925e1f5
data/README.md CHANGED
@@ -62,8 +62,14 @@ Castle.configure do |config|
62
62
  # For authenticate method you can set failover strategies: allow(default), deny, challenge, throw
63
63
  config.failover_strategy = :deny
64
64
 
65
- # Castle::RequestError is raised when timing out in milliseconds (default: 500 milliseconds)
66
- config.request_timeout = 2000
65
+ # Castle::RequestError is raised when timing out in milliseconds (default: 1000 milliseconds)
66
+ config.request_timeout = 1500
67
+
68
+ # Base Castle API url
69
+ # config.base_url = "https://api.castle.io/v1"
70
+
71
+ # Logger (need to respond to info method) - logs Castle API requests and responses
72
+ # config.logger = Logger.new(STDOUT)
67
73
 
68
74
  # Allowlisted and Denylisted headers are case insensitive and allow to use _ and - as a separator, http prefixes are removed
69
75
  # Allowlisted headers
@@ -95,13 +101,14 @@ Castle.configure do |config|
95
101
  # Sometimes, Cloud providers do not use consistent IP addresses to proxy requests.
96
102
  # In this case, the client IP is usually preserved in a custom header. Example:
97
103
  # Cloudflare preserves the client request in the 'Cf-Connecting-Ip' header.
98
- # It would be used like so: configuration.ip_headers=['Cf-Connecting-Ip']
99
- configuration.ip_headers = []
104
+ # It would be used like so: config.ip_headers=['Cf-Connecting-Ip']
105
+ config.ip_headers = []
100
106
 
101
107
  # If the specified header or X-Forwarded-For default contains a proxy chain with public IP addresses,
102
- # then one of the following must be set
103
- # 1. The trusted_proxies value must match the known proxy IP's
104
- # 2. The trusted_proxy_depth value must be set to the number of known trusted proxies in the chain (see below)
108
+ # then you must choose only one of the following (but not both):
109
+ # 1. The trusted_proxies value must match the known proxy IPs. This option is preferable if the IP is static.
110
+ # 2. The trusted_proxy_depth value must be set to the number of known trusted proxies in the chain (see below).
111
+ # This option is preferable if the IPs are ephemeral, but the depth is consistent.
105
112
 
106
113
  # Additionally to make X-Forwarded-For and other headers work better discovering client ip address,
107
114
  # and not the address of a reverse proxy server, you can define trusted proxies
@@ -110,38 +117,60 @@ Castle.configure do |config|
110
117
  # In order to extract the client IP of the X-Forwarded-For header
111
118
  # and not the address of a reverse proxy server, you must define all trusted public proxies
112
119
  # you can achieve this by listing all the proxies ip defined by string or regular expressions
113
- # in trusted_proxies setting
114
- configuration.trusted_proxies = []
120
+ # in the trusted_proxies setting
121
+ config.trusted_proxies = []
115
122
  # or by providing number of trusted proxies used in the chain
116
- configuration.trusted_proxy_depth = 0
123
+ config.trusted_proxy_depth = 0
124
+ # note that you must pick one approach over the other.
117
125
 
118
- # If there is no possibility to define options above and there is no other header which can have client ip
119
- # then you may set trust_proxy_chain = true to trust all of the proxy IP's in X-Forwarded-For
120
- configuration.trust_proxy_chain = false
126
+ # If there is no possibility to define options above and there is no other header that holds the client IP,
127
+ # then you may set trust_proxy_chain = true to trust all of the proxy IPs in X-Forwarded-For
128
+ config.trust_proxy_chain = false
129
+ # *Warning*: this mode is highly promiscuous and could lead to wrongly trusting a spoofed IP if the request passes through a malicious proxy
121
130
 
122
- # *Note: default list of proxies which is always marked as trusted: Castle::Configuration::TRUSTED_PROXIES
131
+ # *Note: the default list of proxies that are always marked as "trusted" can be found in: Castle::Configuration::TRUSTED_PROXIES
123
132
  end
124
133
  ```
125
134
 
135
+ ### Multi-environment configuration
136
+
137
+ It is also possible to define multiple configs within one application.
138
+
139
+ ```ruby
140
+ # Initialize new instance of Castle::Configuration
141
+ config = Castle::Configuration.new.tap do |c|
142
+ # and set any attribute
143
+ c.api_secret = 'YOUR_API_SECRET'
144
+ end
145
+ ```
146
+
147
+ After a successful setup, you can pass the config to any API command as follows:
148
+
149
+ ```ruby
150
+ ::Castle::API::GetDevice.call(device_token: device_token, config: config)
151
+ ```
152
+
126
153
  ## Event Context
127
154
 
128
155
  The client will automatically configure the context for each request.
129
156
 
130
157
  ### Overriding Default Context Properties
131
158
 
132
- If you need to modify the event context properties or if you desire to add additional properties such as user traits to the context, you can pass the properties in as options to the method of interest. An example:
159
+ If you need to modify the event context properties or if you desire to add additional properties such as user traits to the context, you can pass the properties along with the other data. For example:
133
160
  ```ruby
134
- request_context = ::Castle::Client.to_context(request)
135
- track_options = ::Castle::Client.to_options({
136
- event: ::Castle::Events::LOGIN_SUCCEEDED,
161
+ {
162
+ event: '$login.succeeded',
137
163
  user_id: user.id,
138
164
  properties: {
139
165
  key: 'value'
140
166
  },
141
167
  user_traits: {
142
168
  key: 'value'
169
+ },
170
+ context: {
171
+ section: 'mobile'
143
172
  }
144
- })
173
+ }
145
174
  ```
146
175
 
147
176
  ## Tracking
@@ -151,7 +180,7 @@ Here is a simple example of a track event.
151
180
  ```ruby
152
181
  begin
153
182
  castle.track(
154
- event: ::Castle::Events::LOGIN_SUCCEEDED,
183
+ event: '$login.succeeded',
155
184
  user_id: user.id
156
185
  )
157
186
  rescue Castle::Error => e
@@ -173,9 +202,8 @@ By default Castle sends requests synchronously. To eg. use Sidekiq to send reque
173
202
  class CastleTrackingWorker
174
203
  include Sidekiq::Worker
175
204
 
176
- def perform(context, track_options = {})
177
- client = ::Castle::Client.new(context)
178
- client.track(track_options)
205
+ def perform(payload = {})
206
+ ::Castle::API::Track.call(payload)
179
207
  end
180
208
  end
181
209
  ```
@@ -183,18 +211,20 @@ end
183
211
  #### tracking_controller.rb
184
212
 
185
213
  ```ruby
186
- request_context = ::Castle::Client.to_context(request)
187
- track_options = ::Castle::Client.to_options({
188
- event: ::Castle::Events::LOGIN_SUCCEEDED,
189
- user_id: user.id,
190
- properties: {
191
- key: 'value'
214
+ payload = ::Castle::Payload::Prepare.call(
215
+ {
216
+ event: '$login.succeeded',
217
+ user_id: user.id,
218
+ properties: {
219
+ key: 'value'
220
+ },
221
+ user_traits: {
222
+ key: 'value'
223
+ }
192
224
  },
193
- user_traits: {
194
- key: 'value'
195
- }
196
- })
197
- CastleTrackingWorker.perform_async(request_context, track_options)
225
+ request
226
+ )
227
+ CastleTrackingWorker.perform_async(payload)
198
228
  ```
199
229
 
200
230
  ## Connection reuse
@@ -202,14 +232,14 @@ CastleTrackingWorker.perform_async(request_context, track_options)
202
232
  If you want to reuse the connection to send multiple events:
203
233
 
204
234
  ```ruby
205
- Castle::API::Session.call do |http|
235
+ Castle::Session.call do |http|
206
236
  castle.track(
207
- event: ::Castle::Events::LOGOUT_SUCCEEDED,
237
+ event: '$logout.succeeded',
208
238
  user_id: user2.id
209
239
  http: http
210
240
  )
211
241
  castle.track(
212
- event: ::Castle::Events::LOGIN_SUCCEEDED,
242
+ event: '$login.succeeded',
213
243
  user_id: user1.id
214
244
  http: http
215
245
  )
@@ -218,7 +248,41 @@ end
218
248
 
219
249
  ## Events
220
250
 
221
- List of Recognized Events can be found [here](https://github.com/castle/castle-ruby/tree/master/lib/castle/events.rb) or in the [docs](https://docs.castle.io/api_reference/#list-of-recognized-events)
251
+ List of Recognized Events can be found in the [docs](https://docs.castle.io/v1/reference/events/)
252
+
253
+ ## Device management
254
+
255
+ This SDK allows issuing requests to [Castle's Device Management Endpoints](https://docs.castle.io/v1/reference/api-reference/#devices). Use these endpoints for admin-level management of end-user devices (i.e., for an internal dashboard).
256
+
257
+ Fetching device data, approving a device, reporting a device requires a valid `device_token`.
258
+
259
+ ```ruby
260
+ # Get device data
261
+ ::Castle::API::GetDevice.call(device_token: device_token)
262
+ # Approve a device
263
+ ::Castle::API::ApproveDevice.call(device_token: device_token)
264
+ # Report a device
265
+ ::Castle::API::ReportDevice.call(device_token: device_token)
266
+ ```
267
+
268
+ #### castle_device_reporting_worker.rb
269
+
270
+ ```ruby
271
+ class CastleDeviceReportingWorker
272
+ include Sidekiq::Worker
273
+
274
+ def perform(device_token)
275
+ ::Castle::API::ReportDevice.call(device_token: device_token)
276
+ end
277
+ end
278
+ ```
279
+
280
+ Fetching available devices that belong to a given user requires a valid `user_id`.
281
+
282
+ ```ruby
283
+ # Get user's devices data
284
+ ::Castle::API::GetDevicesForUser.call(user_id: user.id)
285
+ ```
222
286
 
223
287
  ## Impersonation mode
224
288
 
@@ -229,6 +293,16 @@ https://castle.io/docs/impersonation_mode
229
293
  `Castle::Error` will be thrown if the Castle API returns a 400 or a 500 level HTTP response.
230
294
  You can also choose to catch a more [finegrained error](https://github.com/castle/castle-ruby/blob/master/lib/castle/errors.rb).
231
295
 
296
+ ## Webhooks
297
+
298
+ Castle uses webhooks to notify about `$incident.confirmed` or `$review.opened` events. Each webhook has `X-Castle-Signature` header that allows verifying webhook's source.
299
+
300
+ ```ruby
301
+ # Verify the webhook, passed as a Request object
302
+ ::Castle::Webhooks::Verify.call(webhook_request)
303
+ # Castle::WebhookVerificationError is raised when the signature is not matching
304
+ ```
305
+
232
306
  ## Documentation
233
307
 
234
- [Official Castle docs](https://castle.io/docs)
308
+ [Official Castle docs](https://docs.castle.io/)
data/lib/castle.rb CHANGED
@@ -1,45 +1,65 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- %w[
4
- openssl
5
- net/http
6
- json
7
- time
8
- ].each(&method(:require))
3
+ %w[openssl net/http json time].each(&method(:require))
9
4
 
10
5
  %w[
11
6
  castle/version
12
- castle/events
7
+ castle/verdict
13
8
  castle/errors
14
9
  castle/command
15
- castle/utils
16
- castle/utils/merger
17
- castle/utils/cloner
18
- castle/utils/timestamp
10
+ castle/utils/deep_symbolize_keys
11
+ castle/utils/clean_invalid_chars
12
+ castle/utils/merge
13
+ castle/utils/clone
14
+ castle/utils/get_timestamp
15
+ castle/utils/secure_compare
19
16
  castle/validators/present
20
17
  castle/validators/not_supported
21
- castle/context/merger
22
- castle/context/sanitizer
23
- castle/context/default
24
- castle/commands/identify
18
+ castle/webhooks/verify
19
+ castle/context/merge
20
+ castle/context/sanitize
21
+ castle/context/get_default
22
+ castle/context/prepare
23
+ castle/commands/approve_device
25
24
  castle/commands/authenticate
25
+ castle/commands/end_impersonation
26
+ castle/commands/filter
27
+ castle/commands/get_device
28
+ castle/commands/get_devices_for_user
29
+ castle/commands/log
30
+ castle/commands/report_device
31
+ castle/commands/risk
32
+ castle/commands/start_impersonation
26
33
  castle/commands/track
27
- castle/commands/review
28
- castle/commands/impersonate
34
+ castle/api/approve_device
35
+ castle/api/authenticate
36
+ castle/api/end_impersonation
37
+ castle/api/filter
38
+ castle/api/get_device
39
+ castle/api/get_devices_for_user
40
+ castle/api/log
41
+ castle/api/report_device
42
+ castle/api/risk
43
+ castle/api/start_impersonation
44
+ castle/api/track
45
+ castle/payload/prepare
29
46
  castle/configuration
30
- castle/failover_auth_response
47
+ castle/singleton_configuration
48
+ castle/logger
49
+ castle/failover/prepare_response
50
+ castle/failover/strategy
31
51
  castle/client
32
- castle/headers_filter
33
- castle/headers_formatter
52
+ castle/headers/filter
53
+ castle/headers/format
54
+ castle/headers/extract
34
55
  castle/secure_mode
35
- castle/extractors/client_id
36
- castle/extractors/headers
37
- castle/extractors/ip
38
- castle/api/connection
39
- castle/api/response
40
- castle/api/request
41
- castle/api/session
42
- castle/review
56
+ castle/client_id/extract
57
+ castle/ips/extract
58
+ castle/core/get_connection
59
+ castle/core/process_response
60
+ castle/core/send_request
61
+ castle/core/process_webhook
62
+ castle/session
43
63
  castle/api
44
64
  ].each(&method(:require))
45
65
 
@@ -55,7 +75,7 @@ module Castle
55
75
  end
56
76
 
57
77
  def config
58
- Configuration.instance
78
+ SingletonConfiguration.instance
59
79
  end
60
80
 
61
81
  def api_secret=(api_secret)
data/lib/castle/api.rb CHANGED
@@ -20,30 +20,34 @@ module Castle
20
20
  # @param command [String]
21
21
  # @param headers [Hash]
22
22
  # @param http [Net::HTTP]
23
- def request(command, headers = {}, http = nil)
24
- raise Castle::ConfigurationError, 'configuration is not valid' unless Castle.config.valid?
23
+ # @param config [Castle::Configuration, Castle::SingletonConfiguration, nil]
24
+ # @return [Hash]
25
+ def call(command, headers = {}, http = nil, config = nil)
26
+ Castle::Core::ProcessResponse.call(send_request(command, headers, http, config), config)
27
+ end
28
+
29
+ private
30
+
31
+ # @param command [String]
32
+ # @param headers [Hash]
33
+ # @param http [Net::HTTP]
34
+ # @param config [Castle::Configuration, Castle::SingletonConfiguration]
35
+ def send_request(command, headers = {}, http = nil, config = nil)
36
+ config ||= Castle.config
37
+
38
+ raise Castle::ConfigurationError, 'configuration is not valid' unless config.valid?
25
39
 
26
40
  begin
27
- Castle::API::Request.call(
28
- command,
29
- Castle.config.api_secret,
30
- headers,
31
- http
32
- )
41
+ Castle::Core::SendRequest.call(command, headers, http, config)
33
42
  rescue *HANDLED_ERRORS => e
34
43
  # @note We need to initialize the error, as the original error is a cause for this
35
44
  # custom exception. If we would do it the default Ruby way, the original error
36
45
  # would get converted into a string
37
- raise Castle::RequestError.new(e) # rubocop:disable Style/RaiseArgs
46
+ # rubocop:disable Style/RaiseArgs
47
+ raise Castle::RequestError.new(e)
48
+ # rubocop:enable Style/RaiseArgs
38
49
  end
39
50
  end
40
-
41
- # @param command [String]
42
- # @param headers [Hash]
43
- # @param http [Net::HTTP]
44
- def call(command, headers = {}, http = nil)
45
- Castle::API::Response.call(request(command, headers, http))
46
- end
47
51
  end
48
52
  end
49
53
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Castle
4
+ module API
5
+ # Sends PUT devices/#{device_token}/approve request
6
+ module ApproveDevice
7
+ class << self
8
+ # @param options [Hash]
9
+ # return [Hash]
10
+ def call(options = {})
11
+ options = Castle::Utils::DeepSymbolizeKeys.call(options || {})
12
+ http = options.delete(:http)
13
+ config = options.delete(:config) || Castle.config
14
+
15
+ Castle::API.call(Castle::Commands::ApproveDevice.build(options), {}, http, config)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Castle
4
+ module API
5
+ module Authenticate
6
+ class << self
7
+ # @param options [Hash]
8
+ # return [Hash]
9
+ def call(options = {})
10
+ unless options[:no_symbolize]
11
+ options = Castle::Utils::DeepSymbolizeKeys.call(options || {})
12
+ end
13
+ options.delete(:no_symbolize)
14
+ http = options.delete(:http)
15
+ config = options.delete(:config) || Castle.config
16
+
17
+ response =
18
+ Castle::API.call(Castle::Commands::Authenticate.build(options), {}, http, config)
19
+ response.merge(failover: false, failover_reason: nil)
20
+ rescue Castle::RequestError, Castle::InternalServerError => e
21
+ unless config.failover_strategy == :throw
22
+ strategy = (config || Castle.config).failover_strategy
23
+ return(
24
+ Castle::Failover::PrepareResponse.new(
25
+ options[:user_id],
26
+ reason: e.to_s,
27
+ strategy: strategy
28
+ ).call
29
+ )
30
+ end
31
+
32
+ raise e
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end