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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +2 -0
  4. data/lib/api_models/version.rb +5 -0
  5. data/lib/api_models.rb +68 -0
  6. data/lib/models/account.rb +39 -0
  7. data/lib/models/agent.rb +439 -0
  8. data/lib/models/app.rb +18 -0
  9. data/lib/models/app47_cache.rb +69 -0
  10. data/lib/models/app_active_build.rb +32 -0
  11. data/lib/models/app_policy.rb +24 -0
  12. data/lib/models/app_shield_policy.rb +35 -0
  13. data/lib/models/authorized_user_policy.rb +44 -0
  14. data/lib/models/b2b_app.rb +8 -0
  15. data/lib/models/cat/customer.rb +9 -0
  16. data/lib/models/cat/customer_device.rb +10 -0
  17. data/lib/models/cl/customer.rb +9 -0
  18. data/lib/models/cl/customer_device.rb +10 -0
  19. data/lib/models/commerce_app_store.rb +8 -0
  20. data/lib/models/concerns/app47_app_analyzable.rb +46 -0
  21. data/lib/models/concerns/app47_app_buildable.rb +46 -0
  22. data/lib/models/concerns/app47_app_configurable.rb +34 -0
  23. data/lib/models/concerns/app47_app_policies.rb +59 -0
  24. data/lib/models/concerns/app47_cdn_url.rb +50 -0
  25. data/lib/models/concerns/app47_email_sendable.rb +29 -0
  26. data/lib/models/concerns/app47_logger.rb +109 -0
  27. data/lib/models/concerns/checkin_able.rb +28 -0
  28. data/lib/models/concerns/searchable.rb +54 -0
  29. data/lib/models/configuration_constraint.rb +22 -0
  30. data/lib/models/configuration_group.rb +50 -0
  31. data/lib/models/configuration_rule.rb +58 -0
  32. data/lib/models/device.rb +124 -0
  33. data/lib/models/external_app.rb +15 -0
  34. data/lib/models/gehc/customer.rb +17 -0
  35. data/lib/models/gehc/customer_device.rb +23 -0
  36. data/lib/models/group.rb +40 -0
  37. data/lib/models/internal_app.rb +11 -0
  38. data/lib/models/metric_data_job.rb +16 -0
  39. data/lib/models/option.rb +37 -0
  40. data/lib/models/pin_code_policy.rb +50 -0
  41. data/lib/models/platform.rb +26 -0
  42. data/lib/models/platform_model.rb +14 -0
  43. data/lib/models/product_app.rb +22 -0
  44. data/lib/models/product_support_app.rb +19 -0
  45. data/lib/models/queue_manager.rb +67 -0
  46. data/lib/models/redis_configuration.rb +137 -0
  47. data/lib/models/sso_ad_group.rb +7 -0
  48. data/lib/models/sso_ad_server.rb +13 -0
  49. data/lib/models/sso_ad_user.rb +13 -0
  50. data/lib/models/sso_azure_server.rb +18 -0
  51. data/lib/models/sso_directory_group.rb +13 -0
  52. data/lib/models/sso_directory_server.rb +21 -0
  53. data/lib/models/sso_google_server.rb +13 -0
  54. data/lib/models/sso_ldap_group.rb +8 -0
  55. data/lib/models/sso_ldap_rest_server.rb +34 -0
  56. data/lib/models/sso_ldap_server.rb +19 -0
  57. data/lib/models/sso_ldap_user.rb +7 -0
  58. data/lib/models/sso_oauth_server.rb +16 -0
  59. data/lib/models/sso_saml_v2_server.rb +25 -0
  60. data/lib/models/sso_server.rb +38 -0
  61. data/lib/models/sso_user.rb +13 -0
  62. data/lib/models/system_configuration.rb +92 -0
  63. data/lib/models/time_bomb_policy.rb +138 -0
  64. data/lib/models/user.rb +53 -0
  65. data/lib/models/user_app_permission.rb +16 -0
  66. data/lib/models/user_device.rb +83 -0
  67. data/lib/models/version_management_policy.rb +113 -0
  68. data/lib/models/web_app.rb +12 -0
  69. 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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Active Directory Group
5
+ #
6
+ class SsoAdGroup < SsoDirectoryGroup
7
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Connection to AD Server
5
+ #
6
+ class SsoAdServer < SsoDirectoryServer
7
+ #
8
+ # Return the AD Server display name.
9
+ #
10
+ def display_name
11
+ 'AD Server'
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Active Directory (AD) User
5
+ #
6
+ class SsoAdUser < SsoUser
7
+ #
8
+ # Fields
9
+ #
10
+ field :dn, type: String
11
+ field :user_id, type: String
12
+ field :last_synchronized_at, type: DateTime
13
+ 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,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Google OAuth 2.0
5
+ #
6
+ class SsoGoogleServer < SsoOauthServer
7
+ #
8
+ # Google Server SSO name
9
+ #
10
+ def display_name
11
+ 'Google OAuth 2.0'
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Light Weight Active Directory Group
5
+ #
6
+ class SsoLdapGroup < SsoDirectoryGroup
7
+ # Marker class for now
8
+ 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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Light Weight Directory Access Protocol (LDAP) User
5
+ #
6
+ class SsoLdapUser < SsoAdUser
7
+ 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
@@ -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