rails_base 0.75.6 → 0.80.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/rails_base/rails_base_query_checker.js +36 -0
  3. data/app/controllers/rails_base/admin_controller.rb +54 -9
  4. data/app/controllers/rails_base/mfa/evaluation_controller.rb +59 -0
  5. data/app/controllers/rails_base/mfa/register/sms_controller.rb +45 -0
  6. data/app/controllers/rails_base/mfa/register/totp_controller.rb +42 -0
  7. data/app/controllers/rails_base/mfa/validate/sms_controller.rb +83 -0
  8. data/app/controllers/rails_base/mfa/validate/totp_controller.rb +35 -0
  9. data/app/controllers/rails_base/secondary_authentication_controller.rb +40 -96
  10. data/app/controllers/rails_base/user_settings_controller.rb +11 -1
  11. data/app/controllers/rails_base/users/registrations_controller.rb +1 -1
  12. data/app/controllers/rails_base/users/sessions_controller.rb +16 -13
  13. data/app/controllers/rails_base_application_controller.rb +96 -1
  14. data/app/jobs/twilio_job.rb +1 -1
  15. data/app/mailers/rails_base/email_verification_mailer.rb +6 -4
  16. data/app/mailers/rails_base/event_mailer.rb +4 -2
  17. data/app/mailers/rails_base/mailer_kwarg_inject.rb +31 -0
  18. data/app/models/rails_base/user_constants.rb +6 -3
  19. data/app/models/rails_base/user_helper/totp/backup_method_options.rb +33 -0
  20. data/app/models/rails_base/user_helper/totp/class_options.rb +35 -0
  21. data/app/models/rails_base/user_helper/totp/consume_method_options.rb +60 -0
  22. data/app/models/rails_base/user_helper/totp.rb +41 -0
  23. data/app/models/user.rb +28 -13
  24. data/app/services/rails_base/authentication/constants.rb +1 -1
  25. data/app/services/rails_base/authentication/decision_twofa_type.rb +61 -30
  26. data/app/services/rails_base/authentication/send_forgot_password.rb +0 -1
  27. data/app/services/rails_base/authentication/single_sign_on_send.rb +1 -1
  28. data/app/services/rails_base/authentication/sso_verify_email.rb +3 -1
  29. data/app/services/rails_base/authentication/update_phone_send_verification.rb +2 -2
  30. data/app/services/rails_base/authentication/verify_forgot_password.rb +8 -11
  31. data/app/services/rails_base/mfa/decision.rb +70 -0
  32. data/app/services/rails_base/mfa/encrypt_token.rb +34 -0
  33. data/app/services/rails_base/mfa/sms/remove.rb +35 -0
  34. data/app/services/rails_base/{authentication/send_login_mfa_to_user.rb → mfa/sms/send.rb} +19 -13
  35. data/app/services/rails_base/mfa/sms/validate.rb +105 -0
  36. data/app/services/rails_base/mfa/strategy/base.rb +44 -0
  37. data/app/services/rails_base/mfa/strategy/every_request.rb +14 -0
  38. data/app/services/rails_base/mfa/strategy/skip_every_request.rb +14 -0
  39. data/app/services/rails_base/mfa/strategy/time_based.rb +24 -0
  40. data/app/services/rails_base/mfa/totp/helper.rb +21 -0
  41. data/app/services/rails_base/mfa/totp/otp_metadata.rb +19 -0
  42. data/app/services/rails_base/mfa/totp/remove.rb +40 -0
  43. data/app/services/rails_base/mfa/totp/validate_code.rb +52 -0
  44. data/app/services/rails_base/mfa/totp/validate_temporary_code.rb +37 -0
  45. data/app/services/rails_base/mfa.rb +18 -0
  46. data/app/services/rails_base/name_change.rb +3 -3
  47. data/app/views/layouts/rails_base/application.html.erb +22 -6
  48. data/app/views/rails_base/devise/passwords/new.html.erb +1 -1
  49. data/app/views/rails_base/mfa/_switch_mfa_type.html.erb +17 -0
  50. data/app/views/rails_base/mfa/validate/sms/sms_event_input.html.erb +2 -0
  51. data/app/views/rails_base/mfa/validate/totp/totp_event_input.html.erb +1 -0
  52. data/app/views/rails_base/secondary_authentication/reset_password_input.html.erb +4 -0
  53. data/app/views/rails_base/shared/_enable_mfa_auth_modal.html.erb +1 -1
  54. data/app/views/rails_base/shared/_logged_in_header.html.erb +1 -25
  55. data/app/views/rails_base/shared/_modify_mfa_auth_modal.html.erb +102 -3
  56. data/app/views/rails_base/shared/mfa/sms/_login_input.html.erb +13 -0
  57. data/app/views/rails_base/shared/mfa/totp/_login_input.html.erb +22 -0
  58. data/app/views/rails_base/shared/totp/_add_authenticator.html.erb +76 -0
  59. data/app/views/rails_base/shared/totp/_add_authenticator_modal.html.erb +25 -0
  60. data/app/views/rails_base/shared/totp/_confirm_code.html.erb +31 -0
  61. data/app/views/rails_base/shared/totp/_confirm_code_ajax.html.erb +3 -0
  62. data/app/views/rails_base/shared/totp/_confirm_code_rest.html.erb +5 -0
  63. data/app/views/rails_base/shared/totp/_remove_authenticator_modal.html.erb +50 -0
  64. data/app/views/rails_base/user_settings/index.html.erb +84 -1
  65. data/config/initializers/admin_action_helper.rb +44 -8
  66. data/config/routes.rb +42 -7
  67. data/db/migrate/20240808013706_add_totp_to_users.rb +9 -0
  68. data/db/migrate/20240825012724_reconfigure_mfa_variable_names.rb +10 -0
  69. data/lib/rails_base/admin/action_helper.rb +0 -1
  70. data/lib/rails_base/admin/default_index_tile.rb +3 -3
  71. data/lib/rails_base/config.rb +26 -22
  72. data/lib/rails_base/configuration/admin.rb +5 -5
  73. data/lib/rails_base/configuration/base.rb +1 -0
  74. data/lib/rails_base/configuration/mfa.rb +27 -60
  75. data/lib/rails_base/configuration/totp.rb +82 -0
  76. data/lib/rails_base/configuration/twilio.rb +85 -0
  77. data/lib/rails_base/mfa_event.rb +186 -0
  78. data/lib/rails_base/version.rb +3 -3
  79. data/lib/rails_base.rb +1 -0
  80. data/lib/twilio_helper.rb +3 -3
  81. metadata +129 -64
  82. data/app/controllers/rails_base/mfa_auth_controller.rb +0 -50
  83. data/app/services/rails_base/authentication/mfa_set_encrypt_token.rb +0 -32
  84. data/app/services/rails_base/authentication/mfa_validator.rb +0 -88
  85. data/app/views/rails_base/mfa_auth/mfa_code.html.erb +0 -11
  86. data/app/views/rails_base/secondary_authentication/forgot_password.html.erb +0 -9
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsBase::Mfa::Totp
4
+ class Remove < RailsBase::ServiceBase
5
+ include Helper
6
+
7
+ delegate :user, to: :context
8
+ delegate :otp_code, to: :context
9
+ delegate :password, to: :context
10
+
11
+ def call
12
+ password_result = RailsBase::Authentication::AuthenticateUser.(email: user.email, current_user: user, password: password)
13
+
14
+ if password_result.failure?
15
+ log(level: :debug, msg: "#{lgp} Password validation failed. Unable to continue")
16
+ context.fail!(message: password_result.message)
17
+ end
18
+
19
+ valid_code = ValidateCode.(user: user, otp_code: otp_code)
20
+ if valid_code.failure?
21
+ log(level: :debug, msg: "#{lgp} Code Validation failed.")
22
+ context.fail!(message: "#{valid_code.message}. Please try again.")
23
+ end
24
+
25
+ begin
26
+ user.reset_otp!
27
+ log(level: :info, msg: "#{lgp} TOTP successfully removed from User Account")
28
+ rescue => e
29
+ context.fail!(message: "Yikes! Unknown error occured. TOTP was not removed from the account.")
30
+ end
31
+ end
32
+
33
+ def validate!
34
+ raise "Expected user to be a User." unless User === user
35
+ raise "Expected otp_code to be present" if otp_code.nil?
36
+ raise "Expected password to be present" if password.nil?
37
+ end
38
+ end
39
+ end
40
+
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsBase::Mfa::Totp
4
+ class ValidateCode < RailsBase::ServiceBase
5
+ include Helper
6
+
7
+ delegate :user, to: :context
8
+ delegate :otp_code, to: :context
9
+
10
+ def call
11
+ return if validate_and_consume_otp
12
+
13
+ context.fail!(message: "Invalid TOTP code")
14
+ end
15
+
16
+ def validate_and_consume_otp
17
+ if user.consumed_timestep
18
+ # reconstruct the timestamp of the last consumed timestep
19
+ after_timestamp = user.consumed_timestep * otp.interval
20
+ end
21
+
22
+ if otp.verify(otp_code.gsub(/\s+/, ""), drift_behind: User.totp_drift_behind, drift_ahead: User.totp_drift_ahead, after: after_timestamp)
23
+ log(level: :debug, msg: "#{lgp} Correct code provided")
24
+ return consume_otp!
25
+ else
26
+ log(level: :debug, msg: "#{lgp} InValid code provided")
27
+ end
28
+
29
+ false
30
+ end
31
+
32
+ # An OTP cannot be used more than once in a given timestep
33
+ # Storing timestep of last valid OTP is sufficient to satisfy this requirement
34
+ def consume_otp!
35
+ timestep = Time.now.utc.to_i / otp.interval
36
+ if user.consumed_timestep != timestep
37
+ user.consumed_timestep = timestep
38
+ log(level: :debug, msg: "#{lgp} Consuming timestep based on code input")
39
+ return user.save(validate: false)
40
+ end
41
+
42
+ log(level: :debug, msg: "#{lgp} Timestep for code was already consumed. Invalid code")
43
+ false
44
+ end
45
+
46
+ def validate!
47
+ raise "Expected user to be a User. " unless User === user
48
+ raise "Expected otp_code to be present" if otp_code.nil?
49
+ raise "Expected `otp_secret` passed in or `otp_secret` present on User" if secret.nil?
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsBase::Mfa::Totp
4
+ class ValidateTemporaryCode < RailsBase::ServiceBase
5
+ include Helper
6
+
7
+ delegate :user, to: :context
8
+ delegate :otp_code, to: :context
9
+
10
+ def call
11
+ valid_code = ValidateCode.(user: user, otp_code: otp_code, otp_secret: current_secret)
12
+ if valid_code.failure?
13
+ log(level: :debug, msg: "#{lgp} Code Validation failed. Will not persist temporary token")
14
+ context.fail!(message: valid_code.message)
15
+ end
16
+
17
+ log(level: :info, msg: "#{lgp} correctly validated authenticator code. Persisting")
18
+ user.persist_otp_metadata!
19
+ if user.otp_backup_codes.empty?
20
+ backup_codes = user.generate_otp_backup_codes!
21
+ log(level: :info, msg: "#{lgp} first authenticator added. Generating Backup Codes. Will also return backup codes to user")
22
+ context.backup_codes = backup_codes
23
+ else
24
+ log(level: :warn, msg: "#{lgp} added additional Authenticator. Will NOT provide backup codes")
25
+ end
26
+ end
27
+
28
+ def current_secret
29
+ @current_secret ||= user.reload.otp_metadata(safe: true, use_existing_temp: true)[:secret]
30
+ end
31
+
32
+ def validate!
33
+ raise "Expected user to be a User. " unless User === user
34
+ raise "Expected otp_code to be present" if otp_code.nil?
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsBase::Mfa
4
+ MFA_DECISIONS = [
5
+ OTP = :otp,
6
+ SMS = :sms,
7
+ NONE = :none
8
+ ]
9
+
10
+ def self.mfa_link(mfa:, mfa_event:)
11
+ case mfa
12
+ when OTP
13
+ { method: :get, link: RailsBase.url_routes.mfa_with_event_path(mfa_event:, type: mfa) }
14
+ when SMS
15
+ { method: :post, link: RailsBase.url_routes.sms_validate_send_event_path(mfa_event:) }
16
+ end
17
+ end
18
+ end
@@ -41,9 +41,9 @@ class RailsBase::NameChange < RailsBase::ServiceBase
41
41
  return if admin_user_id
