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
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Castle
|
4
|
+
module Payload
|
5
|
+
# prepares payload based on the request
|
6
|
+
module Prepare
|
7
|
+
class << self
|
8
|
+
# @param payload_options [Hash]
|
9
|
+
# @param request [Request]
|
10
|
+
# @param options [Hash] required for context preparation
|
11
|
+
# @return [Hash]
|
12
|
+
def call(payload_options, request, options = {})
|
13
|
+
context = Castle::Context::Prepare.call(request, payload_options.merge(options))
|
14
|
+
|
15
|
+
payload =
|
16
|
+
Castle::Utils::DeepSymbolizeKeys.call(payload_options || {}).merge(context: context)
|
17
|
+
payload[:timestamp] ||= Castle::Utils::GetTimestamp.call
|
18
|
+
|
19
|
+
warn '[DEPRECATION] use user_traits instead of traits key' if payload.key?(:traits)
|
20
|
+
|
21
|
+
payload
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/castle/secure_mode.rb
CHANGED
@@ -4,8 +4,13 @@ require 'openssl'
|
|
4
4
|
|
5
5
|
module Castle
|
6
6
|
module SecureMode
|
7
|
-
|
8
|
-
|
7
|
+
class << self
|
8
|
+
# @param user_id [String]
|
9
|
+
# @param config [Castle::Configuration, Castle::SingletonConfiguration, nil]
|
10
|
+
def signature(user_id, config = nil)
|
11
|
+
config ||= Castle.config
|
12
|
+
OpenSSL::HMAC.hexdigest('sha256', config.api_secret, user_id.to_s)
|
13
|
+
end
|
9
14
|
end
|
10
15
|
end
|
11
16
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Castle
|
4
|
+
# this module uses the Connection object
|
5
|
+
# and provides start method for persistent connection usage
|
6
|
+
# when there is a need of sending multiple requests at once
|
7
|
+
module Session
|
8
|
+
HTTPS_SCHEME = 'https'
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def call(&block)
|
12
|
+
return unless block_given?
|
13
|
+
|
14
|
+
Castle::Core::GetConnection.call.start(&block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,16 +4,12 @@ module Castle
|
|
4
4
|
module Hanami
|
5
5
|
module Action
|
6
6
|
def castle
|
7
|
-
@castle ||= ::Castle::Client.from_request(request, cookies: (cookies if defined?
|
7
|
+
@castle ||= ::Castle::Client.from_request(request, cookies: (cookies if defined?(cookies)))
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.included(base)
|
12
|
-
base.configure
|
13
|
-
controller.prepare do
|
14
|
-
include Castle::Hanami::Action
|
15
|
-
end
|
16
|
-
end
|
12
|
+
base.configure { controller.prepare { include Castle::Hanami::Action } }
|
17
13
|
end
|
18
14
|
end
|
19
15
|
end
|
data/lib/castle/support/rails.rb
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Castle
|
4
|
+
module Utils
|
5
|
+
module CleanInvalidChars
|
6
|
+
class << self
|
7
|
+
def call(arg)
|
8
|
+
case arg
|
9
|
+
when ::String
|
10
|
+
arg.encode('UTF-8', invalid: :replace, undef: :replace)
|
11
|
+
when ::Hash
|
12
|
+
arg.transform_values { |v| Castle::Utils::CleanInvalidChars.call(v) }
|
13
|
+
when ::Array
|
14
|
+
arg.map { |el| Castle::Utils::CleanInvalidChars.call(el) }
|
15
|
+
else
|
16
|
+
arg
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Castle
|
4
|
+
module Utils
|
5
|
+
module DeepSymbolizeKeys
|
6
|
+
class << self
|
7
|
+
# Returns a new hash with all keys converted to symbols, as long as
|
8
|
+
# they respond to +to_sym+. This includes the keys from the root hash
|
9
|
+
# and from all nested hashes and arrays.
|
10
|
+
#
|
11
|
+
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
|
12
|
+
#
|
13
|
+
# Castle::Hash.deep_symbolize_keys(hash)
|
14
|
+
# # => {:person=>{:name=>"Rob", :age=>"28"}}
|
15
|
+
def call(object, &block)
|
16
|
+
case object
|
17
|
+
when Hash
|
18
|
+
object.each_with_object({}) do |(key, value), result|
|
19
|
+
result[key.to_sym] = Castle::Utils::DeepSymbolizeKeys.call(value, &block)
|
20
|
+
end
|
21
|
+
when Array
|
22
|
+
object.map { |e| Castle::Utils::DeepSymbolizeKeys.call(e, &block) }
|
23
|
+
else
|
24
|
+
object
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def call!(object, &block)
|
29
|
+
case object
|
30
|
+
when Hash
|
31
|
+
object.each_key do |key|
|
32
|
+
value = object.delete(key)
|
33
|
+
object[key.to_sym] = Castle::Utils::DeepSymbolizeKeys.call!(value, &block)
|
34
|
+
end
|
35
|
+
object
|
36
|
+
when Array
|
37
|
+
object.map! { |e| Castle::Utils::DeepSymbolizeKeys.call!(e, &block) }
|
38
|
+
else
|
39
|
+
object
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Castle
|
4
|
+
module Utils
|
5
|
+
# Generates a timestamp
|
6
|
+
class GetTimestamp
|
7
|
+
class << self
|
8
|
+
# Returns current time as ISO8601 formatted string
|
9
|
+
def call
|
10
|
+
Time.now.utc.iso8601(3)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
module Castle
|
4
4
|
module Utils
|
5
|
-
class
|
5
|
+
class Merge
|
6
6
|
def self.call(base, extra)
|
7
|
-
base_s = Castle::Utils.
|
8
|
-
extra_s = Castle::Utils.
|
7
|
+
base_s = Castle::Utils::DeepSymbolizeKeys.call(base)
|
8
|
+
extra_s = Castle::Utils::DeepSymbolizeKeys.call(extra)
|
9
9
|
|
10
10
|
extra_s.each do |name, value|
|
11
11
|
if value.nil?
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Castle
|
4
|
+
module Utils
|
5
|
+
# Code borrowed from ActiveSupport
|
6
|
+
class SecureCompare
|
7
|
+
class << self
|
8
|
+
# @param str_a [String] first string to be compared
|
9
|
+
# @param str_b [String] second string to be compared
|
10
|
+
def call(str_a, str_b)
|
11
|
+
return false unless str_a.bytesize == str_b.bytesize
|
12
|
+
|
13
|
+
l = str_a.unpack "C#{str_a.bytesize}"
|
14
|
+
|
15
|
+
res = 0
|
16
|
+
str_b.each_byte { |byte| res |= byte ^ l.shift }
|
17
|
+
res.zero?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/castle/version.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Castle
|
4
|
+
module Webhooks
|
5
|
+
# Verify a webhook
|
6
|
+
class Verify
|
7
|
+
class << self
|
8
|
+
# Checks if webhook is valid
|
9
|
+
# @param webhook [Request]
|
10
|
+
# @param config [Castle::Configuration, Castle::SingletonConfiguration, nil]
|
11
|
+
def call(webhook, config = nil)
|
12
|
+
config ||= Castle.config
|
13
|
+
expected_signature = compute_signature(webhook, config)
|
14
|
+
signature = webhook.env['HTTP_X_CASTLE_SIGNATURE']
|
15
|
+
verify_signature(signature, expected_signature)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Computes a webhook signature using provided user_id
|
21
|
+
# @param webhook [Request]
|
22
|
+
# @param config [Castle::Configuration, Castle::SingletonConfiguration]
|
23
|
+
# @return [String]
|
24
|
+
def compute_signature(webhook, config)
|
25
|
+
Base64.encode64(
|
26
|
+
OpenSSL::HMAC.digest(
|
27
|
+
OpenSSL::Digest.new('sha256'),
|
28
|
+
config.api_secret,
|
29
|
+
Castle::Core::ProcessWebhook.call(webhook, config)
|
30
|
+
)
|
31
|
+
).strip
|
32
|
+
end
|
33
|
+
|
34
|
+
# Check if the signatures are matching
|
35
|
+
# @param signature [String] first signature to be compared
|
36
|
+
# @param expected_signature [String] second signature to be compared
|
37
|
+
def verify_signature(signature, expected_signature)
|
38
|
+
return if Castle::Utils::SecureCompare.call(signature, expected_signature)
|
39
|
+
|
40
|
+
raise Castle::WebhookVerificationError, 'Signature not matching the expected signature'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -4,21 +4,25 @@ require 'spec_helper'
|
|
4
4
|
require_relative 'support/all'
|
5
5
|
|
6
6
|
RSpec.describe HomeController, type: :request do
|
7
|
-
|
7
|
+
context 'with index pages' do
|
8
8
|
let(:request) do
|
9
9
|
{
|
10
10
|
'event' => '$login.succeeded',
|
11
11
|
'user_id' => '123',
|
12
|
-
'properties' => {
|
13
|
-
|
12
|
+
'properties' => {
|
13
|
+
'key' => 'value'
|
14
|
+
},
|
15
|
+
'user_traits' => {
|
16
|
+
'key' => 'value'
|
17
|
+
},
|
14
18
|
'timestamp' => now.utc.iso8601(3),
|
15
19
|
'sent_at' => now.utc.iso8601(3),
|
16
20
|
'context' => {
|
17
21
|
'client_id' => '',
|
18
22
|
'active' => true,
|
19
|
-
'origin' => 'web',
|
20
23
|
'headers' => {
|
21
|
-
'Accept' =>
|
24
|
+
'Accept' =>
|
25
|
+
'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5',
|
22
26
|
'Authorization' => true,
|
23
27
|
'Content-Length' => '0',
|
24
28
|
'Cookie' => true,
|
@@ -36,26 +40,50 @@ RSpec.describe HomeController, type: :request do
|
|
36
40
|
end
|
37
41
|
let(:now) { Time.now }
|
38
42
|
let(:headers) do
|
39
|
-
{
|
40
|
-
'HTTP_AUTHORIZATION' => 'Basic 123',
|
41
|
-
'HTTP_X_FORWARDED_FOR' => '5.5.5.5, 1.2.3.4'
|
42
|
-
}
|
43
|
+
{ 'HTTP_AUTHORIZATION' => 'Basic 123', 'HTTP_X_FORWARDED_FOR' => '5.5.5.5, 1.2.3.4' }
|
43
44
|
end
|
44
45
|
|
45
46
|
before do
|
46
47
|
Timecop.freeze(now)
|
47
48
|
stub_request(:post, 'https://api.castle.io/v1/track')
|
48
|
-
get '/', headers: headers
|
49
49
|
end
|
50
50
|
|
51
51
|
after { Timecop.return }
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
describe '#index1' do
|
54
|
+
before { get '/index1', headers: headers }
|
55
|
+
|
56
|
+
it do
|
57
|
+
assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
|
58
|
+
JSON.parse(req.body) == request
|
59
|
+
end
|
56
60
|
end
|
61
|
+
|
62
|
+
it { expect(response).to be_successful }
|
57
63
|
end
|
58
64
|
|
59
|
-
|
65
|
+
describe '#index2' do
|
66
|
+
before { get '/index2', headers: headers }
|
67
|
+
|
68
|
+
it do
|
69
|
+
assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
|
70
|
+
JSON.parse(req.body) == request
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it { expect(response).to be_successful }
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#index3' do
|
78
|
+
before { get '/index3', headers: headers }
|
79
|
+
|
80
|
+
it do
|
81
|
+
assert_requested :post, 'https://api.castle.io/v1/track', times: 1 do |req|
|
82
|
+
JSON.parse(req.body) == request
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it { expect(response).to be_successful }
|
87
|
+
end
|
60
88
|
end
|
61
89
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class HomeController < ActionController::Base
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
# prepare context and calling track with client example
|
5
|
+
def index1
|
6
|
+
request_context = ::Castle::Context::Prepare.call(request)
|
7
|
+
payload = {
|
7
8
|
event: '$login.succeeded',
|
8
9
|
user_id: '123',
|
9
10
|
properties: {
|
@@ -12,9 +13,52 @@ class HomeController < ActionController::Base
|
|
12
13
|
user_traits: {
|
13
14
|
key: 'value'
|
14
15
|
}
|
15
|
-
|
16
|
-
client = ::Castle::Client.new(request_context)
|
17
|
-
client.track(
|
16
|
+
}
|
17
|
+
client = ::Castle::Client.new(context: request_context)
|
18
|
+
client.track(payload)
|
19
|
+
|
20
|
+
render inline: 'hello'
|
21
|
+
end
|
22
|
+
|
23
|
+
# prepare payload and calling track with client example
|
24
|
+
def index2
|
25
|
+
payload =
|
26
|
+
::Castle::Payload::Prepare.call(
|
27
|
+
{
|
28
|
+
event: '$login.succeeded',
|
29
|
+
user_id: '123',
|
30
|
+
properties: {
|
31
|
+
key: 'value'
|
32
|
+
},
|
33
|
+
user_traits: {
|
34
|
+
key: 'value'
|
35
|
+
}
|
36
|
+
},
|
37
|
+
request
|
38
|
+
)
|
39
|
+
client = ::Castle::Client.new
|
40
|
+
client.track(payload)
|
41
|
+
|
42
|
+
render inline: 'hello'
|
43
|
+
end
|
44
|
+
|
45
|
+
# prepare payload and calling track with direct API::Track service
|
46
|
+
def index3
|
47
|
+
payload =
|
48
|
+
::Castle::Payload::Prepare.call(
|
49
|
+
{
|
50
|
+
event: '$login.succeeded',
|
51
|
+
user_id: '123',
|
52
|
+
properties: {
|
53
|
+
key: 'value'
|
54
|
+
},
|
55
|
+
user_traits: {
|
56
|
+
key: 'value'
|
57
|
+
}
|
58
|
+
},
|
59
|
+
request
|
60
|
+
)
|
61
|
+
Castle::API::Track.call(payload)
|
18
62
|
|
19
63
|
render inline: 'hello'
|
20
64
|
end
|