api_models 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +2 -0
- data/lib/api_models/version.rb +5 -0
- data/lib/api_models.rb +68 -0
- data/lib/models/account.rb +39 -0
- data/lib/models/agent.rb +439 -0
- data/lib/models/app.rb +18 -0
- data/lib/models/app47_cache.rb +69 -0
- data/lib/models/app_active_build.rb +32 -0
- data/lib/models/app_policy.rb +24 -0
- data/lib/models/app_shield_policy.rb +35 -0
- data/lib/models/authorized_user_policy.rb +44 -0
- data/lib/models/b2b_app.rb +8 -0
- data/lib/models/cat/customer.rb +9 -0
- data/lib/models/cat/customer_device.rb +10 -0
- data/lib/models/cl/customer.rb +9 -0
- data/lib/models/cl/customer_device.rb +10 -0
- data/lib/models/commerce_app_store.rb +8 -0
- data/lib/models/concerns/app47_app_analyzable.rb +46 -0
- data/lib/models/concerns/app47_app_buildable.rb +46 -0
- data/lib/models/concerns/app47_app_configurable.rb +34 -0
- data/lib/models/concerns/app47_app_policies.rb +59 -0
- data/lib/models/concerns/app47_cdn_url.rb +50 -0
- data/lib/models/concerns/app47_email_sendable.rb +29 -0
- data/lib/models/concerns/app47_logger.rb +109 -0
- data/lib/models/concerns/checkin_able.rb +28 -0
- data/lib/models/concerns/searchable.rb +54 -0
- data/lib/models/configuration_constraint.rb +22 -0
- data/lib/models/configuration_group.rb +50 -0
- data/lib/models/configuration_rule.rb +58 -0
- data/lib/models/device.rb +124 -0
- data/lib/models/external_app.rb +15 -0
- data/lib/models/gehc/customer.rb +17 -0
- data/lib/models/gehc/customer_device.rb +23 -0
- data/lib/models/group.rb +40 -0
- data/lib/models/internal_app.rb +11 -0
- data/lib/models/metric_data_job.rb +16 -0
- data/lib/models/option.rb +37 -0
- data/lib/models/pin_code_policy.rb +50 -0
- data/lib/models/platform.rb +26 -0
- data/lib/models/platform_model.rb +14 -0
- data/lib/models/product_app.rb +22 -0
- data/lib/models/product_support_app.rb +19 -0
- data/lib/models/queue_manager.rb +67 -0
- data/lib/models/redis_configuration.rb +137 -0
- data/lib/models/sso_ad_group.rb +7 -0
- data/lib/models/sso_ad_server.rb +13 -0
- data/lib/models/sso_ad_user.rb +13 -0
- data/lib/models/sso_azure_server.rb +18 -0
- data/lib/models/sso_directory_group.rb +13 -0
- data/lib/models/sso_directory_server.rb +21 -0
- data/lib/models/sso_google_server.rb +13 -0
- data/lib/models/sso_ldap_group.rb +8 -0
- data/lib/models/sso_ldap_rest_server.rb +34 -0
- data/lib/models/sso_ldap_server.rb +19 -0
- data/lib/models/sso_ldap_user.rb +7 -0
- data/lib/models/sso_oauth_server.rb +16 -0
- data/lib/models/sso_saml_v2_server.rb +25 -0
- data/lib/models/sso_server.rb +38 -0
- data/lib/models/sso_user.rb +13 -0
- data/lib/models/system_configuration.rb +92 -0
- data/lib/models/time_bomb_policy.rb +138 -0
- data/lib/models/user.rb +53 -0
- data/lib/models/user_app_permission.rb +16 -0
- data/lib/models/user_device.rb +83 -0
- data/lib/models/version_management_policy.rb +113 -0
- data/lib/models/web_app.rb +12 -0
- metadata +408 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dc2b42f380187648ed1eb18f3b2faa1ef2719e09e5e36245abb3441bfe90c215
|
4
|
+
data.tar.gz: 7db4b2aa8b21342d5fee241631d579033097db73a78e635b71d2d33091756ce2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9eff6f1c11c250fc24d2799c75975d7f4eab183cf17fbb5da3b162239e14cf144b1dd27437bfcb4f4594886b593d5a8f14928f411cf1659fd0b36110c19ee4ac
|
7
|
+
data.tar.gz: edc46b089835c626227297aa2147c3383ed5a22efe210507e737113cd21568c8a48c13b2eda95e527abf55686ab8ff6a7604cc6b5eaaddffec61324dd43e27a4
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2020 App47
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
data/lib/api_models.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'api_models/version'
|
4
|
+
|
5
|
+
# Concerns
|
6
|
+
require 'models/concerns/app47_app_analyzable.rb'
|
7
|
+
require 'models/concerns/app47_app_buildable.rb'
|
8
|
+
require 'models/concerns/app47_app_configurable.rb'
|
9
|
+
require 'models/concerns/app47_app_policies.rb'
|
10
|
+
require 'models/concerns/app47_cdn_url.rb'
|
11
|
+
require 'models/concerns/app47_email_sendable.rb'
|
12
|
+
require 'models/concerns/app47_logger.rb'
|
13
|
+
require 'models/concerns/checkin_able.rb'
|
14
|
+
require 'models/concerns/searchable.rb'
|
15
|
+
|
16
|
+
require 'models/account.rb'
|
17
|
+
require 'models/agent.rb'
|
18
|
+
require 'models/app.rb'
|
19
|
+
require 'models/app47_cache.rb'
|
20
|
+
require 'models/app_active_build.rb'
|
21
|
+
require 'models/app_policy.rb'
|
22
|
+
require 'models/app_shield_policy.rb'
|
23
|
+
require 'models/authorized_user_policy.rb'
|
24
|
+
require 'models/b2b_app.rb'
|
25
|
+
require 'models/product_app.rb'
|
26
|
+
require 'models/commerce_app_store.rb'
|
27
|
+
require 'models/configuration_constraint.rb'
|
28
|
+
require 'models/configuration_group.rb'
|
29
|
+
require 'models/configuration_rule.rb'
|
30
|
+
require 'models/device.rb'
|
31
|
+
require 'models/external_app.rb'
|
32
|
+
require 'models/group.rb'
|
33
|
+
require 'models/internal_app.rb'
|
34
|
+
require 'models/metric_data_job.rb'
|
35
|
+
require 'models/option.rb'
|
36
|
+
require 'models/pin_code_policy.rb'
|
37
|
+
require 'models/platform.rb'
|
38
|
+
require 'models/platform_model.rb'
|
39
|
+
require 'models/queue_manager.rb'
|
40
|
+
require 'models/redis_configuration.rb'
|
41
|
+
require 'models/sso_directory_group.rb'
|
42
|
+
require 'models/user.rb'
|
43
|
+
require 'models/sso_server.rb'
|
44
|
+
require 'models/sso_directory_server.rb'
|
45
|
+
require 'models/sso_user.rb'
|
46
|
+
require 'models/sso_ad_group.rb'
|
47
|
+
require 'models/sso_ad_server.rb'
|
48
|
+
require 'models/sso_ad_user.rb'
|
49
|
+
require 'models/sso_ldap_group.rb'
|
50
|
+
require 'models/sso_ldap_rest_server.rb'
|
51
|
+
require 'models/sso_ldap_server.rb'
|
52
|
+
require 'models/sso_ldap_user.rb'
|
53
|
+
require 'models/sso_oauth_server.rb'
|
54
|
+
require 'models/sso_azure_server.rb'
|
55
|
+
require 'models/sso_google_server.rb'
|
56
|
+
require 'models/sso_saml_v2_server.rb'
|
57
|
+
require 'models/system_configuration.rb'
|
58
|
+
require 'models/time_bomb_policy.rb'
|
59
|
+
require 'models/user_app_permission.rb'
|
60
|
+
require 'models/user_device.rb'
|
61
|
+
require 'models/version_management_policy.rb'
|
62
|
+
require 'models/web_app.rb'
|
63
|
+
require 'models/cat/customer.rb'
|
64
|
+
require 'models/cat/customer_device.rb'
|
65
|
+
require 'models/cl/customer.rb'
|
66
|
+
require 'models/cl/customer_device.rb'
|
67
|
+
require 'models/gehc/customer.rb'
|
68
|
+
require 'models/gehc/customer_device.rb'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Main Account object, should hold references to everything else.
|
5
|
+
#
|
6
|
+
class Account
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
|
10
|
+
#
|
11
|
+
# Fields
|
12
|
+
#
|
13
|
+
field :name, type: String
|
14
|
+
field :stage, { type: String, default: 'Trial' }
|
15
|
+
field :api_url, type: String
|
16
|
+
#
|
17
|
+
# Relationships
|
18
|
+
#
|
19
|
+
has_many :apps do
|
20
|
+
#
|
21
|
+
# return a list of apps where all the user flag is turned on
|
22
|
+
#
|
23
|
+
def distinct_all_users
|
24
|
+
where(all_users: true)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
has_many :users
|
28
|
+
has_many :groups
|
29
|
+
has_many :sso_servers
|
30
|
+
|
31
|
+
#
|
32
|
+
# Is the API supported for this account?
|
33
|
+
#
|
34
|
+
def api_enabled?
|
35
|
+
!%w[Terminated Rejected].include?(stage)
|
36
|
+
rescue StandardError
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
data/lib/models/agent.rb
ADDED
@@ -0,0 +1,439 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Represents an agent, a specific install of an app on a device.
|
5
|
+
#
|
6
|
+
class Agent
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
include CheckinAble
|
10
|
+
include App47Logger
|
11
|
+
#
|
12
|
+
# Fields
|
13
|
+
#
|
14
|
+
field :agent_version, type: String
|
15
|
+
field :app_version, type: String
|
16
|
+
field :app_version_code, type: String
|
17
|
+
field :app_environment, type: String, default: 'production'
|
18
|
+
field :net_new_counted, type: Boolean, default: false
|
19
|
+
# field :installed_version, type: String
|
20
|
+
#
|
21
|
+
# Relationships
|
22
|
+
#
|
23
|
+
belongs_to :device
|
24
|
+
belongs_to :app, inverse_of: :agents, optional: true
|
25
|
+
#
|
26
|
+
# Call backs
|
27
|
+
#
|
28
|
+
after_create :notify_new_agent
|
29
|
+
before_save :update_app_version
|
30
|
+
after_find :migrate_data
|
31
|
+
#
|
32
|
+
# Delegations
|
33
|
+
#
|
34
|
+
delegate :platform, to: :device
|
35
|
+
|
36
|
+
#
|
37
|
+
# If the agent is capable of reporting the correct version code, basically is the agent version high enough on the
|
38
|
+
# respective platform to have the correct version code to report.
|
39
|
+
#
|
40
|
+
def use_version_code?
|
41
|
+
app.use_version_code?(platform) && (ios? && agent_version.to_f >= 4.4 || android? && agent_version.to_f >= 3.2)
|
42
|
+
rescue StandardError
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Is this agent an ios agent?
|
48
|
+
#
|
49
|
+
def ios?
|
50
|
+
platform.eql?('iOS')
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Is this agent an Android Agent
|
55
|
+
#
|
56
|
+
def android?
|
57
|
+
platform.eql?('Android')
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# return the configuration for this agent
|
62
|
+
#
|
63
|
+
def config_data
|
64
|
+
data = App47Cache.get(config_cache_key)
|
65
|
+
if data.nil?
|
66
|
+
data = build_config_data
|
67
|
+
else
|
68
|
+
data[:server_time_epoch] = Time.now.to_i
|
69
|
+
end
|
70
|
+
|
71
|
+
App47Cache.set(config_cache_key, data, 30)
|
72
|
+
data
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Fetch or create an agent
|
77
|
+
#
|
78
|
+
def self.fetch(app, device, json)
|
79
|
+
agent = Agent.find_or_create_by(device: device, app: app)
|
80
|
+
device.apps << app if agent.new_record? # Add this app to the device if agent is new
|
81
|
+
# new_version = json[:app_version]
|
82
|
+
# agent.notify_new_app_version(new_version) unless new_version.nil? || new_version.eql?(agent.app_version)
|
83
|
+
agent.update_attributes!(json)
|
84
|
+
agent
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Main entry point for inserting metric data
|
89
|
+
#
|
90
|
+
def insert_metric_data(type, data, agent_ip)
|
91
|
+
# If the agent isn't enabled, then drop the data and return a hearty "Thank you!"
|
92
|
+
return true unless app_agent_enabled?
|
93
|
+
|
94
|
+
send "insert_#{type}_data", data.symbolize_keys, agent_ip
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Notify the main worker to update the app and agent configuration information with the new
|
99
|
+
# version
|
100
|
+
#
|
101
|
+
# We also want to force the config to regenerate for the agent as the version will
|
102
|
+
# yield different results.
|
103
|
+
#
|
104
|
+
def notify_new_app_version(new_version)
|
105
|
+
# App47Cache.delete config_cache_key
|
106
|
+
# App47Cache.delete policies_cache_key
|
107
|
+
# QueueManager.push_worker job: 'app_upgrade',
|
108
|
+
# app_id: app_id.to_s,
|
109
|
+
# agent_id: id.to_s,
|
110
|
+
# current_version: app_version,
|
111
|
+
# new_version: new_version
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Safely update attributes from the document
|
116
|
+
#
|
117
|
+
def update_attributes!(attributes = {})
|
118
|
+
super(filter_json(attributes))
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Safely update attributes from the document
|
123
|
+
#
|
124
|
+
def update!(attributes = {})
|
125
|
+
super(filter_json(attributes))
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Find the user by the device id associated with the agent's device
|
130
|
+
#
|
131
|
+
def find_user
|
132
|
+
account = app.account
|
133
|
+
device_identifier = device.unique_identifier
|
134
|
+
device = UserDevice.find_device_by device_identifier
|
135
|
+
user = device.user
|
136
|
+
raise 'Invalid account' unless account.eql?(user.account)
|
137
|
+
|
138
|
+
device.user
|
139
|
+
rescue StandardError
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# filter only the json parameters we want to take into the device. The agent
|
145
|
+
# sends up more than we need for the device.
|
146
|
+
#
|
147
|
+
def filter_json(json)
|
148
|
+
filtered_json = {}
|
149
|
+
%i[agent_version app_version app_version_code app_environment].each do |field|
|
150
|
+
filtered_json[field] = json[field] if json[field].present?
|
151
|
+
end
|
152
|
+
filtered_json
|
153
|
+
end
|
154
|
+
|
155
|
+
#
|
156
|
+
# Encrypt the data unique to this agent.
|
157
|
+
#
|
158
|
+
def encrypt_data(data)
|
159
|
+
cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
160
|
+
cipher.encrypt
|
161
|
+
user_token = device.unique_identifier
|
162
|
+
user_token += user_token while user_token.length < 48
|
163
|
+
cipher.key = user_token[0..31]
|
164
|
+
cipher.iv = user_token[32..47]
|
165
|
+
Base64.encode64(cipher.update(data) + cipher.final)
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
#
|
171
|
+
# Remove analysis_states and modified_at attributes that are no longer used
|
172
|
+
#
|
173
|
+
def migrate_data
|
174
|
+
remove_attribute :analysis_states
|
175
|
+
remove_attribute :modified_at
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Basic information relavant to any metric
|
180
|
+
#
|
181
|
+
def base_metric_data(data, agent_ip, session_id = nil)
|
182
|
+
if data[:start_time_epoch].nil?
|
183
|
+
r_start_time = Time.parse(data[:start_time]).gmtime
|
184
|
+
record_raw_time = data[:start_time].to_s.encode('UTF-8')
|
185
|
+
time_zone = record_raw_time.split(' ').last
|
186
|
+
else
|
187
|
+
r_start_time = Time.at(data[:start_time_epoch].to_i).utc
|
188
|
+
time_zone = nil
|
189
|
+
record_raw_time = nil
|
190
|
+
end
|
191
|
+
|
192
|
+
{ agent_id: id.to_s,
|
193
|
+
start_time: r_start_time,
|
194
|
+
time_zone: time_zone,
|
195
|
+
app_id: app_id.to_s,
|
196
|
+
record_date: r_start_time.strftime('%D'),
|
197
|
+
session_id: data[:session_id] || session_id,
|
198
|
+
userinfo: data[:userinfo],
|
199
|
+
tags: data[:tags],
|
200
|
+
ip_address: agent_ip,
|
201
|
+
device_id: device_id.to_s,
|
202
|
+
raw_agent_time_str: record_raw_time,
|
203
|
+
raw_agent_epoch_str: data[:start_time_epoch],
|
204
|
+
loc: {
|
205
|
+
lat: (data[:location_lat].nil? ? 0 : data[:location_lat].to_f),
|
206
|
+
long: (data[:location_long].nil? ? 0 : data[:location_long].to_f)
|
207
|
+
} }
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# insert log data received from the agent
|
212
|
+
#
|
213
|
+
def insert_logs_data(data, agent_ip, session_id = nil)
|
214
|
+
return if data[:logs].blank?
|
215
|
+
|
216
|
+
data[:logs].each { |log_data| insert_log_data(log_data.symbolize_keys, agent_ip, session_id) }
|
217
|
+
end
|
218
|
+
|
219
|
+
#
|
220
|
+
# insert a single log entry
|
221
|
+
#
|
222
|
+
def insert_log_data(data, agent_ip, session_id = nil)
|
223
|
+
log_level = data[:level].downcase
|
224
|
+
QueueManager.push_log_event base_metric_data(data, agent_ip, session_id).merge(
|
225
|
+
log_id: data[:uuid],
|
226
|
+
level: log_level,
|
227
|
+
crash_log_format: data[:crash_log_format],
|
228
|
+
is_error_or_crash: %w[error crash].include?(log_level),
|
229
|
+
message: safely_encode(data, :message),
|
230
|
+
filename: safely_encode(data, :filename),
|
231
|
+
line_number: data[:line_number],
|
232
|
+
error_name: safely_encode(data, :error_name),
|
233
|
+
error_reason: safely_encode(data, :error_reason),
|
234
|
+
error_detail: safely_encode(data, :error_detail)
|
235
|
+
)
|
236
|
+
end
|
237
|
+
|
238
|
+
#
|
239
|
+
# Insert multiple timed events
|
240
|
+
#
|
241
|
+
def insert_timed_events_data(data, agent_ip, session_id = nil)
|
242
|
+
return if data[:timedevents].blank?
|
243
|
+
|
244
|
+
data[:timedevents].each { |event_data| insert_timed_event_data(event_data.symbolize_keys, agent_ip, session_id) }
|
245
|
+
end
|
246
|
+
|
247
|
+
#
|
248
|
+
# Insert a single timed event
|
249
|
+
#
|
250
|
+
def insert_timed_event_data(data, agent_ip, session_id = nil)
|
251
|
+
duration = data[:duration].to_f
|
252
|
+
return if duration <= 0
|
253
|
+
|
254
|
+
QueueManager.push_timed_event base_metric_data(data, agent_ip, session_id).merge(
|
255
|
+
timed_event_id: data[:uuid],
|
256
|
+
duration: duration,
|
257
|
+
name: data[:name],
|
258
|
+
created_at_hf: Time.now.gmtime.strftime('%Y-%m-%d %H:%M:%S.%L')
|
259
|
+
)
|
260
|
+
end
|
261
|
+
|
262
|
+
#
|
263
|
+
# Insert multiple generic events
|
264
|
+
#
|
265
|
+
def insert_generic_events_data(data, agent_ip, session_id = nil)
|
266
|
+
return if data[:events].blank?
|
267
|
+
|
268
|
+
data[:events].each { |event_data| insert_generic_event_data(event_data.symbolize_keys, agent_ip, session_id) }
|
269
|
+
end
|
270
|
+
|
271
|
+
#
|
272
|
+
# Insert a single generic event
|
273
|
+
#
|
274
|
+
def insert_generic_event_data(data, agent_ip, session_id = nil)
|
275
|
+
QueueManager.push_generic_event base_metric_data(data, agent_ip, session_id).merge(event_id: data[:uuid],
|
276
|
+
name: data[:name])
|
277
|
+
end
|
278
|
+
|
279
|
+
#
|
280
|
+
# Insert a single session event
|
281
|
+
#
|
282
|
+
# Returns the session id for use elsewhere
|
283
|
+
#
|
284
|
+
def insert_session_data(data, agent_ip)
|
285
|
+
duration = data[:duration].to_f
|
286
|
+
return if duration <= 0
|
287
|
+
|
288
|
+
QueueManager.push_session base_metric_data(data, agent_ip).merge(session_id: data[:uuid], duration: duration)
|
289
|
+
data[:uuid]
|
290
|
+
end
|
291
|
+
|
292
|
+
#
|
293
|
+
# Insert bulk data which contacts a session, logs, timed events and generic events
|
294
|
+
#
|
295
|
+
def insert_bulk_data(data, agent_ip)
|
296
|
+
session_id = insert_session_data(data[:session].symbolize_keys, agent_ip)
|
297
|
+
insert_logs_data(data, agent_ip, session_id)
|
298
|
+
insert_generic_events_data(data, agent_ip, session_id)
|
299
|
+
insert_timed_events_data(data, agent_ip, session_id)
|
300
|
+
metrics = data[:app47logs]
|
301
|
+
metrics.each { |app47log| log_debug "AgentLog47: #{id}: #{app47log.inspect}" } if metrics.present?
|
302
|
+
end
|
303
|
+
|
304
|
+
#
|
305
|
+
# Build the config data from scratch
|
306
|
+
#
|
307
|
+
def build_config_data
|
308
|
+
data = default_config_data
|
309
|
+
return data if app.blank?
|
310
|
+
|
311
|
+
if app.api_enabled?
|
312
|
+
data[:agent_enabled] = true
|
313
|
+
data[:configuration_groups] = app.configuration_groups.match_agent(self)
|
314
|
+
data[:message] = 'App found and agent enabled'
|
315
|
+
if app.agent_capture_sessions?
|
316
|
+
data[:capture_sessions] = true
|
317
|
+
data[:capture_generic_events] = app.agent_capture_generic_events?
|
318
|
+
data[:capture_timed_events] = app.agent_capture_timed_events?
|
319
|
+
data[:agent_log_level] = app.agent_log_level
|
320
|
+
data[:session_threshold_seconds] = app.agent_session_threshold_seconds
|
321
|
+
end
|
322
|
+
end
|
323
|
+
data[:message] = 'App found and agent disabled'
|
324
|
+
data[:upload_on_exit] = app.agent_upload_on_exit
|
325
|
+
data[:capture_crash_format] = app.agent_capture_crash_format
|
326
|
+
data[:delay_data_upload_interval] = app.agent_delay_data_upload_interval
|
327
|
+
data[:configuration_update_frequency] = app.agent_configuration_update_frequency
|
328
|
+
data
|
329
|
+
end
|
330
|
+
|
331
|
+
#
|
332
|
+
# Build the default config data block
|
333
|
+
#
|
334
|
+
def default_config_data
|
335
|
+
{ agent_id: id.to_s,
|
336
|
+
agent_log_level: 'None',
|
337
|
+
session_data_endpoint: api_url,
|
338
|
+
realtime_data_endpoint: api_url,
|
339
|
+
upload_on_exit: false,
|
340
|
+
show_network_activity: true,
|
341
|
+
capture_crash_format: 'none',
|
342
|
+
capture_crashes: false,
|
343
|
+
capture_generic_events: false,
|
344
|
+
agent_enabled: false,
|
345
|
+
session_threshold_seconds: 5,
|
346
|
+
message: 'Unknown app id, disabling agent',
|
347
|
+
capture_timed_events: false,
|
348
|
+
capture_sessions: false,
|
349
|
+
delay_data_upload_interval: 60,
|
350
|
+
pin_code_required: 0,
|
351
|
+
configuration_update_frequency: 7,
|
352
|
+
configuration_groups: [],
|
353
|
+
server_time_epoch: Time.now.to_i }.merge(policies_for_agent)
|
354
|
+
end
|
355
|
+
|
356
|
+
#
|
357
|
+
# Return either the agent's account api url or the system configuration one by default
|
358
|
+
#
|
359
|
+
def api_url
|
360
|
+
app.account.api_url.blank? ? SystemConfiguration.api_url : app.account.api_url
|
361
|
+
rescue StandardError
|
362
|
+
SystemConfiguration.api_url
|
363
|
+
end
|
364
|
+
|
365
|
+
#
|
366
|
+
# Key used to store the agent's config
|
367
|
+
#
|
368
|
+
def policies_cache_key
|
369
|
+
@policies_cache_key ||= "agent_policies::#{id}"
|
370
|
+
end
|
371
|
+
|
372
|
+
#
|
373
|
+
# Key used to store the agent's config
|
374
|
+
#
|
375
|
+
def config_cache_key
|
376
|
+
@config_cache_key ||= "config_cache::#{id}"
|
377
|
+
end
|
378
|
+
|
379
|
+
#
|
380
|
+
# Tell the net new worker to update analytics
|
381
|
+
#
|
382
|
+
def notify_new_agent
|
383
|
+
QueueManager.push_worker job: 'new_agent', app_id: app_id.to_s, agent_id: id.to_s
|
384
|
+
end
|
385
|
+
|
386
|
+
#
|
387
|
+
# Safely encode the given string, capturing any error.
|
388
|
+
#
|
389
|
+
def safely_encode(data, name)
|
390
|
+
data[name].force_encoding('ISO-8859-1').encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
|
391
|
+
rescue StandardError
|
392
|
+
nil
|
393
|
+
end
|
394
|
+
|
395
|
+
#
|
396
|
+
# Safely test if the app is enabled, this allows the app to be missing
|
397
|
+
#
|
398
|
+
def app_agent_enabled?
|
399
|
+
app.agent_enabled?
|
400
|
+
rescue StandardError
|
401
|
+
false
|
402
|
+
end
|
403
|
+
|
404
|
+
#
|
405
|
+
# Clear the cache
|
406
|
+
#
|
407
|
+
def update_app_version
|
408
|
+
return unless changed.include?('app_version')
|
409
|
+
|
410
|
+
(from, to) = changes[:app_version]
|
411
|
+
return if from.eql?(to)
|
412
|
+
|
413
|
+
App47Cache.delete config_cache_key
|
414
|
+
App47Cache.delete policies_cache_key
|
415
|
+
QueueManager.push_worker job: 'app_upgrade',
|
416
|
+
app_id: app_id.to_s,
|
417
|
+
agent_id: id.to_s,
|
418
|
+
current_version: from,
|
419
|
+
new_version: to
|
420
|
+
true # Force a return of true so that we don't break the callback chain.
|
421
|
+
end
|
422
|
+
|
423
|
+
#
|
424
|
+
# Return a hash of security policies for this agent
|
425
|
+
#
|
426
|
+
def policies_for_agent
|
427
|
+
defaults = { device_enabled: 1, enforce_active_version: false }
|
428
|
+
current = App47Cache.get(policies_cache_key)
|
429
|
+
return current if current.present?
|
430
|
+
|
431
|
+
current = app.policies.inject(defaults) { |acc, elem| acc.merge(elem.enforce_policy(self)) }
|
432
|
+
App47Cache.set(policies_cache_key, current, 30)
|
433
|
+
rescue StandardError
|
434
|
+
# Clear it out of cache just in case that's the issue
|
435
|
+
App47Cache.delete(policies_cache_key)
|
436
|
+
# Return the default set of policies
|
437
|
+
{ device_enabled: 1, enforce_active_version: false }
|
438
|
+
end
|
439
|
+
end
|
data/lib/models/app.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Base class of app
|
5
|
+
#
|
6
|
+
class App
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
#
|
10
|
+
# Fields
|
11
|
+
#
|
12
|
+
field :name, type: String
|
13
|
+
field :all_users, type: Boolean, default: false
|
14
|
+
#
|
15
|
+
# Relationships
|
16
|
+
#
|
17
|
+
belongs_to :account
|
18
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
#
|
6
|
+
# Public: Provide a common interface to redis cache
|
7
|
+
#
|
8
|
+
# Examples
|
9
|
+
#
|
10
|
+
# RedisCacheService.delete("key name")
|
11
|
+
# # => the value of the key deleted
|
12
|
+
#
|
13
|
+
# RedisCacheService.get("key name")
|
14
|
+
# # => the value of the key
|
15
|
+
#
|
16
|
+
class App47Cache
|
17
|
+
include Singleton
|
18
|
+
|
19
|
+
class << self
|
20
|
+
#
|
21
|
+
# Return the redis connection
|
22
|
+
#
|
23
|
+
def redis
|
24
|
+
@redis ||= Redis.new(RedisConfiguration.load(12))
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Delete a key from cache
|
29
|
+
#
|
30
|
+
# key - the key to delete
|
31
|
+
#
|
32
|
+
def delete(key)
|
33
|
+
redis.del key
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Get a key from cache
|
38
|
+
#
|
39
|
+
# key - the key to fetch, if key is not found, returns nil
|
40
|
+
#
|
41
|
+
def get(key)
|
42
|
+
return nil if ENV['RACK_ENV'].eql?('staging')
|
43
|
+
|
44
|
+
value = redis.get key
|
45
|
+
value.nil? ? nil : Marshal.restore(value)
|
46
|
+
rescue StandardError
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Set a key with a value and TTL
|
52
|
+
#
|
53
|
+
# key - the key to delete
|
54
|
+
# value - the value to set
|
55
|
+
# ttl(optional) - optional time to live parameter, default is no ttl, live forever
|
56
|
+
#
|
57
|
+
# Returns the value passed in
|
58
|
+
#
|
59
|
+
def set(key, value, ttl = nil)
|
60
|
+
in_value = Marshal.dump value
|
61
|
+
if ttl
|
62
|
+
redis.setex key, ttl, in_value
|
63
|
+
else
|
64
|
+
redis.set key, in_value
|
65
|
+
end
|
66
|
+
value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Holds the active build for a given app
|
5
|
+
#
|
6
|
+
class AppActiveBuild
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
include App47CdnUrl
|
10
|
+
#
|
11
|
+
# Fields
|
12
|
+
#
|
13
|
+
field :version
|
14
|
+
field :version_code
|
15
|
+
field :file_url
|
16
|
+
field :environment
|
17
|
+
field :platform
|
18
|
+
field :enforce, type: Boolean, default: false
|
19
|
+
#
|
20
|
+
# Relationships
|
21
|
+
#
|
22
|
+
belongs_to :app, inverse_of: :app_active_builds
|
23
|
+
|
24
|
+
#
|
25
|
+
# Return the selected tracking version
|
26
|
+
#
|
27
|
+
def display_version
|
28
|
+
send(app.tracked_version(platform)) || version
|
29
|
+
rescue StandardError
|
30
|
+
version
|
31
|
+
end
|
32
|
+
end
|