42
42
 
43
43
  RailsBase::EmailVerificationMailer.event(
44
- user: current_user,
45
- event: "Succesfull name change",
46
- msg: "We changed the name on your account from #{original_name} to #{context.name_change}."
44
+ current_user,
45
+ "Succesfull name change",
46
+ "We changed the name on your account from #{original_name} to #{context.name_change}."
47
47
  ).deliver_me
48
48
  end
49
49
 
@@ -83,12 +83,28 @@
83
83
  <%= render partial: 'rails_base/shared/logged_out_header'%>
84
84
  <% end %>
85
85
  <% if notice %>
86
- <div class="alert alert-success alert-dismissible fade show" role="alert">
87
- <%= notice %>
88
- <button type="button" class="close" data-dismiss="alert" aria-label="Close">
89
- <span aria-hidden="true">&times;</span>
90
- </button>
91
- </div>
86
+ <% if session.delete(:add_mfa_button) %>
87
+ <div class="alert alert-success alert-dismissible fade show" role="alert">
88
+ <div class="row">
89
+ <div class="col-md-6">
90
+ <%= notice %>
91
+ </div>
92
+ <div class="col-md-6">
93
+ <%= link_to "Enable MFA", RailsBase.url_routes.user_settings_path(openmfa: true), method: :get, class: "btn btn-light float-right" %>
94
+ </div>
95
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
96
+ <span aria-hidden="true">&times;</span>
97
+ </button>
98
+ </div>
99
+ </div>
100
+ <% else %>
101
+ <div class="alert alert-success alert-dismissible fade show" role="alert">
102
+ <%= notice %>
103
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
104
+ <span aria-hidden="true">&times;</span>
105
+ </button>
106
+ </div>
107
+ <% end %>
92
108
  <% end %>
