api_models 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Easily fetch the redis configuration from redis.yml in the config directory.
|
5
|
+
# There are several formats to support
|
6
|
+
#
|
7
|
+
# URL with single server
|
8
|
+
# development:
|
9
|
+
# url: 'redis://localhost:6379/0'
|
10
|
+
#
|
11
|
+
# Host/port combination for single server
|
12
|
+
# development:
|
13
|
+
# host: localhost
|
14
|
+
# port: 6379
|
15
|
+
# db: 0
|
16
|
+
#
|
17
|
+
# Sentinel
|
18
|
+
# development:
|
19
|
+
# master: production
|
20
|
+
# sentinels:
|
21
|
+
# - host1:6379
|
22
|
+
# - host2:6379
|
23
|
+
# - host3:6379
|
24
|
+
# role: master
|
25
|
+
#
|
26
|
+
# Available for all options
|
27
|
+
# connect_timeout: 0.2
|
28
|
+
# read_timeout: 0.2
|
29
|
+
# write_timeout: 0.2
|
30
|
+
# timeout: 1
|
31
|
+
#
|
32
|
+
class RedisConfiguration
|
33
|
+
#
|
34
|
+
# Methods are static
|
35
|
+
#
|
36
|
+
class << self
|
37
|
+
#
|
38
|
+
# Load the configuration using the given DB
|
39
|
+
#
|
40
|
+
# Trying first the URL, then host, then sentinel, then default method
|
41
|
+
#
|
42
|
+
def load(database = nil)
|
43
|
+
load_url(database) || load_host(database) || load_sentinel(database) || load_default(database)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
#
|
49
|
+
# Load the base set of parameters from the config file
|
50
|
+
#
|
51
|
+
def load_base(raw_config)
|
52
|
+
base = {}
|
53
|
+
%i[connect_timeout namespace read_timeout write_timeout timeout].each do |key|
|
54
|
+
base[key] = raw_config[key.to_s] unless raw_config[key.to_s].nil?
|
55
|
+
end
|
56
|
+
base
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Load a default configuration with the given database
|
61
|
+
#
|
62
|
+
def load_default(database = 0)
|
63
|
+
{ host: '127.0.0.1', port: 6_379, db: (database || 0) }
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Load the url
|
68
|
+
#
|
69
|
+
def load_url(database = 0)
|
70
|
+
raw_config = load_file
|
71
|
+
return if raw_config.nil? || raw_config['url'].nil?
|
72
|
+
|
73
|
+
config = load_base(raw_config)
|
74
|
+
config[:url] = raw_config['url']
|
75
|
+
config[:db] = (database || 0)
|
76
|
+
config
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Load the given host
|
81
|
+
#
|
82
|
+
def load_host(database = nil)
|
83
|
+
raw_config = load_file
|
84
|
+
return if raw_config.nil? || raw_config['host'].nil?
|
85
|
+
|
86
|
+
config = load_base(raw_config)
|
87
|
+
config[:host] = raw_config['host']
|
88
|
+
config[:port] = raw_config['port'] || 6_379
|
89
|
+
config[:db] = database || raw_config['db'] || 0
|
90
|
+
config
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Load the sentinel configuration
|
95
|
+
#
|
96
|
+
def load_sentinel(database = 0)
|
97
|
+
raw_config = load_file
|
98
|
+
return if raw_config.nil? || raw_config['master'].nil?
|
99
|
+
|
100
|
+
config = load_base(raw_config)
|
101
|
+
config[:url] = "redis://#{raw_config['master']}"
|
102
|
+
config[:sentinels] = raw_config['sentinels'].collect do |sentinel|
|
103
|
+
parts = sentinel.split(':')
|
104
|
+
host = parts.first
|
105
|
+
port = parts.count.eql?(2) ? parts.last : 26_379
|
106
|
+
{ host: host, port: port }
|
107
|
+
end
|
108
|
+
config[:db] = database || 0
|
109
|
+
config[:role] = raw_config['role'] || 'master'
|
110
|
+
config
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Return the config file
|
115
|
+
#
|
116
|
+
def config_file_path
|
117
|
+
File.expand_path([ENV['APP_CONFIG_DIR'], 'config', 'redis.yml'].compact.join('/'))
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Load the config/redis.yml and return the environment name
|
122
|
+
#
|
123
|
+
def load_file
|
124
|
+
config = nil
|
125
|
+
file_path = config_file_path
|
126
|
+
if File.exist? file_path
|
127
|
+
yaml_data = YAML.load_file(file_path)
|
128
|
+
config = yaml_data[ENV['RACK_ENV']] if yaml_data
|
129
|
+
end
|
130
|
+
|
131
|
+
config
|
132
|
+
rescue StandardError => error
|
133
|
+
puts "Error loading #{config_file_path} file", error
|
134
|
+
nil # return nothing if there is an error
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Azure SSO Server
|
5
|
+
#
|
6
|
+
class SsoAzureServer < SsoOauthServer
|
7
|
+
#
|
8
|
+
# Fields
|
9
|
+
#
|
10
|
+
field :tenant_id, type: String
|
11
|
+
|
12
|
+
#
|
13
|
+
# Google Server SSO name
|
14
|
+
#
|
15
|
+
def display_name
|
16
|
+
'Azure OAuth 2.0'
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Base class for SSO directory (AD/LDAP) group
|
5
|
+
#
|
6
|
+
class SsoDirectoryGroup < Group
|
7
|
+
#
|
8
|
+
# Fields
|
9
|
+
#
|
10
|
+
field :dn, type: String
|
11
|
+
field :synchronize, type: Boolean, default: false
|
12
|
+
field :auto_approve_devices, type: Boolean, default: true
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Base class for SSO Directory servers, i.e., AD and LDAP
|
5
|
+
#
|
6
|
+
class SsoDirectoryServer < SsoServer
|
7
|
+
# fields
|
8
|
+
field :ssl, type: Boolean, default: false
|
9
|
+
field :currently_syncing, type: Boolean, default: false
|
10
|
+
field :server_name, type: String
|
11
|
+
field :port, type: String, default: '389'
|
12
|
+
field :username, type: String
|
13
|
+
field :password, type: String
|
14
|
+
field :frequency, type: String, default: '24'
|
15
|
+
field :last_sync_time, type: DateTime
|
16
|
+
field :last_sync_message, type: String
|
17
|
+
field :treebase, type: String
|
18
|
+
field :user_identifier, type: String
|
19
|
+
# relationships
|
20
|
+
has_many :groups, inverse_of: :sso_server, dependent: :nullify
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Interact with the Ldap Restful API for authentication
|
5
|
+
#
|
6
|
+
class SsoLdapRestServer < SsoServer
|
7
|
+
#
|
8
|
+
# Fields
|
9
|
+
#
|
10
|
+
field :auth_url, type: String
|
11
|
+
field :auth_bearer_token, type: String
|
12
|
+
field :auth_params, type: String
|
13
|
+
field :search_url, type: String
|
14
|
+
field :search_bearer_token, type: String
|
15
|
+
field :search_key_name, type: String, default: 'staff_id'
|
16
|
+
field :image_url, type: String
|
17
|
+
field :image_bearer_token, type: String
|
18
|
+
field :image_api_key, type: String
|
19
|
+
|
20
|
+
#
|
21
|
+
# Display name for this server, should be overriden by concrete implementations.
|
22
|
+
#
|
23
|
+
def display_name
|
24
|
+
'LDAP Rest API Server'
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Using the appropriate SSO server configuration obtain the
|
29
|
+
# the user profile address
|
30
|
+
#
|
31
|
+
def user_profile(user_id)
|
32
|
+
account.users.find(user_id)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Hold the configuration for LDAP synchronization, Using the ad_configuration logic to sync with server
|
5
|
+
#
|
6
|
+
class SsoLdapServer < SsoDirectoryServer
|
7
|
+
#
|
8
|
+
# Fields
|
9
|
+
#
|
10
|
+
field :user_filter, type: String, default: 'ou=users'
|
11
|
+
field :group_filter, type: String, default: 'ou=groups'
|
12
|
+
field :group_identifier, type: String, default: 'gidNumber'
|
13
|
+
#
|
14
|
+
# Return the display name for this server type
|
15
|
+
#
|
16
|
+
def display_name
|
17
|
+
'LDAP Server'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# OAuth 2.0 Server
|
5
|
+
#
|
6
|
+
class SsoOauthServer < SsoServer
|
7
|
+
# Fields
|
8
|
+
field :server_url, type: String
|
9
|
+
field :auth_url, type: String
|
10
|
+
field :token_url, type: String
|
11
|
+
field :profile_url, type: String
|
12
|
+
field :redirect_path, type: String, default: 'eas/auth/oauth'
|
13
|
+
field :client_id, type: String
|
14
|
+
field :client_secret, type: String
|
15
|
+
field :scopes, type: String
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# SSO SAML V2 Server
|
5
|
+
#
|
6
|
+
class SsoSamlV2Server < SsoServer
|
7
|
+
#
|
8
|
+
# Fields
|
9
|
+
#
|
10
|
+
field :idp_url, type: String
|
11
|
+
field :idp_xml, type: String
|
12
|
+
field :xml_last_fetched_at, type: Time, default: Time.now.utc
|
13
|
+
field :xml_cache_days, type: Integer, default: 365
|
14
|
+
field :name_identifier_format, type: String, default: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
|
15
|
+
field :name_attribute_key, type: String
|
16
|
+
field :email_attribute_key, type: String
|
17
|
+
field :groups_attribute_key, type: String
|
18
|
+
|
19
|
+
#
|
20
|
+
# Display name for this server, should be overriden by concrete implementations.
|
21
|
+
#
|
22
|
+
def display_name
|
23
|
+
'SAML V2 Server'
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Base server container for an account which can have 0..N sso servers configured.
|
5
|
+
#
|
6
|
+
class SsoServer
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
include App47Logger
|
10
|
+
#
|
11
|
+
# fields
|
12
|
+
#
|
13
|
+
field :active, type: Boolean, default: false
|
14
|
+
field :external_authentication, type: Boolean, default: false
|
15
|
+
field :name, type: String
|
16
|
+
field :default_user_invitation_message, type: String
|
17
|
+
#
|
18
|
+
# relationships
|
19
|
+
#
|
20
|
+
belongs_to :account, inverse_of: :sso_servers
|
21
|
+
has_many :users, inverse_of: :sso_server, dependent: :nullify, class_name: 'SsoUser'
|
22
|
+
has_many :groups, inverse_of: :sso_server, class_name: 'Group'
|
23
|
+
|
24
|
+
#
|
25
|
+
# Display name for this server, should be overriden by concrete implementations.
|
26
|
+
#
|
27
|
+
def display_name
|
28
|
+
'SSO Server'
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# Using the appropriate SSO server configuration obtain the
|
33
|
+
# the user profile address, this should be implemented by the child class.
|
34
|
+
#
|
35
|
+
def user_profile(_code)
|
36
|
+
raise 'Failed to retrieve user profile from provider'
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Base class for a SSO User
|
5
|
+
#
|
6
|
+
class SsoUser < User
|
7
|
+
field :session_hours_length, type: Integer, default: 24
|
8
|
+
field :last_code, type: String
|
9
|
+
#
|
10
|
+
# Relationships
|
11
|
+
#
|
12
|
+
belongs_to :sso_server, class_name: 'SsoServer', inverse_of: :users
|
13
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# The System configuration. Various configuration items that can be updated/defined at run time instead
|
5
|
+
# of AppConfiguration that is defining things statically in code.
|
6
|
+
#
|
7
|
+
# In hindsight (being 20/20) this should have been named stack_configuration as now the stack UI is
|
8
|
+
# what allows the administrator to update/configure this information.
|
9
|
+
#
|
10
|
+
# Use of this class allows you to simply ask for the configuration parameter directly without
|
11
|
+
# first having to get an instance of it.
|
12
|
+
#
|
13
|
+
# SystemConfiguration.queue_impl #=> 'RedisQueue'
|
14
|
+
#
|
15
|
+
# This method only is allowed for accessors, you should NEVER set values on the SystemConfiguration
|
16
|
+
# unless you are updating via the Admin or Stack UI, or during testing to setup a specific configuration
|
17
|
+
# for that.
|
18
|
+
#
|
19
|
+
class SystemConfiguration
|
20
|
+
include Mongoid::Document
|
21
|
+
include Mongoid::Timestamps
|
22
|
+
|
23
|
+
field :environment, type: String, default: 'test'
|
24
|
+
# Queue Implementation
|
25
|
+
field :queue_impl, type: String, default: 'DelayedJob'
|
26
|
+
field :queue_base, type: String, default: 'test'
|
27
|
+
# AWS
|
28
|
+
field :aws_access_key_id, type: String
|
29
|
+
field :aws_secret_access_key, type: String
|
30
|
+
field :s3_bucket_name, type: String
|
31
|
+
field :cdn_url, type: String
|
32
|
+
# Redis
|
33
|
+
field :redis_queue_url, type: String, default: 'redis://localhost:6379/10'
|
34
|
+
# URLs
|
35
|
+
field :webui_url, type: String, default: 'https://cirrus.app47.com'
|
36
|
+
field :api_url, type: String, default: 'https://api.app47.mobi'
|
37
|
+
field :slack_api_url, type: String
|
38
|
+
field :company_name, type: String, default: 'App47'
|
39
|
+
field :api_version, type: String, default: '3.0'
|
40
|
+
#
|
41
|
+
# Validations
|
42
|
+
#
|
43
|
+
validates :environment, presence: true, uniqueness: true
|
44
|
+
#
|
45
|
+
# Call backs
|
46
|
+
#
|
47
|
+
after_save :clear_cache
|
48
|
+
|
49
|
+
class << self
|
50
|
+
#
|
51
|
+
# Fetch the system configuration based on environment name. First try the rails cache
|
52
|
+
# if not there, then go to the database.
|
53
|
+
#
|
54
|
+
# Also, if an argument error is thrown, then just fetch from the database.
|
55
|
+
#
|
56
|
+
def configuration
|
57
|
+
cache_key = "SystemConfiguration::#{ENV['RACK_ENV']}"
|
58
|
+
|
59
|
+
begin
|
60
|
+
config = App47Cache.get(cache_key) || SystemConfiguration.where(environment: ENV['RACK_ENV']).first
|
61
|
+
rescue ArgumentError
|
62
|
+
# This seems to happen in testing relative to Country, when it does, remove
|
63
|
+
# ourselves from the cache and return the DB entry.
|
64
|
+
App47Cache.delete cache_key
|
65
|
+
config = SystemConfiguration.where(environment: ENV['RACK_ENV']).first
|
66
|
+
end
|
67
|
+
if config.nil?
|
68
|
+
SystemConfiguration.create
|
69
|
+
else
|
70
|
+
App47Cache.set(cache_key, config, 300)
|
71
|
+
config
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def method_missing(method, *_args)
|
76
|
+
configuration.send method
|
77
|
+
end
|
78
|
+
|
79
|
+
def respond_to_missing?(method_name, _include_private = false)
|
80
|
+
SystemConfiguration.fields.include?(method_name.to_sym)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
#
|
87
|
+
# Clear the cache when the object is saved
|
88
|
+
#
|
89
|
+
def clear_cache
|
90
|
+
App47Cache.delete "SystemConfiguration::#{ENV['RACK_ENV']}"
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Time Bomb policy for this app
|
5
|
+
#
|
6
|
+
class TimeBombPolicy < AppPolicy
|
7
|
+
#
|
8
|
+
# Constants
|
9
|
+
#
|
10
|
+
OPTION_KILL = 'kill' unless defined? OPTION_KILL
|
11
|
+
OPTION_WIPE = 'wipe' unless defined? OPTION_WIPE
|
12
|
+
BOMB_OPTIONS = [OPTION_KILL, OPTION_WIPE].freeze unless defined? BOMB_OPTIONS
|
13
|
+
OPTION_AM = 'am' unless defined? OPTION_AM
|
14
|
+
OPTION_PM = 'pm' unless defined? OPTION_PM
|
15
|
+
TIME_OPTIONS = [OPTION_AM, OPTION_PM].freeze unless defined? TIME_OPTIONS
|
16
|
+
HOURS_TO_MS = 60 * 60 * 1000
|
17
|
+
UNIT_HOURS = 'hours' unless defined? UNIT_HOURS
|
18
|
+
UNIT_DAYS = 'days' unless defined? UNIT_DAYS
|
19
|
+
UNIT_WEEKS = 'weeks' unless defined? UNIT_WEEKS
|
20
|
+
UNIT_MONTHS = 'months' unless defined? UNIT_MONTHS
|
21
|
+
ALL_UNITS = [UNIT_HOURS, UNIT_DAYS, UNIT_WEEKS, UNIT_MONTHS].freeze unless defined? ALL_UNITS
|
22
|
+
#
|
23
|
+
# fields
|
24
|
+
#
|
25
|
+
field :expire_at, type: Integer
|
26
|
+
field :expiration_type, type: String, default: OPTION_KILL
|
27
|
+
field :expiration_message, type: String, default: 'The application has expired'
|
28
|
+
field :expiration_time_zone, type: String, default: 'local'
|
29
|
+
# field :kill_after_hours, type: Integer
|
30
|
+
field :kill_after_interval, type: Integer
|
31
|
+
field :kill_after_unit, type: String
|
32
|
+
field :wipe_after_interval, type: Integer
|
33
|
+
field :wipe_after_unit, type: String
|
34
|
+
# field :wipe_after_hours, type: Integer
|
35
|
+
field :inactivity_message, type: String, default: 'The application has been inactive for too long a period'
|
36
|
+
field :start_time, type: String
|
37
|
+
field :end_time, type: String
|
38
|
+
field :time_window_time_zone, type: String, default: 'local'
|
39
|
+
field :days, type: String, default: 'MTWHFSU'
|
40
|
+
field :time_window_message, type: String, default: 'The application is trying to run outside of the allowed time'
|
41
|
+
field :time_window_active, type: Boolean, default: false
|
42
|
+
field :expiration_active, type: Boolean, default: false
|
43
|
+
field :check_in_active, type: Boolean, default: false
|
44
|
+
|
45
|
+
#
|
46
|
+
# return the policy hash for this agent
|
47
|
+
#
|
48
|
+
def enforce_policy(agent)
|
49
|
+
policy = super.merge(enforce_time_bomb: 0)
|
50
|
+
return policy unless active?
|
51
|
+
|
52
|
+
time_bomb_policies = expiration_policy.merge(check_in_policy).merge(time_window_policy)
|
53
|
+
|
54
|
+
if time_bomb_policies.present?
|
55
|
+
policy[:time_bomb] = time_bomb_policies
|
56
|
+
policy[:enforce_time_bomb] = 1
|
57
|
+
end
|
58
|
+
|
59
|
+
policy
|
60
|
+
rescue StandardError => error
|
61
|
+
log_error("Unable to build time bomb policy for agent: #{agent.inspect} - #{inspect}", error)
|
62
|
+
# Return the default policy
|
63
|
+
{ enforce_time_bomb: 0 }
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Determine if we should enforce time of day policy
|
68
|
+
#
|
69
|
+
def time_window_policy
|
70
|
+
return {} unless time_window_active?
|
71
|
+
|
72
|
+
{
|
73
|
+
time_window:
|
74
|
+
{ start_time: start_time,
|
75
|
+
end_time: end_time,
|
76
|
+
time_zone: time_window_time_zone,
|
77
|
+
days: days,
|
78
|
+
message: time_window_message }
|
79
|
+
}
|
80
|
+
rescue StandardError => error
|
81
|
+
log_error("Unable to build time bomb time window policy: #{inspect}", error)
|
82
|
+
{}
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# determine if we should enforce the expire at policy
|
87
|
+
#
|
88
|
+
def expiration_policy
|
89
|
+
return {} unless expiration_active? && expire_at.present?
|
90
|
+
|
91
|
+
{
|
92
|
+
expire:
|
93
|
+
{
|
94
|
+
expiration_after: expire_at,
|
95
|
+
time_zone: expiration_time_zone,
|
96
|
+
type: expiration_type,
|
97
|
+
message: expiration_message
|
98
|
+
}
|
99
|
+
}
|
100
|
+
rescue StandardError => error
|
101
|
+
log_error("Unable to build time bomb expire at policy: #{inspect}", error)
|
102
|
+
{}
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Determine if the check in, or "Time bomb" policy should be enforced
|
107
|
+
#
|
108
|
+
def check_in_policy
|
109
|
+
return {} unless check_in_active
|
110
|
+
|
111
|
+
policy = { message: inactivity_message }
|
112
|
+
policy[:kill_after] = check_in_milliseconds(:kill) if kill_after_interval.present?
|
113
|
+
policy[:wipe_after] = check_in_milliseconds(:wipe) if wipe_after_interval.present?
|
114
|
+
{ check_in: policy }
|
115
|
+
rescue StandardError => error
|
116
|
+
log_error("Unable to build time bomb check in policy: #{inspect}", error)
|
117
|
+
{}
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Return the number of milli seconds between check ins
|
122
|
+
#
|
123
|
+
def check_in_milliseconds(type)
|
124
|
+
interval = send("#{type}_after_interval").to_i
|
125
|
+
case send "#{type}_after_unit"
|
126
|
+
when UNIT_HOURS
|
127
|
+
interval * HOURS_TO_MS
|
128
|
+
when UNIT_DAYS
|
129
|
+
24 * interval * HOURS_TO_MS
|
130
|
+
when UNIT_WEEKS
|
131
|
+
7 * 24 * interval * HOURS_TO_MS
|
132
|
+
when UNIT_MONTHS
|
133
|
+
30 * 24 * interval * HOURS_TO_MS
|
134
|
+
else
|
135
|
+
raise "Unknown unit: #{type}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/models/user.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# A user in the system is someone who has access to the enterprise app store
|
5
|
+
#
|
6
|
+
class User
|
7
|
+
include Mongoid::Document
|
8
|
+
include Mongoid::Timestamps
|
9
|
+
include App47EmailSendable
|
10
|
+
include App47Logger
|
11
|
+
include Searchable
|
12
|
+
#
|
13
|
+
# Fields
|
14
|
+
#
|
15
|
+
field :name, type: String
|
16
|
+
field :active, type: Boolean, default: true
|
17
|
+
field :pin_code, type: String
|
18
|
+
field :pin_code_locked, type: Boolean, default: false
|
19
|
+
#
|
20
|
+
# Relationships
|
21
|
+
#
|
22
|
+
belongs_to :account, inverse_of: :users
|
23
|
+
# has_and_belongs_to_many :groups, dependent: :nullify
|
24
|
+
has_and_belongs_to_many :allowed_apps, class_name: 'App', dependent: :nullify, inverse_of: :user_apps
|
25
|
+
has_and_belongs_to_many :test_apps, class_name: 'App', dependent: :nullify, inverse_of: :test_users
|
26
|
+
has_many :app_permissions, class_name: 'UserAppPermission', dependent: :destroy
|
27
|
+
has_many :devices, class_name: 'UserDevice'
|
28
|
+
|
29
|
+
#
|
30
|
+
# Return the unique set of application ids for this given user
|
31
|
+
#
|
32
|
+
def allowed_app_set
|
33
|
+
app_permissions.collect(&:app) + account.apps.distinct_all_users
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Find a user device by safely trying a number of approaches
|
38
|
+
# 1. By ID
|
39
|
+
# 2. By unique identifier
|
40
|
+
# 3. By app47 identifier
|
41
|
+
# 4. By token
|
42
|
+
#
|
43
|
+
def find_device_by(device_id)
|
44
|
+
raise 'Invalid ID' if device_id.blank?
|
45
|
+
|
46
|
+
devices.where(_id: device_id).first ||
|
47
|
+
devices.where(unique_identifier: device_id).first ||
|
48
|
+
devices.where(app47_identifier: device_id).first ||
|
49
|
+
devices.where(token: device_id).first
|
50
|
+
rescue StandardError
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|