securenative 0.1.17 → 0.1.18

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 (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +5 -2
  3. data/.github/workflows/test.yml +5 -2
  4. data/.gitignore +3 -1
  5. data/Gemfile +5 -2
  6. data/Gemfile.lock +218 -10
  7. data/README.md +3 -3
  8. data/VERSION +1 -1
  9. data/lib/api_manager.rb +35 -0
  10. data/lib/config/configuration_builder.rb +30 -0
  11. data/lib/config/configuration_manager.rb +55 -0
  12. data/lib/config/securenative_options.rb +22 -0
  13. data/lib/context/hanami_context.rb +35 -0
  14. data/lib/context/rails_context.rb +41 -0
  15. data/lib/context/securenative_context.rb +67 -0
  16. data/lib/context/sinatra_context.rb +35 -0
  17. data/lib/enums/api_route.rb +6 -0
  18. data/lib/enums/event_types.rb +23 -0
  19. data/lib/enums/failover_strategy.rb +6 -0
  20. data/lib/enums/risk_level.rb +7 -0
  21. data/lib/errors/securenative_config_error.rb +4 -0
  22. data/lib/errors/securenative_http_error.rb +4 -0
  23. data/lib/errors/securenative_invalid_options_error.rb +4 -0
  24. data/lib/errors/securenative_invalid_uri_error.rb +4 -0
  25. data/lib/errors/securenative_parse_error.rb +4 -0
  26. data/lib/errors/securenative_sdk_Illegal_state_error.rb +4 -0
  27. data/lib/errors/securenative_sdk_error.rb +4 -0
  28. data/lib/event_manager.rb +156 -0
  29. data/lib/{securenative/event_options_builder.rb → event_options.rb} +5 -3
  30. data/lib/http/secure_native_http_response.rb +12 -0
  31. data/lib/http/securenative_http_client.rb +32 -0
  32. data/lib/{securenative/models → models}/client_token.rb +2 -0
  33. data/lib/{securenative/models → models}/device.rb +3 -1
  34. data/lib/models/event_options.rb +15 -0
  35. data/lib/models/request_context.rb +18 -0
  36. data/lib/models/request_options.rb +12 -0
  37. data/lib/models/sdk_event.rb +35 -0
  38. data/lib/models/user_traits.rb +13 -0
  39. data/lib/models/verify_result.rb +12 -0
  40. data/lib/securenative.rb +95 -0
  41. data/lib/utils/date_utils.rb +9 -0
  42. data/lib/{securenative/utils → utils}/encryption_utils.rb +1 -4
  43. data/lib/{securenative/utils → utils}/ip_utils.rb +7 -6
  44. data/lib/utils/request_utils.rb +54 -0
  45. data/lib/{securenative/logger.rb → utils/secure_native_logger.rb} +5 -3
  46. data/lib/{securenative/utils → utils}/signature_utils.rb +4 -2
  47. data/lib/utils/utils.rb +9 -0
  48. data/lib/{securenative/utils → utils}/version_utils.rb +3 -1
  49. data/{lib/securenative → out/production/securenative-ruby}/api_manager.rb +6 -5
  50. data/{lib/securenative → out/production/securenative-ruby}/config/configuration_builder.rb +7 -3
  51. data/{lib/securenative → out/production/securenative-ruby}/config/configuration_manager.rb +5 -3
  52. data/{lib/securenative → out/production/securenative-ruby}/config/securenative_options.rb +3 -1
  53. data/out/production/securenative-ruby/context/securenative_context.rb +40 -0
  54. data/out/production/securenative-ruby/enums/api_route.rb +6 -0
  55. data/out/production/securenative-ruby/enums/event_types.rb +23 -0
  56. data/out/production/securenative-ruby/enums/failover_strategy.rb +6 -0
  57. data/out/production/securenative-ruby/enums/risk_level.rb +7 -0
  58. data/out/production/securenative-ruby/errors/securenative_config_error.rb +4 -0
  59. data/out/production/securenative-ruby/errors/securenative_http_error.rb +4 -0
  60. data/out/production/securenative-ruby/errors/securenative_invalid_options_error.rb +4 -0
  61. data/out/production/securenative-ruby/errors/securenative_invalid_uri_error.rb +4 -0
  62. data/out/production/securenative-ruby/errors/securenative_parse_error.rb +4 -0
  63. data/out/production/securenative-ruby/errors/securenative_sdk_Illegal_state_error.rb +4 -0
  64. data/out/production/securenative-ruby/errors/securenative_sdk_error.rb +4 -0
  65. data/out/production/securenative-ruby/event_manager.rb +156 -0
  66. data/out/production/securenative-ruby/event_options.rb +32 -0
  67. data/{lib/securenative → out/production/securenative-ruby}/http/http_response.rb +3 -1
  68. data/out/production/securenative-ruby/http/securenative_http_client.rb +32 -0
  69. data/out/production/securenative-ruby/models/client_token.rb +12 -0
  70. data/out/production/securenative-ruby/models/device.rb +10 -0
  71. data/{lib/securenative → out/production/securenative-ruby}/models/event_options.rb +3 -1
  72. data/{lib/securenative → out/production/securenative-ruby}/models/request_context.rb +5 -2
  73. data/out/production/securenative-ruby/models/request_options.rb +12 -0
  74. data/{lib/securenative → out/production/securenative-ruby}/models/sdk_event.rb +11 -3
  75. data/{lib/securenative → out/production/securenative-ruby}/models/user_traits.rb +3 -1
  76. data/{lib/securenative → out/production/securenative-ruby}/models/verify_result.rb +3 -1
  77. data/{lib/securenative → out/production/securenative-ruby}/securenative.rb +24 -15
  78. data/out/production/securenative-ruby/utils/date_utils.rb +9 -0
  79. data/out/production/securenative-ruby/utils/encryption_utils.rb +35 -0
  80. data/out/production/securenative-ruby/utils/ip_utils.rb +23 -0
  81. data/{lib/securenative → out/production/securenative-ruby}/utils/request_utils.rb +5 -3
  82. data/out/production/securenative-ruby/utils/secure_native_logger.rb +44 -0
  83. data/out/production/securenative-ruby/utils/signature_utils.rb +16 -0
  84. data/out/production/securenative-ruby/utils/utils.rb +9 -0
  85. data/out/production/securenative-ruby/utils/version_utils.rb +12 -0
  86. data/out/test/securenative-ruby/spec_api_manager.rb +81 -0
  87. data/out/test/securenative-ruby/spec_context_builder.rb +69 -0
  88. data/out/test/securenative-ruby/spec_date_utils.rb +13 -0
  89. data/out/test/securenative-ruby/spec_encryption_utils.rb +26 -0
  90. data/out/test/securenative-ruby/spec_event_manager.rb +59 -0
  91. data/out/test/securenative-ruby/spec_helper.rb +20 -0
  92. data/out/test/securenative-ruby/spec_ip_utils.rb +41 -0
  93. data/out/test/securenative-ruby/spec_securenative.rb +65 -0
  94. data/out/test/securenative-ruby/spec_securenative_http_client.rb +23 -0
  95. data/out/test/securenative-ruby/spec_signature_utils.rb +18 -0
  96. data/securenative.gemspec +1 -1
  97. metadata +89 -42
  98. data/.travis.yml +0 -6
  99. data/lib/securenative/context/context_builder.rb +0 -59
  100. data/lib/securenative/context/securenative_context.rb +0 -14
  101. data/lib/securenative/enums/api_route.rb +0 -4
  102. data/lib/securenative/enums/event_types.rb +0 -21
  103. data/lib/securenative/enums/failover_strategy.rb +0 -4
  104. data/lib/securenative/enums/risk_level.rb +0 -5
  105. data/lib/securenative/event_manager.rb +0 -150
  106. data/lib/securenative/exceptions/securenative_config_exception.rb +0 -2
  107. data/lib/securenative/exceptions/securenative_http_exception.rb +0 -2
  108. data/lib/securenative/exceptions/securenative_invalid_options_exception.rb +0 -2
  109. data/lib/securenative/exceptions/securenative_invalid_uri_exception.rb +0 -2
  110. data/lib/securenative/exceptions/securenative_parse_exception.rb +0 -2
  111. data/lib/securenative/exceptions/securenative_sdk_Illegal_state_exception.rb +0 -2
  112. data/lib/securenative/exceptions/securenative_sdk_exception.rb +0 -2
  113. data/lib/securenative/http/securenative_http_client.rb +0 -30
  114. data/lib/securenative/models/request_options.rb +0 -10
  115. data/lib/securenative/securenative.iml +0 -9
  116. data/lib/securenative/utils/date_utils.rb +0 -7
  117. data/lib/securenative/utils/utils.rb +0 -9
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parseconfig'
4
+
5
+ class ConfigurationManager
6
+ DEFAULT_CONFIG_FILE = 'securenative.cfg'
7
+ CUSTOM_CONFIG_FILE_ENV_NAME = 'SECURENATIVE_CONFIG_FILE'
8
+ @config = nil
9
+
10
+ def self.read_resource_file(resource_path)
11
+ @config = ParseConfig.new(resource_path)
12
+
13
+ properties = {}
14
+ @config.get_groups.each do |group|
15
+ group.each do |key, value|
16
+ properties[key.upcase] = value
17
+ end
18
+ end
19
+ properties
20
+ end
21
+
22
+ def self._get_resource_path(env_name)
23
+ Env.fetch(env_name, ENV[DEFAULT_CONFIG_FILE])
24
+ end
25
+
26
+ def self.config_builder
27
+ ConfigurationBuilder.default_config_builder
28
+ end
29
+
30
+ def self._get_env_or_default(properties, key, default)
31
+ return Env[key] if Env[key]
32
+ return properties[key] if properties[key]
33
+
34
+ default
35
+ end
36
+
37
+ def self.load_config
38
+ options = ConfigurationBuilder().default_securenative_options
39
+
40
+ resource_path = DEFAULT_CONFIG_FILE
41
+ resource_path = Env[CUSTOM_CONFIG_FILE_ENV_NAME] if Env[CUSTOM_CONFIG_FILE_ENV_NAME]
42
+
43
+ properties = read_resource_file(resource_path)
44
+
45
+ ConfigurationBuilder(_get_env_or_default(properties, 'SECURENATIVE_API_KEY', options.api_key),
46
+ _get_env_or_default(properties, 'SECURENATIVE_API_URL', options.api_url),
47
+ _get_env_or_default(properties, 'SECURENATIVE_INTERVAL', options.interval),
48
+ _get_env_or_default(properties, 'SECURENATIVE_MAX_EVENTS', options.max_events),
49
+ _get_env_or_default(properties, 'SECURENATIVE_TIMEOUT', options.timeout),
50
+ _get_env_or_default(properties, 'SECURENATIVE_AUTO_SEND', options.auto_send),
51
+ _get_env_or_default(properties, 'SECURENATIVE_DISABLE', options.disable),
52
+ _get_env_or_default(properties, 'SECURENATIVE_LOG_LEVEL', options.log_level),
53
+ _get_env_or_default(properties, 'SECURENATIVE_FAILOVER_STRATEGY', options.fail_over_strategy))
54
+ end
55
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'enums/failover_strategy'
4
+
5
+ class SecureNativeOptions
6
+ attr_reader :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
7
+ attr_writer :api_key, :api_url, :interval, :max_events, :timeout, :auto_send, :disable, :log_level, :fail_over_strategy
8
+
9
+ def initialize(api_key: nil, api_url: "https://api.securenative.com/collector/api/v1", interval: 1000,
10
+ max_events: 1000, timeout: 1500, auto_send: true, disable: false, log_level: "FATAL",
11
+ fail_over_strategy: FailOverStrategy::FAIL_OPEN)
12
+ @api_key = api_key
13
+ @api_url = api_url
14
+ @interval = interval
15
+ @max_events = max_events
16
+ @timeout = timeout
17
+ @auto_send = auto_send
18
+ @disable = disable
19
+ @log_level = log_level
20
+ @fail_over_strategy = fail_over_strategy
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HanamiContext
4
+ def self.get_client_token(request)
5
+ begin
6
+ request.env[SECURENATIVE_COOKIE]
7
+ rescue StandardError
8
+ nil
9
+ end
10
+ end
11
+
12
+ def self.get_url(request)
13
+ begin
14
+ request.env['REQUEST_PATH']
15
+ rescue StandardError
16
+ nil
17
+ end
18
+ end
19
+
20
+ def self.get_method(request)
21
+ begin
22
+ request.request_method
23
+ rescue StandardError
24
+ nil
25
+ end
26
+ end
27
+
28
+ def self.get_headers(request)
29
+ begin
30
+ request.headers.to_hash
31
+ rescue StandardError
32
+ nil
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RailsContext
4
+ def self.get_client_token(request)
5
+ begin
6
+ request.cookies[SECURENATIVE_COOKIE]
7
+ rescue StandardError
8
+ nil
9
+ end
10
+ end
11
+
12
+ def self.get_url(request)
13
+ begin
14
+ # Rails >= 3.x
15
+ request.fullpath
16
+ rescue StandardError
17
+ begin
18
+ # Rails < 3.x & Sinatra
19
+ request.url if url.nil?
20
+ rescue StandardError
21
+ nil
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.get_method(request)
27
+ begin
28
+ request.method
29
+ rescue StandardError
30
+ nil
31
+ end
32
+ end
33
+
34
+ def self.get_headers(request)
35
+ begin
36
+ request.headers.to_hash
37
+ rescue StandardError
38
+ nil
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'utils/request_utils'
4
+ require 'utils/utils'
5
+ require 'context/rails_context'
6
+ require 'context/hanami_context'
7
+ require 'context/sinatra_context'
8
+
9
+ class SecureNativeContext
10
+ attr_reader :client_token, :ip, :remote_ip, :headers, :url, :http_method, :body
11
+ attr_writer :client_token, :ip, :remote_ip, :headers, :url, :http_method, :body
12
+
13
+ SECURENATIVE_COOKIE = '_sn'
14
+
15
+ def initialize(client_token: nil, ip: nil, remote_ip: nil, headers: nil, url: nil, http_method: nil, body: nil)
16
+ @client_token = client_token
17
+ @ip = ip
18
+ @remote_ip = remote_ip
19
+ @headers = headers
20
+ @url = url
21
+ @http_method = http_method
22
+ @body = body
23
+ end
24
+
25
+ def self.default_context_builder
26
+ SecureNativeContext.new
27
+ end
28
+
29
+ def self.from_http_request(request)
30
+ client_token = RailsContext.get_client_token(request)
31
+ client_token = SinatraContext.get_client_token(request) if client_token.nil?
32
+ client_token = HanamiContext.get_client_token(request) if client_token.nil?
33
+
34
+ begin
35
+ headers = RailsContext.get_headers(request)
36
+ headers = SinatraContext.get_headers(request) if headers.nil?
37
+ headers = HanamiContext.get_headers(request) if headers.nil?
38
+
39
+ # Standard Ruby request
40
+ headers = request.header.to_hash if headers.nil?
41
+ rescue StandardError
42
+ headers = []
43
+ end
44
+
45
+ url = RailsContext.get_url(request)
46
+ url = SinatraContext.get_url(request) if url.nil?
47
+ url = HanamiContext.get_url(request) if url.nil?
48
+ url = '' if url.nil?
49
+
50
+ method = RailsContext.get_method(request)
51
+ method = SinatraContext.get_method(request) if method.nil?
52
+ method = HanamiContext.get_method(request) if method.nil?
53
+ method = '' if method.nil?
54
+
55
+ begin
56
+ body = request.body.to_s
57
+ rescue StandardError
58
+ body = ''
59
+ end
60
+
61
+ client_token = RequestUtils.get_secure_header_from_request(headers) if Utils.null_or_empty?(client_token)
62
+
63
+ SecureNativeContext.new(client_token: client_token, ip: RequestUtils.get_client_ip_from_request(request),
64
+ remote_ip: RequestUtils.get_remote_ip_from_request(request),
65
+ headers: headers, url: url, http_method: method || '', body: body)
66
+ end
67
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SinatraContext
4
+ def self.get_client_token(request)
5
+ begin
6
+ request.env[SECURENATIVE_COOKIE]
7
+ rescue StandardError
8
+ nil
9
+ end
10
+ end
11
+
12
+ def self.get_url(request)
13
+ begin
14
+ request.url
15
+ rescue StandardError
16
+ nil
17
+ end
18
+ end
19
+
20
+ def self.get_method(request)
21
+ begin
22
+ request.method
23
+ rescue StandardError
24
+ nil
25
+ end
26
+ end
27
+
28
+ def self.get_headers(request)
29
+ begin
30
+ request.headers.to_hash
31
+ rescue StandardError
32
+ nil
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiRoute
4
+ TRACK = 'track'
5
+ VERIFY = 'verify'
6
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EventTypes
4
+ LOG_IN = 'sn.user.login'
5
+ LOG_IN_CHALLENGE = 'sn.user.login.challenge'
6
+ LOG_IN_FAILURE = 'sn.user.login.failure'
7
+ LOG_OUT = 'sn.user.logout'
8
+ SIGN_UP = 'sn.user.signup'
9
+ AUTH_CHALLENGE = 'sn.user.auth.challenge'
10
+ AUTH_CHALLENGE_SUCCESS = 'sn.user.auth.challenge.success'
11
+ AUTH_CHALLENGE_FAILURE = 'sn.user.auth.challenge.failure'
12
+ TWO_FACTOR_DISABLE = 'sn.user.2fa.disable'
13
+ EMAIL_UPDATE = 'sn.user.email.update'
14
+ PASSWORD_REST = 'sn.user.password.reset'
15
+ PASSWORD_REST_SUCCESS = 'sn.user.password.reset.success'
16
+ PASSWORD_UPDATE = 'sn.user.password.update'
17
+ PASSWORD_REST_FAILURE = 'sn.user.password.reset.failure'
18
+ USER_INVITE = 'sn.user.invite'
19
+ ROLE_UPDATE = 'sn.user.role.update'
20
+ PROFILE_UPDATE = 'sn.user.profile.update'
21
+ PAGE_VIEW = 'sn.user.page.view'
22
+ VERIFY = 'sn.verify'
23
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FailOverStrategy
4
+ FAIL_OPEN = 'fail-open'
5
+ FAIL_CLOSED = 'fail-closed'
6
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RiskLevel
4
+ LOW = 'low'
5
+ MEDIUM = 'medium'
6
+ HIGH = 'high'
7
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SecureNativeConfigError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SecureNativeHttpError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SecureNativeInvalidOptionsError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SecureNativeInvalidUriError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SecureNativeParseError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SecureNativeSDKIllegalStateError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SecureNativeSDKError < StandardError
4
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'utils/secure_native_logger'
4
+ require 'config/securenative_options'
5
+ require 'http/securenative_http_client'
6
+ require 'errors/securenative_sdk_error'
7
+
8
+ class QueueItem
9
+ attr_reader :url, :body, :retry_sending
10
+ attr_writer :url, :body, :retry_sending
11
+
12
+ def initialize(url, body, retry_sending)
13
+ @url = url
14
+ @body = body
15
+ @retry = retry_sending
16
+ end
17
+ end
18
+
19
+ class EventManager
20
+ def initialize(options = SecureNativeOptions.new, http_client = nil)
21
+ if options.api_key.nil?
22
+ raise SecureNativeSDKError, 'API key cannot be None, please get your API key from SecureNative console.'
23
+ end
24
+
25
+ @http_client = if http_client.nil?
26
+ SecureNativeHttpClient.new(options)
27
+ else
28
+ http_client
29
+ end
30
+
31
+ @queue = []
32
+ @semaphore = Mutex.new
33
+ @interval = options.interval
34
+ @options = options
35
+ @send_enabled = false
36
+ @attempt = 0
37
+ @coefficients = [1, 1, 2, 3, 5, 8, 13]
38
+
39
+ @thread = Thread.new { run }
40
+ end
41
+
42
+ def send_async(event, resource_path)
43
+ if @options.disable
44
+ SecureNativeLogger.warning('SDK is disabled. no operation will be performed')
45
+ return
46
+ end
47
+
48
+ item = QueueItem.new(resource_path, EventManager.serialize(event).to_json, false)
49
+ @queue.append(item)
50
+ end
51
+
52
+ def flush
53
+ @queue.each do |item|
54
+ @http_client.post(item.url, item.body)
55
+ end
56
+ end
57
+
58
+ def send_sync(event, resource_path, retry_sending)
59
+ if @options.disable
60
+ SecureNativeLogger.warning('SDK is disabled. no operation will be performed')
61
+ return
62
+ end
63
+
64
+ SecureNativeLogger.debug("Attempting to send event #{event}")
65
+ res = @http_client.post(resource_path, EventManager.serialize(event).to_json)
66
+
67
+ if res.status_code != 200
68
+ SecureNativeLogger.info("SecureNative failed to call endpoint #{resource_path} with event #{event}. adding back to queue")
69
+ item = QueueItem.new(resource_path, EventManager.serialize(event).to_json, retry_sending)
70
+ @queue.append(item)
71
+ end
72
+
73
+ res
74
+ end
75
+
76
+ def run
77
+ loop do
78
+ @semaphore.synchronize do
79
+ next unless !@queue.empty? && @send_enabled
80
+
81
+ @queue.each do |item|
82
+ begin
83
+ res = @http_client.post(item.url, item.body)
84
+ if res.status_code == 401
85
+ item.retry_sending = false
86
+ elsif res.status_code != 200
87
+ raise SecureNativeHttpError, res.status_code
88
+ end
89
+ SecureNativeLogger.debug("Event successfully sent; #{item.body}")
90
+ return res
91
+ rescue StandardError => e
92
+ SecureNativeLogger.error("Failed to send event; #{e}")
93
+ if item.retry_sending
94
+ @attempt = 0 if @coefficients.length == @attempt + 1
95
+
96
+ back_off = @coefficients[@attempt] * @options.interval
97
+ SecureNativeLogger.debug("Automatic back-off of #{back_off}")
98
+ @send_enabled = false
99
+ sleep back_off
100
+ @send_enabled = true
101
+ end
102
+ end
103
+ end
104
+ end
105
+ sleep @interval / 1000
106
+ end
107
+ end
108
+
109
+ def start_event_persist
110
+ SecureNativeLogger.debug('Starting automatic event persistence')
111
+ if @options.auto_send || @send_enabled
112
+ @send_enabled = true
113
+ else
114
+ SecureNativeLogger.debug('Automatic event persistence is disabled, you should persist events manually')
115
+ end
116
+ end
117
+
118
+ def stop_event_persist
119
+ if @send_enabled
120
+ SecureNativeLogger.debug('Attempting to stop automatic event persistence')
121
+ begin
122
+ flush
123
+ @thread&.stop?
124
+ SecureNativeLogger.debug('Stopped event persistence')
125
+ rescue StandardError => e
126
+ SecureNativeLogger.error("Could not stop event scheduler; #{e}")
127
+ end
128
+ end
129
+ end
130
+
131
+ def self.serialize(obj)
132
+ {
133
+ rid: obj.rid,
134
+ eventType: obj.event_type,
135
+ userId: obj.user_id,
136
+ userTraits: {
137
+ name: obj.user_traits.name,
138
+ email: obj.user_traits.email,
139
+ phone: obj.user_traits.phone,
140
+ createdAt: obj.user_traits.created_at
141
+ },
142
+ request: {
143
+ cid: obj.request.cid,
144
+ vid: obj.request.vid,
145
+ fp: obj.request.fp,
146
+ ip: obj.request.ip,
147
+ remoteIp: obj.request.remote_ip,
148
+ http_method: obj.request.http_method,
149
+ url: obj.request.url,
150
+ headers: obj.request.headers
151
+ },
152
+ timestamp: obj.timestamp,
153
+ properties: obj.properties
154
+ }
155
+ end
156
+ end