93
109
  <% if alert %>
94
110
  <div class="alert alert-danger alert-dismissible fade show" role="alert">
@@ -10,7 +10,7 @@
10
10
  <%= f.label :email, class: 'text-center' %><br>
11
11
  <%= f.email_field :email, autofocus: true, autocomplete: "email", placeholder: :email, class: 'form-control'%>
12
12
  <div class="invalid-feedback">
13
- Password Confirmation does not match Password
13
+ Valid email required
14
14
  </div>
15
15
  </div>
16
16
  </div>
@@ -0,0 +1,17 @@
1
+ <% if mfa_options.length > 0 %>
2
+ <br>
3
+ <div class="row">
4
+ <div class="col-md-6 offset-3">
5
+ <hr>
6
+ </div>
7
+ </div>
8
+ <% end %>
9
+
10
+ <% mfa_options.each do |metadata| %>
11
+ <br>
12
+ <div class="row">
13
+ <div class="col-md-6 offset-md-3">
14
+ <%= link_to metadata[:text], metadata[:link], method: metadata[:method], class: "btn btn-warning btn-block" %>
15
+ </div>
16
+ </div>
17
+ <% end %>
@@ -0,0 +1,2 @@
1
+
2
+ <%= render partial: 'rails_base/shared/mfa/sms/login_input', locals: { mfa_options: @mfa_options, mfa_event: @__rails_base_mfa_event } %>
@@ -0,0 +1 @@
1
+ <%= render partial: 'rails_base/shared/mfa/totp/login_input', locals: { endpoint: RailsBase.url_routes.totp_validate_event_path(mfa_event: @__rails_base_mfa_event.event), type: :rest, mfa_options: @mfa_options } %>
@@ -0,0 +1,4 @@
1
+
2
+ <h2 class='text-center'>Reset your password <%= @user.full_name%></h2>
3
+
4
+ <%= render partial: 'rails_base/shared/reset_password_form', locals: { sign_in_flow: true, url: RailsBase.url_routes.reset_password_auth_path(data: @data) }%>
@@ -86,7 +86,7 @@
86
86
  var data = { 'phone_number': number}
