rails_base 0.51.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 (194) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +32 -0
  4. data/Rakefile +32 -0
  5. data/app/assets/config/rails_base/manifest.js +3 -0
  6. data/app/assets/images/rails_base/favicon.ico +0 -0
  7. data/app/assets/javascripts/rails_base/admin.js +2 -0
  8. data/app/assets/javascripts/rails_base/application.js +22 -0
  9. data/app/assets/javascripts/rails_base/cable.js +13 -0
  10. data/app/assets/javascripts/rails_base/mfa_auth.coffee +3 -0
  11. data/app/assets/javascripts/rails_base/secondary_authentication.coffee +3 -0
  12. data/app/assets/javascripts/rails_base/sessions.js +152 -0
  13. data/app/assets/javascripts/rails_base/user_settings.coffee +3 -0
  14. data/app/assets/stylesheets/rails_base/admin.css +4 -0
  15. data/app/assets/stylesheets/rails_base/application.scss +15 -0
  16. data/app/assets/stylesheets/rails_base/mfa_auth.scss +3 -0
  17. data/app/assets/stylesheets/rails_base/scaffolds.scss +84 -0
  18. data/app/assets/stylesheets/rails_base/secondary_authentication.scss +3 -0
  19. data/app/assets/stylesheets/rails_base/user_settings.scss +3 -0
  20. data/app/controllers/rails_base/admin_controller.rb +315 -0
  21. data/app/controllers/rails_base/application_controller.rb +153 -0
  22. data/app/controllers/rails_base/errors_controller.rb +29 -0
  23. data/app/controllers/rails_base/mfa_auth_controller.rb +50 -0
  24. data/app/controllers/rails_base/secondary_authentication_controller.rb +224 -0
  25. data/app/controllers/rails_base/switch_user_controller.rb +29 -0
  26. data/app/controllers/rails_base/user_settings_controller.rb +81 -0
  27. data/app/controllers/rails_base/users/passwords_controller.rb +19 -0
  28. data/app/controllers/rails_base/users/registrations_controller.rb +80 -0
  29. data/app/controllers/rails_base/users/sessions_controller.rb +108 -0
  30. data/app/helpers/rails_base/admin_helper.rb +107 -0
  31. data/app/helpers/rails_base/appearance_helper.rb +58 -0
  32. data/app/helpers/rails_base/application_helper.rb +26 -0
  33. data/app/helpers/rails_base/capture_reference_helper.rb +57 -0
  34. data/app/helpers/rails_base/mfa_auth_helper.rb +2 -0
  35. data/app/helpers/rails_base/secondary_authentication_helper.rb +2 -0
  36. data/app/helpers/rails_base/user_field_validators.rb +108 -0
  37. data/app/helpers/rails_base/user_settings_helper.rb +22 -0
  38. data/app/jobs/rails_base/application_job.rb +10 -0
  39. data/app/jobs/twilio_job.rb +9 -0
  40. data/app/mailers/rails_base/application_mailer.rb +9 -0
  41. data/app/mailers/rails_base/email_verification_mailer.rb +22 -0
  42. data/app/mailers/rails_base/event_mailer.rb +16 -0
  43. data/app/models/admin_action.rb +119 -0
  44. data/app/models/rails_base/application_record.rb +22 -0
  45. data/app/models/rails_base/user_constants.rb +28 -0
  46. data/app/models/secret.rb +37 -0
  47. data/app/models/short_lived_data.rb +132 -0
  48. data/app/models/user.rb +143 -0
  49. data/app/services/rails_base/admin_risky_mfa_send.rb +80 -0
  50. data/app/services/rails_base/admin_update_attribute.rb +100 -0
  51. data/app/services/rails_base/authentication/authenticate_user.rb +28 -0
  52. data/app/services/rails_base/authentication/constants.rb +60 -0
  53. data/app/services/rails_base/authentication/decision_twofa_type.rb +76 -0
  54. data/app/services/rails_base/authentication/destroy_user.rb +45 -0
  55. data/app/services/rails_base/authentication/mfa_set_encrypt_token.rb +32 -0
  56. data/app/services/rails_base/authentication/mfa_validator.rb +88 -0
  57. data/app/services/rails_base/authentication/modify_password.rb +67 -0
  58. data/app/services/rails_base/authentication/send_forgot_password.rb +26 -0
  59. data/app/services/rails_base/authentication/send_login_mfa_to_user.rb +77 -0
  60. data/app/services/rails_base/authentication/send_verification_email.rb +103 -0
  61. data/app/services/rails_base/authentication/session_token_verifier.rb +31 -0
  62. data/app/services/rails_base/authentication/single_sign_on_create.rb +44 -0
  63. data/app/services/rails_base/authentication/single_sign_on_send.rb +101 -0
  64. data/app/services/rails_base/authentication/single_sign_on_verify.rb +42 -0
  65. data/app/services/rails_base/authentication/sso_verify_email.rb +43 -0
  66. data/app/services/rails_base/authentication/update_phone_send_verification.rb +46 -0
  67. data/app/services/rails_base/authentication/verify_forgot_password.rb +46 -0
  68. data/app/services/rails_base/email_change.rb +20 -0
  69. data/app/services/rails_base/encryption.rb +87 -0
  70. data/app/services/rails_base/name_change.rb +71 -0
  71. data/app/services/rails_base/service_base.rb +65 -0
  72. data/app/services/rails_base/service_logging.rb +23 -0
  73. data/app/views/layouts/rails_base/application.html.erb +185 -0
  74. data/app/views/layouts/rails_base/mailer.html.erb +13 -0
  75. data/app/views/layouts/rails_base/mailer.text.erb +1 -0
  76. data/app/views/new.html.erb +4 -0
  77. data/app/views/rails_base/admin/history.html.erb +26 -0
  78. data/app/views/rails_base/admin/index.html.erb +149 -0
  79. data/app/views/rails_base/admin/show_config.html.erb +18 -0
  80. data/app/views/rails_base/devise/confirmations/new.html.erb +16 -0
  81. data/app/views/rails_base/devise/mailer/confirmation_instructions.html.erb +5 -0
  82. data/app/views/rails_base/devise/mailer/email_changed.html.erb +7 -0
  83. data/app/views/rails_base/devise/mailer/password_change.html.erb +3 -0
  84. data/app/views/rails_base/devise/mailer/reset_password_instructions.html.erb +8 -0
  85. data/app/views/rails_base/devise/mailer/unlock_instructions.html.erb +7 -0
  86. data/app/views/rails_base/devise/passwords/edit.html.erb +25 -0
  87. data/app/views/rails_base/devise/passwords/new.html.erb +27 -0
  88. data/app/views/rails_base/devise/registrations/edit.html.erb +43 -0
  89. data/app/views/rails_base/devise/registrations/new.html.erb +123 -0
  90. data/app/views/rails_base/devise/sessions/new.html.erb +4 -0
  91. data/app/views/rails_base/devise/shared/_error_messages.html.erb +15 -0
  92. data/app/views/rails_base/devise/shared/_links.html.erb +25 -0
  93. data/app/views/rails_base/devise/unlocks/new.html.erb +16 -0
  94. data/app/views/rails_base/email_verification_mailer/email_verification.html.erb +25 -0
  95. data/app/views/rails_base/email_verification_mailer/event.html.erb +20 -0
  96. data/app/views/rails_base/email_verification_mailer/forgot_password.html.erb +22 -0
  97. data/app/views/rails_base/errors/internal_error.html.erb +1 -0
  98. data/app/views/rails_base/errors/not_found.html.erb +1 -0
  99. data/app/views/rails_base/errors/unacceptable.html.erb +1 -0
  100. data/app/views/rails_base/event_mailer/event.html.erb +10 -0
  101. data/app/views/rails_base/mfa_auth/mfa_code.html.erb +10 -0
  102. data/app/views/rails_base/secondary_authentication/after_email_login_session_new.html.erb +3 -0
  103. data/app/views/rails_base/secondary_authentication/forgot_password.html.erb +9 -0
  104. data/app/views/rails_base/secondary_authentication/remove_me.html.erb +1 -0
  105. data/app/views/rails_base/secondary_authentication/static.html.erb +5 -0
  106. data/app/views/rails_base/shared/_admin_actions_modal.html.erb +65 -0
  107. data/app/views/rails_base/shared/_admin_config_class.html.erb +52 -0
  108. data/app/views/rails_base/shared/_admin_history.html.erb +86 -0
  109. data/app/views/rails_base/shared/_admin_modify_email.html.erb +78 -0
  110. data/app/views/rails_base/shared/_admin_modify_name.html.erb +107 -0
  111. data/app/views/rails_base/shared/_admin_modify_phone.html.erb +87 -0
  112. data/app/views/rails_base/shared/_admin_modify_text.html.erb +35 -0
  113. data/app/views/rails_base/shared/_admin_risky_change.html.erb +57 -0
  114. data/app/views/rails_base/shared/_admin_risky_mfa.html.erb +74 -0
  115. data/app/views/rails_base/shared/_admin_selector_dropdown.html.erb +70 -0
  116. data/app/views/rails_base/shared/_admin_toggle_button.html.erb +72 -0
  117. data/app/views/rails_base/shared/_admin_warning_alert.html.erb +7 -0
  118. data/app/views/rails_base/shared/_appearance_mode_selector.html.erb +183 -0
  119. data/app/views/rails_base/shared/_custom_form_validation_javascript.html.erb +129 -0
  120. data/app/views/rails_base/shared/_enable_mfa_auth_modal.html.erb +105 -0
  121. data/app/views/rails_base/shared/_error_pages.html.erb +123 -0
  122. data/app/views/rails_base/shared/_logged_in_header.html.erb +123 -0
  123. data/app/views/rails_base/shared/_logged_out_header.html.erb +14 -0
  124. data/app/views/rails_base/shared/_mfa_input_layout.html.erb +5 -0
  125. data/app/views/rails_base/shared/_mfa_input_layout_default.html.erb +97 -0
  126. data/app/views/rails_base/shared/_mfa_input_layout_fallback.html.erb +55 -0
  127. data/app/views/rails_base/shared/_modify_mfa_auth_modal.html.erb +20 -0
  128. data/app/views/rails_base/shared/_password_confirm_javascript.html.erb +71 -0
  129. data/app/views/rails_base/shared/_reset_password_form.html.erb +111 -0
  130. data/app/views/rails_base/shared/_session_create_form.html.erb +32 -0
  131. data/app/views/rails_base/shared/_session_timeout_modal.html.erb +76 -0
  132. data/app/views/rails_base/switch_user/_widget.html.erb +5 -0
  133. data/app/views/rails_base/user_settings/_confirm_destroy_user.html.erb +42 -0
  134. data/app/views/rails_base/user_settings/_destroy_user.html.erb +106 -0
  135. data/app/views/rails_base/user_settings/_modify_name.html.erb +71 -0
  136. data/app/views/rails_base/user_settings/_modify_password.html.erb +101 -0
  137. data/app/views/rails_base/user_settings/_modify_password_update_password.html.erb +2 -0
  138. data/app/views/rails_base/user_settings/index.html.erb +54 -0
  139. data/config/initializers/01_rails_config.rb +19 -0
  140. data/config/initializers/admin_action_helper.rb +88 -0
  141. data/config/initializers/browser.rb +4 -0
  142. data/config/initializers/default_logged_in_headers.rb +23 -0
  143. data/config/initializers/devise.rb +314 -0
  144. data/config/initializers/encryption.rb +2 -0
  145. data/config/initializers/switch_user.rb +58 -0
  146. data/config/initializers/switch_user_helper.rb +29 -0
  147. data/config/locales/devise.en.yml +65 -0
  148. data/config/locales/en.yml +58 -0
  149. data/config/routes.rb +114 -0
  150. data/db/migrate/20210212175453_devise_create_rails_base_users.rb +56 -0
  151. data/db/migrate/20210212190537_create_rails_base_short_lived_data.rb +19 -0
  152. data/db/migrate/20210212192645_create_rails_base_secrets.rb +11 -0
  153. data/db/migrate/20210406015744_create_rails_base_admin_actions.rb +17 -0
  154. data/db/seeds.rb +23 -0
  155. data/lib/link_decision_helper.rb +71 -0
  156. data/lib/rails_base.rb +50 -0
  157. data/lib/rails_base/admin/action_cache.rb +99 -0
  158. data/lib/rails_base/admin/action_helper.rb +134 -0
  159. data/lib/rails_base/admin/default_index_tile.rb +176 -0
  160. data/lib/rails_base/admin/index_tile.rb +186 -0
  161. data/lib/rails_base/config.rb +52 -0
  162. data/lib/rails_base/configuration/active_job.rb +38 -0
  163. data/lib/rails_base/configuration/admin.rb +231 -0
  164. data/lib/rails_base/configuration/app.rb +52 -0
  165. data/lib/rails_base/configuration/appearance.rb +131 -0
  166. data/lib/rails_base/configuration/authentication.rb +37 -0
  167. data/lib/rails_base/configuration/base.rb +209 -0
  168. data/lib/rails_base/configuration/display/background_color.rb +25 -0
  169. data/lib/rails_base/configuration/display/btn_danger.rb +25 -0
  170. data/lib/rails_base/configuration/display/btn_dark.rb +25 -0
  171. data/lib/rails_base/configuration/display/btn_info.rb +25 -0
  172. data/lib/rails_base/configuration/display/btn_light.rb +25 -0
  173. data/lib/rails_base/configuration/display/btn_primary.rb +25 -0
  174. data/lib/rails_base/configuration/display/btn_secondary.rb +25 -0
  175. data/lib/rails_base/configuration/display/btn_success.rb +25 -0
  176. data/lib/rails_base/configuration/display/btn_warning.rb +25 -0
  177. data/lib/rails_base/configuration/display/footer.rb +54 -0
  178. data/lib/rails_base/configuration/display/navbar.rb +25 -0
  179. data/lib/rails_base/configuration/display/table_body.rb +25 -0
  180. data/lib/rails_base/configuration/display/table_header.rb +25 -0
  181. data/lib/rails_base/configuration/display/text.rb +26 -0
  182. data/lib/rails_base/configuration/exceptions_app.rb +25 -0
  183. data/lib/rails_base/configuration/login_behavior.rb +17 -0
  184. data/lib/rails_base/configuration/mailer.rb +116 -0
  185. data/lib/rails_base/configuration/mfa.rb +84 -0
  186. data/lib/rails_base/configuration/owner.rb +17 -0
  187. data/lib/rails_base/configuration/redis.rb +29 -0
  188. data/lib/rails_base/configuration/user.rb +43 -0
  189. data/lib/rails_base/engine.rb +51 -0
  190. data/lib/rails_base/version.rb +10 -0
  191. data/lib/tasks/rails_base_tasks.rake +4 -0
  192. data/lib/twilio_helper.rb +26 -0
  193. data/lib/velocity_limiter.rb +91 -0
  194. metadata +619 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2e9681ee6d443c2be30ecaf88c45d4f6d90983af39e79f1c7ca7caaac0d74887
