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
@@ -0,0 +1,153 @@
1
+ module RailsBase
2
+ class ApplicationController < ActionController::Base
3
+ before_action :configure_permitted_parameters, if: :devise_controller?
4
+ before_action :set_time_zone
5
+ before_action :is_timeout_error?
6
+ before_action :admin_reset_impersonation_session!
7
+ before_action :footer_mode_case
8
+
9
+ before_action :populate_admin_actions, if: -> { RailsBase.config.admin.enable_actions? }
10
+ after_action :capture_admin_action
11
+
12
+ include ApplicationHelper
13
+ include AppearanceHelper
14
+ include CaptureReferenceHelper
15
+
16
+ def set_time_zone
17
+ return unless RailsBase.config.user.tz_user_defined?
18
+ return if current_user.nil?
19
+
20
+ # esape this since this is not signed
21
+ offset = cookies[TIMEZONE_OFFSET_COOKIE].to_i
22
+
23
+ cookie_tz = ActiveSupport::TimeZone[((offset * -1) / 60.0)]
24
+
25
+ if session_tz = session[TIMEZONE_SESSION_NAME]
26
+ # if session exists
27
+ if cookie_tz && session_tz != cookie_tz.name
28
+ # if cookie exists and cookie_tz does not match, update db and session
29
+ current_user.update_tz(tz_name: cookie_tz.name)
30
+ session[TIMEZONE_SESSION_NAME] = cookie_tz.name
31
+ end
32
+ else
33
+ # if session timezone does not exist, attempt to push to DB and set to session
34
+ current_user.update_tz(tz_name: cookie_tz.name)
35
+ session[TIMEZONE_SESSION_NAME] = cookie_tz.name
36
+ end
37
+ Thread.current[TIMEZONE_THREAD_NAME] = session[TIMEZONE_SESSION_NAME]
38
+ end
39
+
40
+ def is_timeout_error?
41
+ return if current_user || !params.keys.include?('timeout')
42
+
43
+ flash[:notice] = nil
44
+ flash[:alert] = 'Your session expired. Please sign in again to continue.'
45
+ end
46
+
47
+ def admin_impersonation_session?
48
+ return false if current_user.nil?
49
+ return false unless encrypted_val = session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON].presence
50
+
51
+ token = admin_get_token(encrypted_val: encrypted_val)
52
+ if token.failure?
53
+ logger.warn "Failed to parse encrypted token. Either expired or was not present"
54
+ flash[:alert] = 'Failed to retrieve Session token. Retry action'
55
+ redirect_to RailsBase.url_routes.admin_base_path
56
+ return false
57
+ else
58
+ logger.info "Found original_admin_user_id"
59
+ @original_admin_user_id = token.user_id
60
+ end
61
+ true
62
+ end
63
+
64
+ def admin_reset_impersonation_session!
65
+ return unless admin_impersonation_session?
66
+
67
+ # at this point we know there is an impersonation
68
+ admin_user = User.find @original_admin_user_id
69
+ admin_set_token_on_session(admin_user: admin_user, other_user: current_user)
70
+ end
71
+
72
+ def admin_user?
73
+ return if RailsBase.config.admin.view_admin_page?(current_user)
74
+
75
+ session.clear
76
+ sign_out(current_user)
77
+
78
+ flash[:alert] = 'Unauthorized action. You have been signed out'
79
+ redirect_to RailsBase.url_routes.unauthenticated_root_path
80
+ end
81
+
82
+ def populate_admin_actions
83
+ return if session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON].present?
84
+ return if current_user.nil?
85
+ return unless request.fullpath == RailsBase.url_routes.authenticated_root_path
86
+
87
+ @__admin_actions_array = AdminAction.get_cache_items(user: current_user, alltime: true)
88
+ end
89
+
90
+ def capture_admin_action
91
+ # ToDo: Turn this into a service
92
+ # ToDo: All admin actions come there here: Allow this to be confirugable on or off
93
+ _controller = ActiveSupport::Inflector.camelize("#{params[:controller]}_controller")
94
+ admin_user =
95
+ if _controller == RailsBase::AdminController.to_s
96
+ current_user
97
+ else
98
+ @original_admin_user_id ? User.find(@original_admin_user_id) : nil
99
+ end
100
+
101
+ # Means we are not in the admin controller or we are not impersonating
102
+ return if admin_user.nil? || @_admin_action_struct == false
103
+
104
+ # Admin action for all routes
105
+ (RailsBase::Admin::ActionHelper.actions.dig(RailsBase::Admin::ActionHelper::ACTIONS_KEY) || []).each do |helper|
106
+ Rails.logger.warn("Admin Action for every action")
107
+ helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
108
+ end
109
+
110
+ # Admin action for all controller routes
111
+ object = RailsBase::Admin::ActionHelper.actions.dig(_controller, RailsBase::Admin::ActionHelper::CONTROLLER_ACTIONS_KEY) || []
112
+ object.each do |helper|
113
+ Rails.logger.warn("Admin Action for #{_controller}")
114
+ helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
115
+ end
116
+
117
+ # Admin action for all controller action specific routes
118
+ (RailsBase::Admin::ActionHelper.actions.dig(_controller, params[:action].to_s) || []).each do |helper|
119
+ Rails.logger.warn("Admin Action for #{_controller}##{params[:action]}")
120
+ helper.call(req: request, params: params, admin_user: admin_user, user: current_user, struct: @_admin_action_struct)
121
+ end
122
+ end
123
+
124
+ protected
125
+
126
+ def admin_get_token(encrypted_val:)
127
+ params = {
128
+ mfa_randomized_token: encrypted_val,
129
+ purpose: RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON,
130
+ }
131
+ RailsBase::Authentication::SessionTokenVerifier.call(params)
132
+ end
133
+
134
+ def admin_set_token_on_session(admin_user:, other_user:)
135
+ if admin_user.id != other_user.id #dont do this if you are yourself
136
+ logger.warn { "Admin user [#{admin_user.id}] is impersonating user #{other_user.id}" }
137
+ params = {
138
+ user: admin_user,
139
+ purpose: RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON,
140
+ expires_at: RailsBase::Authentication::Constants::ADMIN_MAX_IDLE_TIME.from_now
141
+ }
142
+ encrpytion = RailsBase::Authentication::MfaSetEncryptToken.call(params)
143
+ session[RailsBase::Authentication::Constants::ADMIN_REMEMBER_REASON] = encrpytion.encrypted_val
144
+ end
145
+ end
146
+
147
+ def configure_permitted_parameters
148
+ added_attrs = [:phone_number, :email, :password, :password_confirmation, :remember_me]
149
+ devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
150
+ devise_parameter_sanitizer.permit :account_update, keys: added_attrs
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,29 @@
1
+ module RailsBase
2
+ class ErrorsController < ApplicationController
3
+ before_action :set_variable
4
+
5
+ def not_found
6
+ @status = 404
7
+ @message = "The Page can't be found"
8
+ render template: 'rails_base/errors/not_found'
9
+ end
10
+
11
+ def unacceptable
12
+ @status = 422
13
+ @message = "Client Error. Please retry"
14
+ render template: 'rails_base/errors/unacceptable'
15
+ end
16
+
17
+ def internal_error
18
+ @status = 500
19
+ @message = "An Internal Error has occured"
20
+ render template: 'rails_base/errors/internal_error'
21
+ end
22
+
23
+ private
24
+
25
+ def set_variable
26
+ @error_page = true
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,50 @@
1
+ module RailsBase
2
+ class MfaAuthController < ApplicationController
3
+ before_action :validate_token, only: [:mfa_code, :mfa_code_verify, :resend_mfa]
4
+
5
+ # GET /mfa_verify
6
+ def mfa_code
7
+ @masked_phone = User.find(@token_verifier.user_id).masked_phone
8
+ end
9
+
10
+ # POST /mfa_verify
11
+ def mfa_code_verify
12
+ mfa_validity = RailsBase::Authentication::MfaValidator.call(params: params, session_mfa_user_id: @token_verifier.user_id)
13
+ if mfa_validity.failure?
14
+ redirect_to(mfa_validity.redirect_url, alert: mfa_validity.message)
15
+ return
16
+ end
17
+
18
+ mfa_validity.user.set_last_mfa_login!
19
+
20
+ sign_in(mfa_validity.user)
21
+ redirect_to RailsBase.url_routes.authenticated_root_path, notice: "Welcome #{mfa_validity.user.full_name}"
22
+ end
23
+
24
+ # POST /mfa_verify
25
+ def resend_mfa
26
+ user = User.find(@token_verifier.user_id)
27
+ mfa_token = RailsBase::Authentication::SendLoginMfaToUser.call(user: user)
28
+ if mfa_token.failure?
29
+ flash[:error] = mfa_token.message
30
+ session[:mfa_randomized_token] = nil
31
+ redirect_to RailsBase.url_routes.new_user_session_path, email: params.dig(:user,:email), alert: mfa_token.message
32
+ return
33
+ end
34
+ expired_at = Time.zone.parse(@token_verifier.expires_at)
35
+ session[:mfa_randomized_token] =
36
+ RailsBase::Authentication::MfaSetEncryptToken.call(user: user, expires_at: expired_at).encrypted_val
37
+
38
+ redirect_to RailsBase.url_routes.mfa_code_path, notice: "MFA has been sent via SMS to number on file"
39
+ end
40
+
41
+ def validate_token
42
+ @token_verifier =
43
+ RailsBase::Authentication::SessionTokenVerifier.call(mfa_randomized_token: session[:mfa_randomized_token])
44
+ return if @token_verifier.success?
45
+
46
+ redirect_to RailsBase.url_routes.new_user_session_path, alert: @token_verifier.message
47
+ return false
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,224 @@
1
+ module RailsBase
2
+ class SecondaryAuthenticationController < ApplicationController
3
+ before_action :authenticate_user!, only: [:remove_phone_mfa, :confirm_phone_registration]
4
+
5
+ before_action :validate_token!, only: [:resend_email, :wait, :confirm_phone_registration]
6
+
7
+ before_action :json_validate_current_user!, only: [:phone_registration]
8
+
9
+ # GET auth/wait
10
+ def static
11
+ return unless validate_token!(purpose: Authentication::Constants::SSOVE_PURPOSE)
12
+
13
+ if flash[:notice].nil? && flash[:alert].nil?
14
+ flash[:notice] = Authentication::Constants::STATIC_WAIT_FLASH
15
+ end
16
+ end
17
+
18
+ def remove_me
19
+ end
20
+
21
+ def testing_route
22
+ Rails.logger.error("This will cause an error to be thrown")
23
+ raise ArgumentError, 'Boo'
24
+ end
25
+
26
+ # POST auth/resend_email
27
+ def resend_email
28
+ user = User.find @token_verifier.user_id
29
+ email_verification = Authentication::SendVerificationEmail.call(user: user, reason: Authentication::Constants::SVE_LOGIN_REASON)
30
+ params =
31
+ if email_verification.failure?
32
+ { alert: email_verification.message }
33
+ else
34
+ { notice: I18n.t('authentication.resend_email', email: user.email) }
35
+ end
36
+ redirect_to RailsBase.url_routes.auth_static_path, params
37
+ end
38
+
39
+ # GET auth/email/:data
40
+ def email_verification
41
+ verify = Authentication::SsoVerifyEmail.call(verification: params[:data])
42
+
43
+ if verify.failure?
44
+ redirect_to(verify.redirect_url, alert: verify.message)
45
+ return
46
+ end
47
+
48
+ session[:mfa_randomized_token] = verify.encrypted_val
49
+ redirect_to RailsBase.url_routes.login_after_email_path
50
+ end
51
+
52
+ # GET auth/login
53
+ def after_email_login_session_new
54
+ return unless validate_token!(purpose: Authentication::Constants::SSOVE_PURPOSE)
55
+
56
+ @user = User.new
57
+ if flash[:alert].nil? && flash[:notice].nil?
58
+ flash[:notice] = I18n.t('authentication.after_email_login_session_new')
59
+ end
60
+ end
61
+
62
+ # POST auth/login
63
+ def after_email_login_session_create
64
+ return unless validate_token!(purpose: Authentication::Constants::SSOVE_PURPOSE)
65
+
66
+ flash[:notice] = nil
67
+ flash[:alert] = nil
68
+ authenticate = Authentication::AuthenticateUser.call(email: params[:user][:email], password: params[:user][:password])
69
+ if authenticate.failure?
70
+ flash[:alert] = authenticate.message
71
+ @user = User.new(email: params[:user][:email])
72
+ render :after_email_login_session_new
73
+ return
74
+ end
75
+
76
+ sign_in(authenticate.user)
77
+ flash[:notice] = I18n.t('authentication.after_email_login_session_create')
78
+ redirect_to RailsBase.url_routes.authenticated_root_path
79
+ end
80
+
81
+ # POST auth/phone
82
+ def phone_registration
83
+ result = Authentication::UpdatePhoneSendVerification.call(user: current_user, phone_number: params[:phone_number])
84
+ if result.failure?
85
+ render :json => { error: I18n.t('request_response.teapot.fail'), msg: result.message }.to_json, :status => 418
86
+ return
87
+ end
88
+ session[:mfa_randomized_token] = result.mfa_randomized_token
89
+
90
+ render :json => { status: :success, message: I18n.t('request_response.teapot.valid') }
91
+ end
92
+
93
+ # POST auth/phone/mfa
94
+ def confirm_phone_registration
95
+ mfa_validity = Authentication::MfaValidator.call(current_user: current_user, params: params, session_mfa_user_id: @token_verifier.user_id)
96
+ if mfa_validity.failure?
97
+ redirect_to RailsBase.url_routes.authenticated_root_path, alert: I18n.t('authentication.confirm_phone_registration.fail', message: mfa_validity.message)
98
+ return
99
+ end
100
+
101
+ current_user.update!(mfa_enabled: true)
102
+
103
+ redirect_to RailsBase.url_routes.authenticated_root_path, notice: I18n.t('authentication.confirm_phone_registration.valid')
104
+ end
105
+
106
+ # DELETE auth/phone/disable
107
+ def remove_phone_mfa
108
+ current_user.update!(mfa_enabled: false, last_mfa_login: nil)
109
+ redirect_to RailsBase.url_routes.authenticated_root_path, notice: I18n.t('authentication.remove_phone_mfa')
110
+ end
111
+
112
+ # GET auth/email/forgot/:data
113
+ def forgot_password
114
+ result = Authentication::VerifyForgotPassword.call(data: params[:data])
115
+
116
+ if result.failure?
117
+ redirect_to result.redirect_url, alert: result.message
118
+ return
119
+ end
120
+ session[:mfa_randomized_token] = result.encrypted_val
121
+ flash[:notice] =
122
+ if @mfa_flow = result.mfa_flow
123
+ I18n.t('authentication.forgot_password.2fa')
124
+ else
125
+ I18n.t('authentication.forgot_password.base')
126
+ end
127
+ @user = result.user
128
+ @data = params[:data]
129
+ end
130
+
131
+ # POST auth/email/forgot/:data
132
+ def forgot_password_with_mfa
133
+ return unless validate_token!(purpose: Authentication::Constants::VFP_PURPOSE)
134
+
135
+ # datum is expired because it was used with #forgot_password method
136
+ # we dont care, we just want to ensure the correct user (multiple verification ways)
137
+ # -- validate user by datum
138
+ # -- validate user by short lived token
139
+ # -- validate user by mfa_token
140
+ # -- When all match by user and within the lifetime of the short lived token... we b gucci uber super secure/over engineered
141
+ expired_datum = ShortLivedData.get_by_data(data: params[:data], reason: Authentication::Constants::VFP_REASON)
142
+
143
+ unless expired_datum
144
+ redirect_to(RailsBase.url_routes.new_user_password_path, alert: I18n.t('authentication.forgot_password_with_mfa.expired_datum'))
145
+ return
146
+ end
147
+
148
+ result = Authentication::MfaValidator.call(params: params, session_mfa_user_id: @token_verifier.user_id, current_user: expired_datum.user)
149
+ if result.failure?
150
+ redirect_to(RailsBase.url_routes.new_user_password_path, alert: result.message)
151
+ return
152
+ end
153
+
154
+ @mfa_flow = false
155
+ @data = params[:data]
156
+ @user = result.user
157
+ flash[:notice] = I18n.t('authentication.forgot_password_with_mfa.valid_mfa')
158
+ render :forgot_password
159
+ end
160
+
161
+ # POST auth/email/reset/:data
162
+ def reset_password
163
+ return unless validate_token!(purpose: Authentication::Constants::VFP_PURPOSE)
164
+
165
+ result = Authentication::ModifyPassword.call(password: params[:user][:password], password_confirmation: params[:user][:password_confirmation], data: params[:data], user_id: @token_verifier.user_id, flow: :forgot_password)
166
+ if result.failure?
167
+ redirect_to RailsBase.url_routes.new_user_password_path, alert: result.message
168
+ return
169
+ end
170
+
171
+ redirect_to RailsBase.url_routes.authenticated_root_path, notice: I18n.t('authentication.reset_password')
172
+ end
173
+
174
+ # GET auth/validate/:data
175
+ def sso_login
176
+ input_params = {
177
+ data: params[:data],
178
+ reason: RailsBase::Authentication::Constants::SSO_LOGIN_REASON
179
+ }
180
+ sso_decision = RailsBase::Authentication::SingleSignOnVerify.call(input_params)
181
+ if sso_decision.failure?
182
+ if current_user.nil?
183
+ flash[:alert] = I18n.t('authentication.sso_login.fail') + sso_decision.message
184
+ redirect_to RailsBase.url_routes.unauthenticated_root_path
185
+ return
186
+ else
187
+ logger.info('User is logged in but failed the SSO login')
188
+ end
189
+ end
190
+
191
+
192
+ sign_in(sso_decision.user) if current_user.nil?
193
+
194
+ url =
195
+ if RailsBase.route_exist?(sso_decision.url_redirect)
196
+ sso_decision.url_redirect
197
+ else
198
+ logger.debug("Failed to find #{sso_decision.url_redirect}. Redirecing to root")
199
+ RailsBase.url_routes.authenticated_root_path
200
+ end
201
+
202
+ flash[:notice] = I18n.t('authentication.sso_login.valid')
203
+ redirect_to url
204
+ end
205
+
206
+ private
207
+
208
+ def json_validate_current_user!
209
+ return if current_user
210
+
211
+ render json: { error: "Unauthorized" }.to_json, :status => 401
212
+ return false
213
+ end
214
+
215
+ def validate_token!(purpose: Authentication::Constants::MSET_PURPOSE)
216
+ @token_verifier =
217
+ Authentication::SessionTokenVerifier.call(purpose: purpose, mfa_randomized_token: session[:mfa_randomized_token])
218
+ return true if @token_verifier.success?
219
+
220
+ redirect_to RailsBase.url_routes.new_user_session_path, alert: @token_verifier.message
221
+ return false
222
+ end
223
+ end
224
+ end