87
87
  $.ajax({
88
88
  type: "POST",
89
- url: "<%= RailsBase.url_routes.phone_registration_path%>",
89
+ url: "<%= RailsBase.url_routes.phone_registration_path %>",
90
90
  headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') },
91
91
  dataType: 'json',
92
92
  data: data,
@@ -1,5 +1,5 @@
1
1
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
2
- <a class="navbar-brand" href="#"><%= RailsBase.config.app.web_title_logged_in(current_user)%></a>
2
+ <a class="navbar-brand" href="<%= RailsBase.url_routes.authenticated_root_path %>"><%= RailsBase.config.app.web_title_logged_in(current_user)%></a>
3
3
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
4
4
  <span class="navbar-toggler-icon"></span>
5
5
  </button>
@@ -41,22 +41,6 @@
41
41
  </button>
42
42
  </div>
43
43
  <div class="modal-body ">
44
- <div class='row'>
45
- <div class='col'>
46
- <% if RailsBase.config.mfa.enable? %>
47
- <% if current_user.mfa_enabled %>
48
- <button type="button" class="btn btn-block btn_info close-me" data-toggle="modal" data-target="#modifyMfamodal">
49
- Modify 2fa Auth
50
- </button>
51
- <% else %>
52
- <button type="button" class="btn btn-block btn_info close-me" data-toggle="modal" data-target="#enableMfamodal">
53
- Enable 2fa Auth
54
- </button>
55
- <% end %>
56
- <% end %>
57
- </div>
58
- </div>
59
- </br>
60
44
  <div class='row'>
61
45
  <div class='col'>
62
46
  <a class="btn btn_info btn-block" href="<%=RailsBase.url_routes.user_settings_path %>" role="button">Modify User</a>
@@ -88,14 +72,6 @@
88
72
  </div>
89
73
  </div>
90
74
 
91
- <% if RailsBase.config.mfa.enable? %>
92
- <% if current_user.mfa_enabled %>
93
- <%= render partial: 'rails_base/shared/modify_mfa_auth_modal'%>
94
- <% else %>
95
- <%= render partial: 'rails_base/shared/enable_mfa_auth_modal'%>
96
- <% end %>
97
- <% end %>
98
-
99
75
  <% if @__admin_actions_array && @__admin_actions_array.present? %>
100
76
  <%= render partial: 'rails_base/shared/admin_actions_modal'%>
101
77
  <% end %>
@@ -1,4 +1,10 @@
1
- <% confirm = "Disabling 2fa on your account will make it more vulnerable. Are you sure you want to disable two factor authentication via SMS text?" %>
1
+ <%
2
+ code_length = RailsBase::Authentication::Constants::MFA_LENGTH
3
+ values = [
4
+ { name: '#smsRemovalPassword', criteria: { required: true }},
5
+ { name: '#smsRemovalCode', criteria: { required: true, pattern: :numeric, min_length: code_length }}
6
+ ]
7
+ %>
2
8
 
3
9
  <div class="modal fade" id="modifyMfamodal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
4
10
  <div class="modal-dialog modal-lg" role="document">
@@ -9,8 +15,49 @@
9
15
  <span aria-hidden="true">&times;</span>
10
16
  </button>
11
17
  </div>
12
- <div class="modal-body">
13
- <%= button_to "Disable 2fa", RailsBase.url_routes.remove_phone_registration_mfa_path, data: { confirm: confirm }, method: :delete, class: "btn btn_danger btn-block" %>
18
+ <div class="modal-body mfaSmsModalBody">
19
+ <div class="mfaSmsStatusDiv"></div>
20
+ <%= form_with(url: RailsBase.url_routes.remove_phone_registration_mfa_path, method: :delete) do |form| %>
21
+ <div id="confirmSmsAuthenticationCode">
22
+ <div class="smsInput">
23
+ <div class="input-group input-group-lg">
24
+ <div class="input-group-prepend">
25
+ <span class="input-group-text" id="smsInput-Prepend">Password</span>
26
+ </div>
27
+ <%= form.password_field :password, id: "smsRemovalPassword", class:"form-control" %>
28
+ <div class="invalid-feedback">
29
+ Password required to remove SMS option for MFA
30
+ </div>
31
+ </div>
32
+ </div>
33
+ <br>
34
+ <div class="smsInput">
35
+ <div class="input-group input-group-lg">
36
+ <div class="input-group-prepend">
37
+ <span class="input-group-text" id="smsInput-Prepend">SMS Code</span>
38
+ </div>
39
+ <%= form.telephone_field :sms_code, id: "smsRemovalCode", class:"form-control", placeholder: "Code delivered via SMS" %>
40
+ <div class="invalid-feedback">
41
+ SMS Code is required. At least <%= code_length %> numerics expected
42
+ </div>
43
+ </div>
44
+ </div>
45
+ <br>
46
+ <div class="smsSubmit">
47
+ <div class="row">
48
+ <div class="col-md-9">
49
+ <%= form.submit "Confirm SMS MFA Removal", id: "confirmSmsRemovalButton", class: " btn btn_danger btn-block" %>
50
+ </div>
51
+ <div class="col-md-3">
52
+ <button type="button" id="sendSmsButton" class="btn btn_warning btn-block" onclick="sendSMS()">
53
+ Send SMS
54
+ </button>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ <% end %>
60
+
14
61
  </div>
15
62
  <div class="modal-footer">
16
63
  <button type="button" class="mr-auto btn btn_secondary" data-dismiss="modal">Close</button>
@@ -18,3 +65,55 @@
18
65
  </div>
19
66
  </div>
20
67
  </div>
68
+
69
+
70
+
71
+ <%= render partial: 'rails_base/shared/custom_form_validation_javascript', locals: { function_name: "mfaSmsRemoval", values: values } %>
72
+
73
+ <script type="text/javascript">
74
+ $(`#confirmSmsRemovalButton`).prop("disabled", true)
75
+ $(`.mfaSmsModalBody input`).on("keypress", function() {
76
+ setConfirmButtonStatus()
77
+ });
78
+
79
+ $(`.mfaSmsModalBody input`).change(function() {
80
+ setConfirmButtonStatus()
81
+ });
82
+
83
+ function setConfirmButtonStatus(){
84
+ if(mfaSmsRemoval_validation_event()){
85
+ $(`#confirmSmsRemovalButton`).prop("disabled", false)
86
+ } else {
87
+ $(`#confirmSmsRemovalButton`).prop("disabled", true)
88
+ }
89
+ }
90
+
91
+ function setDelay(){
92
+ $(`#sendSmsButton`).prop("disabled", true)
93
+ timeoutClock = setTimeout(enableSendSMS, 5_000);
94
+ }
95
+
96
+ function enableSendSMS(){
97
+ $(`#sendSmsButton`).prop("disabled", false)
98
+ }
99
+
100
+ function sendSMS(){
101
+ $(`#sendSmsButton`).text("Resend SMS")
102
+ setDelay();
103
+ $.ajax({
104
+ type: "POST",
105
+ url: "<%= RailsBase.url_routes.sms_validate_send_event_path(mfa_event: RailsBase::MfaEvent::DISABLE_SMS_EVENT) %>",
106
+ headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') },
107
+ dataType: 'json',
108
+ success: function(data) {
109
+ html_notice = `<p class="alert alert-success">${data.message}</p>`
110
+ $(`.mfaSmsStatusDiv`).html(html_notice)
111
+ },
112
+ error: function(xhr, status, error) {
113
+ html_notice = `<p class="alert alert-danger">${xhr.responseJSON.message}</p>`
114
+ $(`.mfaSmsStatusDiv`).html(html_notice)
115
+ console.log(xhr.responseJSON)
116
+ }
117
+ })
118
+ }
119
+ </script>
@@ -0,0 +1,13 @@
1
+
2
+ <div class="row" >
3
+ <div class="col-md-8 offset-md-2">
4
+ <%= render partial: 'rails_base/shared/mfa_input_layout', locals: { url: RailsBase.url_routes.sms_validate_event_path(mfa_event: mfa_event.event), size: 30, masked_phone: @masked_phone }%>
5
+ <br>
6
+ <div class="text-center">
7
+ <%= button_to 'Resend MFA', RailsBase.url_routes.sms_validate_send_event_path(mfa_event: mfa_event.event), method: :post, class: 'btn btn_warning', style: 'width: 25%;' %>
8
+ </div>
9
+ </div>
10
+ </div>
11
+
12
+
13
+ <%= render partial: 'rails_base/mfa/switch_mfa_type', locals: { mfa_options: @mfa_options } %>
@@ -0,0 +1,22 @@
1
+ <div class="row text-center">
2
+ <div class="col-md-10 offset-md-1">
3
+ <div class="h1"> One Time Password</div>
4
+ <div class="row">
5
+ <div class="col">
6
+ MFA is required on your account before you can proceed. Please use the gnerated code from provided by your Password Manager.
7
+ </div>
8
+ </div>
9
+
10
+ <hr>
11
+
12
+ <div class="row">
13
+ <div class="col">
14
+ <div class="totpComfirmation">
15
+ <%= render partial: 'rails_base/shared/totp/confirm_code', locals: { endpoint: endpoint, type: :rest } %>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+
22
+ <%= render partial: 'rails_base/mfa/switch_mfa_type', locals: { mfa_options: mfa_options } %>
@@ -0,0 +1,76 @@
1
+ <div id="totpAddAuthentication">
2
+ <div class="description">
3
+ <h4>What is this?</h4>
4
+ One time Passwords (OTP) are an industry standard for a secondary Authentication (MFA). <%= RailsBase.app_name %> supports One Time Passwords via Time based One Time Password (also referred to as TOTP).
5
+ <div class="row"><div class="col-6 offset-3">
6
+ <hr>
7
+ </div></div>
8
+ When TOTP is enabled on your account, upon logging in, you will be required to also provided the secondary Authentication facor before accessing your data. This is optional but highly recommended.
9
+ <div class="row"><div class="col-6 offset-3">
10
+ <hr>
11
+ </div></div>
12
+ <h4>How to use is this?</h4>
13
+ Using your password manager, you can scan the QR code here to store along with your Username and Password for <%= RailsBase.app_name %>. When logging in, your Password Manager should automatically give you your OTP.
14
+ </div>
15
+ <br>
16
+ <div class="row">
17
+ <div class="col-lg-6">
18
+ <div class="qrCode text-center"></div>
19
+ </div>
20
+ <div class="col-lg-6">
21
+ <div class="row otpauthLink" style="height: 50%; margin-top: 12.5%;">
22
+ <div class="col-12">
23
+ <a class="btn btn-info btn-block" id="defaultManagerURI" href="" target="_blank">Open Default Password Manager</a>
24
+ </div>
25
+ </div>
26
+ <div class="row otpauthLink">
27
+ <div class="col-12">
28
+ <button onclick="copyURIToClipboard()" class="btn btn-info btn-block" id="copyPasteURI">Copy To ClipBoard</button>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+
34
+ <br>
35
+ <div class="row"><div class="col-6 offset-3">
36
+ <hr>
37
+ </div></div>
38
+ <div class="totpValidation">
39
+ <div class="totpdescription">
40
+ <h4>Confirm TOTP code</h4>
41
+ Once you have added the TOTP Athentication to your password manager, please validate the below by entering the code. Once the code is validated, TOTP is enabled on your account.
42
+ </div>
43
+ <div class="totpComfirmation">
44
+ <%= render partial: 'rails_base/shared/totp/confirm_code', locals: { endpoint: endpoint, type: type } %>
45
+ </div>
46
+ </div>
47
+ </div>
48
+
49
+
50
+ <script type="text/javascript">
51
+ var text_to_write;
52
+ function copyURIToClipboard(){
53
+ navigator.clipboard.writeText(text_to_write)
54
+ }
55
+
56
+ function retrieveSuccess(data){
57
+ $(`#totpAddAuthentication .qrCode`).html(data.qr_code)
58
+ $(`#totpAddAuthentication #defaultManagerURI`).attr(`href`, data.uri)
59
+ text_to_write = data.uri
60
+ }
61
+
62
+ function retreiveSecret(){
63
+ $.ajax({
64
+ type: "POST",
65
+ url: "<%= RailsBase.url_routes.totp_register_secret_path %>",
66
+ headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') },
67
+ dataType: 'json',
68
+ success: function(data) {
69
+ retrieveSuccess(data)
70
+ },
71
+ error: function(xhr, status, error) {
72
+ _rails_base_display_alert(`Failed to get event`);
73
+ }
74
+ })
75
+ }
76
+ </script>
@@ -0,0 +1,25 @@
1
+ <div class="modal fade" id="totpEnableModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
2
+ <div class="modal-dialog modal-lg" role="document">
3
+ <div class="modal-content">
4
+ <div class="modal-header">
5
+ <h3 class="modal-title" id="exampleModalLabel">Add Authenticator Device</h3>
6
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
7
+ <span aria-hidden="true">&times;</span>
8
+ </button>
9
+ </div>
10
+ <div class="modal-body">
11
+ <%= render partial: 'rails_base/shared/totp/add_authenticator', locals: { endpoint: endpoint, type: type } %>
12
+ </div>
13
+ <div class="modal-footer">
14
+ <button type="button" class="mr-auto btn btn_secondary" data-dismiss="modal">Close</button>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ </div>
19
+
20
+ <script type="text/javascript">
21
+ $('#totpEnableModal').on('shown.bs.modal', function (e) {
22
+ retreiveSecret()
23
+ })
24
+
25
+ </script>
@@ -0,0 +1,31 @@
1
+ <%
2
+ case type
3
+ when :ajax
4
+ partial = "rails_base/shared/totp/confirm_code_ajax"
5
+ endpoint = endpoint
6
+ when :rest
7
+ partial = "rails_base/shared/totp/confirm_code_rest"
8
+ endpoint = endpoint
9
+ else
10
+ raise "type must be of [:ajax, :rest]"
11
+ end
12
+ %>
13
+ <%= form_with(url: endpoint, method: :post) do |f| %>
14
+ <div id="confirmTotpAuthenticationCode">
15
+ <br>
16
+ <div class="totpInput">
17
+ <div class="input-group input-group-lg">
18
+ <div class="input-group-prepend">
19
+ <span class="input-group-text" id="totpInput-Prepend">OTP</span>
20
+ </div>
21
+ <%= f.telephone_field :totp_code, id: "totpInput-Input", class:"form-control", placeholder: "One Time Password Value" %>
22
+ </div>
23
+ </div>
24
+ <br>
25
+ <div class="totpSubmit">
26
+ <%= render partial: partial, locals: { endpoint: endpoint, form: f } %>
27
+ </div>
28
+ </div>
29
+ <% end %>
30
+
31
+
@@ -0,0 +1,3 @@
1
+ <script type="text/javascript">
2
+
3
+ </script>
@@ -0,0 +1,5 @@
1
+ <div class="row">
2
+ <div class="col-md-6 offset-md-3">
3
+ <%= form.submit "Confirm OTP Code", class: " btn btn_success btn-block" %>
4
+ </div>
5
+ </div>
@@ -0,0 +1,50 @@
1
+ <div class="modal fade" id="totpDisableModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
2
+ <div class="modal-dialog modal-lg" role="document">
3
+ <div class="modal-content">
4
+ <div class="modal-header">
5
+ <h3 class="modal-title" id="exampleModalLabel">Remove TOTP as Multi Factor Authenticator</h3>
6
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">
7
+ <span aria-hidden="true">&times;</span>
8
+ </button>
9
+ </div>
10
+ <div class="modal-body">
11
+ <div class="text-center">
12
+ Time based One time Password is one of the the most Secure MFA option that <%= RailsBase.app_name %> provides. If you would like to remove this MFA option, please enter your credentials below and confirm. Upon Successful request, TOTP is no longer active on your account
13
+ </div>
14
+ <hr>
15
+ <%= form_with(url: RailsBase.url_routes.totp_register_delete_path, method: :delete) do |form| %>
16
+ <div id="confirmTotpAuthenticationCode">
17
+ <div class="totpInput">
18
+ <div class="input-group input-group-lg">
19
+ <div class="input-group-prepend">
20
+ <span class="input-group-text" id="totpInput-Prepend">Password</span>
21
+ </div>
22
+ <%= form.password_field :password, id: "totpRemoval-password", class:"form-control" %>
23
+ </div>
24
+ </div>
25
+ <br>
26
+ <div class="totpInput">
27
+ <div class="input-group input-group-lg">
28
+ <div class="input-group-prepend">
29
+ <span class="input-group-text" id="totpInput-Prepend">TOTP</span>
30
+ </div>
31
+ <%= form.telephone_field :totp_code, id: "totpRemoval-code", class:"form-control", placeholder: "One Time Password Value" %>
32
+ </div>
33
+ </div>
34
+ <br>
35
+ <div class="totpSubmit">
36
+ <div class="row">
37
+ <div class="col-md-6 offset-md-3">
38
+ <%= form.submit "Confirm TOTP Removal", class: " btn btn_danger btn-block" %>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ <% end %>
44
+ </div>
45
+ <div class="modal-footer">
46
+ <button type="button" class="mr-auto btn btn_secondary" data-dismiss="modal">Close</button>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ </div>