4
+ data.tar.gz: 0ad7ffa1d15d9c7b63f1965f94d766d3ea8aadc64a48edc9ed899234b02f8030
5
+ SHA512:
6
+ metadata.gz: 695939c8b3ae5c89d7106fd7e9de827de327a8837c16b22275976c53c6736e94d92c3aa344293ce863a3e0c2cc60deef69cf2227396be3cf27011c7618c7cac8
7
+ data.tar.gz: ef5b03099e37b93a569d260def718202e18029eb4ffa22b33d70766338ae7cd05bf70ad7759d388384362f4d3740d05b16c12e86d2ef16bdc2c1509981705c3d
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2021 Matt Taylor
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ <a href="https://fury.co/f/partner">
2
+ <img src="//badge.fury.io/fp/gemfury.svg" alt="Private Repository">
3
+ </a>
4
+
5
+ # RailsBase
6
+ Short description and motivation.
7
+
8
+ ## Usage
9
+ How to use my plugin.
10
+
11
+ ## Installation
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'rails_base'
16
+ ```
17
+
18
+ And then execute:
19
+ ```bash
20
+ $ bundle
21
+ ```
22
+
23
+ Or install it yourself as:
24
+ ```bash
25
+ $ gem install rails_base
26
+ ```
27
+
28
+ ## Contributing
29
+ Contribution directions go here.
30
+
31
+ ## License
32
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'RailsBase'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1,3 @@
1
+ //= link_tree ../../images/rails_base/
2
+ //= link_directory ../../javascripts/rails_base .js
3
+ //= link_directory ../../stylesheets/rails_base .css
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,22 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
5
+ // vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ // = require rails-ujs
14
+ // = require activestorage
15
+ // = require turbolinks
16
+ // = require_tree .
17
+
18
+ // = require jquery3
19
+ // = require popper
20
+ // = require bootstrap-sprockets
21
+ // = require allow_numeric
22
+ // = require jquery.mask
@@ -0,0 +1,13 @@
1
+ // Action Cable provides the framework to deal with WebSockets in Rails.
2
+ // You can generate new channels where WebSocket features live using the `rails generate channel` command.
3
+ //
4
+ //= require action_cable
5
+ //= require_self
6
+ //= require_tree ./channels
7
+
8
+ (function() {
9
+ this.App || (this.App = {});
10
+
11
+ App.cable = ActionCable.createConsumer();
12
+
13
+ }).call(this);
@@ -0,0 +1,3 @@
1
+ # Place all the behaviors and hooks related to the matching controller here.
2
+ # All this logic will automatically be available in application.js.
3
+ # You can use CoffeeScript in this file: http://coffeescript.org/
@@ -0,0 +1,3 @@
1
+ # Place all the behaviors and hooks related to the matching controller here.
2
+ # All this logic will automatically be available in application.js.
3
+ # You can use CoffeeScript in this file: http://coffeescript.org/
@@ -0,0 +1,152 @@
1
+ // TODO: ADD a readme about how this works
2
+ // TODO: Clean this up
3
+ var SessionsSingleton = function () {
4
+ var SessionsClass = function SessionsClass() {
5
+ return {
6
+ sessionTimoutClock: undefined,
7
+ reminderClock: undefined,
8
+ reminderTime: 60000, // 1min prior to expiration
9
+ timeout: undefined,
10
+ url_get: undefined,
11
+ url_post: undefined,
12
+ ajax_timing: undefined,
13
+
14
+ init: function init(timeout, url_get, url_post, csrf, show_warning) {
15
+ var _self = this;
16
+ _self.timeout = timeout * 1000;
17
+ _self.url_get = url_get;
18
+ _self.url_post = url_post;
19
+ _self.csrf = csrf;
20
+ _self.show_warning = show_warning;
21
+
22
+ _self.logging(`Initialized. timeout ${_self.timeout}`)
23
+
24
+ _self.sessionTimoutClock = window.setTimeout(function () {
25
+ return _self.checkForWarning();
26
+ }, _self.timeout + 500);
27
+
28
+ if(!_self.show_warning){
29
+ return;
30
+ }
31
+ return _self.reminderClock = window.setTimeout(function () {
32
+ return _self.checkForWarning();
33
+ }, _self.timeout - _self.reminderTime);
34
+ },
35
+ checkForWarning: function checkForWarning() {
36
+ var _self = this;
37
+ _self.ajax_timing = new Date();
38
+ _self.logging(`Heartbeat warning`)
39
+ $.ajax({
40
+ type: 'GET',
41
+ url: _self.url_get,
42
+ success: function success(result) {
43
+ _self.logging(`TTL check success: ${JSON.stringify(result)}`)
44
+ _self.warningHeartbeatSuccess(result);
45
+ },
46
+ error: function error() {
47
+ _self.logging(`TTL check failed. Reloading page`)
48
+ return _self.doRedirect();
49
+ }
50
+ });
51
+ },
52
+ checkForSessionHeartbeat: function checkForSessionHeartbeat(){
53
+ var _self = this;
54
+ _self.ajax_timing = new Date()
55
+ $.ajax({
56
+ type: 'GET',
57
+ url: _self.url_get,
58
+ success: function success(result) {
59
+ _self.logging(`TTL check success: ${JSON.stringify(result)}`)
60
+ _self.ajaxPollTtlServer(result);
61
+ },
62
+ error: function error() {
63
+ _self.logging(`TTL check failed. Reloading page`)
64
+ return _self.doRedirect();
65
+ }
66
+ });
67
+ },
68
+ latency: function latency() {
69
+ var _self = this;
70
+ // milliseconds difference
71
+ return ((new Date() - _self.ajax_timing));
72
+ },
73
+ warningHeartbeatSuccess: function warningHeartbeatSuccess(result) {
74
+ var _self = this;
75
+ var ttlMs = result.ttl * 1000
76
+ var latency = _self.latency();
77
+ var skew = (ttlMs - _self.reminderTime);
78
+ _self.logging(`latency ${latency}ms`)
79
+ _self.logging(`skew ${skew}ms`)
80
+ // if the skew more than 5 seconds
81
+ // reset the clock to that time
82
+ if(skew>5000) {
83
+ _self.logging(`Skew is high. Resetting clock`)
84
+ _self.resetClock(ttlMs)
85
+ closeSessionWarning();
86
+ } else {
87
+ _self.logging(`Within skew. Showing countdown`)
88
+
89
+ showSessionWarning(result.ttl);
90
+ }
91
+ },
92
+ ajaxPollTtlServer: function ajaxPollTtlServer() {
93
+ var _self = this;
94
+ _self.ajax_timing = new Date()
95
+ $.ajax({
96
+ type: 'POST',
97
+ url: _self.url_post,
98
+ headers: { 'X-CSRF-Token': _self.csrf },
99
+ success: function success(result) {
100
+ _self.logging(`POST Heartbeat success: ${JSON.stringify(result)}`)
101
+ // TTL comes from server as seconds -- convert to ms
102
+ closeSessionWarning();
103
+ return _self.resetClock(result.ttl * 1000);
104
+ },
105
+ error: function error() {
106
+ _self.logging(`POST TTL check failed. Reloading page`)
107
+ return _self.doRedirect();
108
+ }
109
+ });
110
+ },
111
+ doRedirect: function doRedirect() {
112
+ return window.location.search += '&timeout';
113
+ },
114
+ resetClock: function resetClock(timeout) {
115
+ var _self = this;
116
+ var timeout = timeout / 1000;
117
+ _self.logging(`Clock Reset timout: ${timeout}`)
118
+ var url_get = _self.url_get;
119
+ var url_post = _self.url_post;
120
+ var csrf = _self.csrf;
121
+ var show_warning = _self.show_warning;
122
+ _self.destroy();
123
+ return _self.init(timeout, url_get, url_post, csrf, show_warning);
124
+ },
125
+ destroy: function destroy() {
126
+ var _self = this;
127
+ window.clearTimeout(_self.reminderClock);
128
+ window.clearTimeout(_self.sessionTimoutClock);
129
+ _self.sessionTimoutClock = undefined;
130
+ _self.reminderClock = undefined;
131
+ _self.timeout = undefined;
132
+ return;
133
+ },
134
+ logging: function logging(msg){
135
+ console.log(`${new Date().toJSON()}: SessionManager - ${msg}`)
136
+ }
137
+ };
138
+ };
139
+
140
+ var instance = undefined;
141
+ return {
142
+ getInstance: function getInstance() {
143
+ if (instance == null) {
144
+ instance = new SessionsClass();
145
+ instance.constructor = null;
146
+ }
147
+ return instance;
148
+ }
149
+ };
150
+ }();
151
+
152
+ var sessionManager = SessionsSingleton.getInstance();
@@ -0,0 +1,3 @@
1
+ # Place all the behaviors and hooks related to the matching controller here.
2
+ # All this logic will automatically be available in application.js.
3
+ # You can use CoffeeScript in this file: http://coffeescript.org/
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
6
+ * vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ */
14
+
15
+ @import "bootstrap";
@@ -0,0 +1,3 @@
1
+ // Place all the styles related to the mfa_auth controller here.
2
+ // They will automatically be included in application.css.
3
+ // You can use Sass (SCSS) here: http://sass-lang.com/
@@ -0,0 +1,84 @@
1
+ body {
2
+ background-color: #fff;
3
+ color: #333;
4
+ margin: 33px;
5
+ font-family: verdana, arial, helvetica, sans-serif;
6
+ font-size: 13px;
7
+ line-height: 18px;
8
+ }
9
+
10
+ p, ol, ul, td {
11
+ font-family: verdana, arial, helvetica, sans-serif;
12
+ font-size: 13px;
13
+ line-height: 18px;
14
+ }
15
+
16
+ pre {
17
+ background-color: #eee;
18
+ padding: 10px;
19
+ font-size: 11px;
20
+ }
21
+
22
+ a {
23
+ color: #000;
24
+
25
+ &:visited {
26
+ color: #666;
27
+ }
28
+
29
+ &:hover {
30
+ color: #fff;
31
+ background-color: #000;
32
+ }
33
+ }
34
+
35
+ th {
36
+ padding-bottom: 5px;
37
+ }
38
+
39
+ td {
40
+ padding: 0 5px 7px;
41
+ }
42
+
43
+ div {
44
+ &.field, &.actions {
45
+ margin-bottom: 10px;
46
+ }
47
+ }
48
+
49
+ #notice {
50
+ color: green;
51
+ }
52
+
53
+ .field_with_errors {
54
+ padding: 2px;
55
+ background-color: red;
56
+ display: table;
57
+ }
58
+
59
+ #error_explanation {
60
+ width: 450px;
61
+ border: 2px solid red;
62
+ padding: 7px 7px 0;
63
+ margin-bottom: 20px;
64
+ background-color: #f0f0f0;
65
+
66
+ h2 {
67
+ text-align: left;
68
+ font-weight: bold;
69
+ padding: 5px 5px 5px 15px;
70
+ font-size: 12px;
71
+ margin: -7px -7px 0;
72
+ background-color: #c00;
73
+ color: #fff;
74
+ }
75
+
76
+ ul li {
77
+ font-size: 12px;
78
+ list-style: square;
79
+ }
80
+ }
81
+
82
+ label {
83
+ display: block;
84
+ }
@@ -0,0 +1,3 @@
1
+ // Place all the styles related to the secondary_authentication controller here.
2
+ // They will automatically be included in application.css.
3
+ // You can use Sass (SCSS) here: http://sass-lang.com/
@@ -0,0 +1,3 @@
1
+ // Place all the styles related to the user_settings controller here.
2
+ // They will automatically be included in application.css.
3
+ // You can use Sass (SCSS) here: http://sass-lang.com/
@@ -0,0 +1,315 @@
1
+ module RailsBase
2
+ class AdminController < ApplicationController
3
+ before_action :authenticate_user!, except: [:sso_retrieve]
4
+ before_action :admin_user?, only: [:index, :config, :sso_send]
5
+ before_action :validate_token!, only: [:update_email, :update_phone]
6
+ skip_before_action :admin_reset_impersonation_session!
7
+
8
+ include AdminHelper
9
+
10
+ # GET admin
11
+ def index
12
+ end
13
+
14
+ # GET admin
15
+ def show_config
16
+ unless RailsBase.config.admin.config_page?(current_user)
17
+ flash[:alert] = 'You do not have correct permissions to view admin config'
18
+ redirect_to RailsBase.url_routes.authenticated_root_path
19
+ return
20
+ end
21
+ end
22
+
23
+ #POST admin/sso/:id
24
+ def sso_send
25
+ unless RailsBase.config.admin.sso_tile_users.call(admin_user)
26
+ flash[:alert] = 'You do not have correct permissions to Send an SSO'
27
+ redirect_to RailsBase.url_routes.admin_base_path
28
+ return
29
+ end
30
+
31
+ user = User.find params[:id]
32
+
33
+ local_params = {
34
+ user: user,
35
+ token_length: Authentication::Constants::SSO_SEND_LENGTH,
36
+ uses: Authentication::Constants::SSO_SEND_USES,
37
+ reason: Authentication::Constants::SSO_REASON,
38
+ expires_at: Authentication::Constants::SSO_EXPIRES.from_now,
39
+ url_redirect: RailsBase.url_routes.user_settings_path
40
+ }
41
+
42
+ status = RailsBase::Authentication::SingleSignOnSend.call(local_params)
43
+ if status.failure?
44
+ @_admin_action_struct = false
45
+ flash[:alert] = "Failed to send SSO to user via #{status.sso_destination}. #{status.message}"
46
+ else
47
+ @_admin_action_struct = RailsBase::AdminStruct.new(nil, nil, user)
48
+ flash[:notice] = "Successfully sent SSO to user via #{status.sso_destination}."
49
+ end
50
+ redirect_to RailsBase.url_routes.admin_base_path
51
+ end
52
+
53
+ #GET auth/sso/:data
54
+ def sso_retrieve
55
+ local_params = {
56
+ data: params[:data],
57
+ reason: Authentication::Constants::SSO_REASON.to_s,
58
+ }
59
+ local_params[:bypass] = true if current_user
60
+
61
+ status = RailsBase::Authentication::SingleSignOnVerify.call(local_params)
62
+
63
+ if status.failure? && current_user.nil?
64
+ flash[:alert] = "SSO login failed. #{status.message}"
65
+ redirect_to RailsBase.url_routes.unauthenticated_root_path
66
+ return
67
+ end
68
+
69
+ if status.should_fail
70
+ flash[:notice] = "SSO failed but you are already logged in."
71
+ redirect_to status.url_redirect
72
+ return
73
+ end
74
+
75
+ if current_user
76
+ flash[:notice] = "SSO success. You are already logged in."
77
+ else
78
+ sign_in(status.user)
79
+ flash[:notice] = "SSO success. You are now logged in."
80
+ end
81
+ redirect_to status.url_redirect
82
+ end
83
+
84
+ # POST admin/ack
85
+ def ack
86
+ success = true
87
+ begin
88
+ time = Time.at params[:time].to_i
89
+ RailsBase::Admin::ActionCache.instance.delete_actions_since!(user: current_user, time: time)
90
+ RailsBase::Admin::ActionCache.instance.update_last_viewed(user: current_user, time: time)
91
+ rescue StandardError => e
92
+ logger.error(e.message)
93
+ logger.error('Failed to acknowledge users admion actions')
94
+ success = false
95
+ end
96
+ if success
97
+ render json: { success: true }
98
+ else
99
+ render json: { success: false }, status: 500
100
+ end
101
+ end
102
+
103
+ # GET admin/history
104
+ def history
105
+ unless RailsBase.config.admin.enable_history_by_user?(current_user)
106
+ flash[:alert] = 'You do not have correct permissions to view admin history'
107
+ redirect_to RailsBase.url_routes.authenticated_root_path
108
+ return
109
+ end
110
+
111
+ @starting_admin = paginate_get_admins_array.last
112
+ @starting_user = paginate_get_users_array.last
113
+ session[:rails_base_paginate_start_user] = @starting_user[1]
114
+ session[:rails_base_paginate_start_admin] = @starting_admin[1]
115
+ @starting_page = 1
116
+ @count_on_page = AdminAction::DEFAULT_PAGE_COUNT
117
+ end
118
+
119
+ # POST admin/history
120
+ def history_paginate
121
+ unless RailsBase.config.admin.enable_history_by_user?(current_user)
122
+ render json: { success: false, msg: 'Incorrect permissions to view this page' }, status: 403
123
+ return
124
+ end
125
+
126
+ @starting_admin = paginate_get_admins_array.find { |u| u[1] == params[:admin].to_i } || paginate_get_admins_array.last
127
+ @starting_user = paginate_get_users_array.find { |u| u[1] == params[:user].to_i } || paginate_get_users_array.last
128
+
129
+ @starting_page = paginate_admin_what_page
130
+ @count_on_page = params[:pagination_count].to_i
131
+
132
+ if paginate_diff_id?(type: :admin) || paginate_diff_id?(type: :user)
133
+ logger.warn "Admin or User has been selected. paginating from first page"
134
+ @starting_page = 1
135
+ end
136
+
137
+ session[:rails_base_paginate_start_user] = @starting_user[1]
138
+ session[:rails_base_paginate_start_admin] = @starting_admin[1]
139
+ begin
140
+ html = render_to_string(partial: 'rails_base/shared/admin_history')
141
+ rescue StandardError => e
142
+ logger.error(e.message)
143
+ logger.error('Failed to render html for history')
144
+ html
145
+ end
146
+
147
+ if html
148
+ render json: { success: true, html: html, per_page: @count_on_page, page: @starting_page }
149
+ else
150
+ render json: { success: false }, status: 500
151
+ end
152
+ end
153
+
154
+ # POST admin/update
155
+ def update_attribute
156
+ update = RailsBase::AdminUpdateAttribute.call(params: params, admin_user: admin_user)
157
+ if update.success?
158
+ @_admin_action_struct = RailsBase::AdminStruct.new(update.original_attribute, update.attribute, update.model)
159
+ render json: { success: true, message: update.message, attribute: update.attribute }
160
+ else
161
+ @_admin_action_struct = false
162
+ render json: { success: false, message: update.message }, status: 404
163
+ end
164
+ end
165
+
166
+ def update_name
167
+ unless RailsBase.config.admin.name_tile_users?(admin_user)
168
+ flash[:alert] = 'You do not have correct permissions to change a users name'
169
+ redirect_to RailsBase.url_routes.admin_base_path
170
+ return
171
+ end
172
+ user = User.find(params[:id])
173
+
174
+ result = NameChange.call(
175
+ first_name: params[:first_name],
176
+ last_name: params[:last_name],
177
+ current_user: user,
178
+ admin_user_id: accurate_admin_user
179
+ )
180
+
181
+ if result.success?
182
+ @_admin_action_struct = RailsBase::AdminStruct.new(result.original_name, result.name_change, user)
183
+ msg = "Successfully changed name from [#{result.original_name}] to [#{result.name_change}]"
184
+ render json: { success: true, message: msg, full_name: result.name_change }
185
+ else
186
+ @_admin_action_struct = false
187
+ render json: { success: false, message: "Failed to change #{user.id} name" }, status: 404
188
+ end
189
+ end
190
+
191
+ def update_email
192
+ unless RailsBase.config.admin.email_tile_users?(admin_user)
193
+ flash[:alert] = 'You do not have correct permissions to change a users name'
194
+ redirect_to RailsBase.url_routes.admin_base_path
195
+ return
196
+ end
197
+
198
+ user = User.find(params[:id])
199
+ result = EmailChange.call(email: params[:email], user: user)
200
+ if result.success?
201
+ @_admin_action_struct = RailsBase::AdminStruct.new(result.original_email, result.new_email, user)
202
+ msg = "Successfully changed email from [#{result.original_email}] to [#{result.new_email}]"
203
+ render json: { success: true, message: msg, email: result.new_email }
204
+ else
205
+ @_admin_action_struct = false
206
+ render json: { success: false, message: result.message }, status: 404
207
+ end
208
+ end
209
+
210
+ def update_phone
211
+ begin
212
+ params[:value] = params[:phone_number].gsub(/\D/,'')
213
+ rescue
214
+ params[:value] = ''
215
+ params[:_fail_] = true
216
+ end
217
+ params[:attribute] = :phone_number
218
+ update_attribute
219
+ end
220
+
221
+ # POST admin/validate_intent/send
222
+ def send_2fa
223
+ reason = "#{SESSION_REASON_BASE}-#{SecureRandom.uuid}"
224
+ result = AdminRiskyMfaSend.call(user: admin_user, reason: reason)
225
+ if result.success?
226
+ session[SESSION_REASON_KEY] = reason
227
+ render json: { success: true, message: result.message }
228
+ else
229
+ render json: { success: false, message: result.message }, status: 404
230
+ end
231
+ end
232
+
233
+ # POST admin/validate_intent/verify
234
+ def verify_2fa
235
+ unless modify_id = params[:modify_id]
236
+ logger.warn("Failed to find #{modify_id} in payload")
237
+ render json: { success: false, message: 'Hmm. Something fishy happend. Failed to find text to modify' }, status: 404
238
+ return
239
+ end
240
+
241
+ unless render_partial = SECOND_MODAL_MAPPING[params[:modal_mapping].to_sym] rescue nil
242
+ logger.warn("Mapping [#{params[:modal_mapping]}] is not defined. Expected part of #{SECOND_MODAL_MAPPING.keys}")
243
+ render json: { success: false, message: 'Hmm. Something fishy happend. Failed to find modal mapping' }, status: 404
244
+ return
245
+ end
246
+
247
+ unless user = User.find(params[:id]) rescue nil
248
+ logger.warn("Failed to find id:[#{params[:id]}] ")
249
+ render json: { success: false, message: 'Hmm. Something fishy happend. Failed to find associated id' }, status: 404
250
+ return
251
+ end
252
+
253
+ params = {
254
+ session_mfa_user_id: admin_user.id,
255
+ current_user: admin_user,
256
+ input_reason: session_reason,
257
+ params: parse_mfa_to_obj
258
+ }
259
+ result = RailsBase::Authentication::MfaValidator.call(params)
260
+ encrypt = RailsBase::Authentication::MfaSetEncryptToken.call(user: admin_user, purpose: session_reason, expires_at: 1.minute.from_now)
261
+
262
+ begin
263
+ html = render_to_string(partial: render_partial, locals: { user: user, modify_id: modify_id })
264
+ rescue StandardError => e
265
+ logger.warn("#{e.message}")
266
+ logger.warn("Failed to render html correctly")
267
+ html = nil
268
+ end
269
+ if html.nil?
270
+ logger.warn("Failed to find render html correctly")
271
+ render json: { success: false, message: 'Apologies. Wee are struggling to render the page. Please try again later' }, status: 500
272
+ return
273
+ end
274
+
275
+ if result.success?
276
+ session[:mfa_randomized_token] = encrypt.encrypted_val
277
+ render json: { success: true, message: result.message, html: html }
278
+ else
279
+ render json: { success: false, message: result.message }, status: 404
280
+ end
281
+ end
282
+
283
+ # POST admin/impersonate
284
+ def switch_back
285
+ unless original_user_id = session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_USERID_KEY]
286
+ # something wonky happend to the session. Kick user back to homepage and relogin
287
+ warden.logout(:user)
288
+ flash[:alert] = 'Unknown failure. Please log in again'
289
+ redirect_to RailsBase.url_routes.unauthenticated_root_path
290
+ session.clear
291
+ return
292
+ end
293
+
294
+ # use warden here so that we dont add to devise signin/out hooks
295
+ warden.set_user(User.find(original_user_id), scope: :user)
296
+
297
+ # Critical step to ensure subsequent apps dont think we are an impersonation
298
+ session.delete(RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON)
299
+
300
+ flash[:notice] = 'You no longer have an identity crisis. You are back to normal.'
301
+ redirect_to RailsBase.url_routes.admin_base_path
302
+ end
303
+
304
+ private
305
+
306
+ def validate_token!
307
+ @token_verifier =
308
+ RailsBase::Authentication::SessionTokenVerifier.call(mfa_randomized_token: session[:mfa_randomized_token], purpose: session_reason)
309
+ return if @token_verifier.success?
310
+
311
+ render json: { success: false, message: 'Authorization token has expired or not present. Try again' }, status: 403
312
+ return false
313
+ end
314
+ end
315
+ end