rails_base 0.75.6 → 0.80.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 (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,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsBase
4
+ class MfaEvent
5
+ ENABLE_SMS_EVENT = :sms_enable
6
+ DISABLE_SMS_EVENT = :sms_disable
7
+ FORGOT_PASSWORD = :forgot_password
8
+ ADMIN_VERIFY = :admin_verify
9
+
10
+ class InvalidParameter < ArgumentError; end
11
+
12
+ attr_reader :only_mfa, :phone_number, :set_satiated_on_success, :satiated, :access_count, :flash_notice, :sign_in_user,
13
+ :invalid_redirect, :ttl, :user_id, :event, :description, :death_time, :redirect, :params, :access_count_max
14
+
15
+ def self.admin_actions(user:)
16
+ params = {
17
+ user: user,
18
+ event: ADMIN_VERIFY,
19
+ ttl: 30.seconds,
20
+ redirect: "",
21
+ invalid_redirect: "",
22
+ flash_notice: "",
23
+ }
24
+
25
+ new(**params)
26
+ end
27
+
28
+ def self.login_event(user:)
29
+ params = {
30
+ user: user,
31
+ event: :login,
32
+ ttl: 1.minutes,
33
+ redirect: RailsBase.url_routes.authenticated_root_path,
34
+ invalid_redirect: RailsBase.url_routes.unauthenticated_root_path,
35
+ sign_in_user: true,
36
+ flash_notice: "Welcome #{user.full_name}. You have succesfully signed in"
37
+ }
38
+
39
+ new(**params)
40
+ end
41
+
42
+ # This is a JSON event not html; Can leave redirects/notice empty
43
+ def self.sms_enable(user:)
44
+ params = {
45
+ user: user,
46
+ event: ENABLE_SMS_EVENT,
47
+ ttl: 5.minutes,
48
+ invalid_redirect: RailsBase.url_routes.user_settings_path,
49
+ redirect: RailsBase.url_routes.user_settings_path,
50
+ flash_notice: ""
51
+ }
52
+
53
+ new(**params)
54
+ end
55
+
56
+ def self.sms_disable(user:)
57
+ params = {
58
+ user: user,
59
+ event: DISABLE_SMS_EVENT,
60
+ ttl: 5.minutes,
61
+ invalid_redirect: RailsBase.url_routes.user_settings_path,
62
+ redirect: RailsBase.url_routes.user_settings_path,
63
+ flash_notice: "SMS option for MFA is disabled"
64
+ }
65
+
66
+ new(**params)
67
+ end
68
+
69
+ def self.forgot_password(user:, data:)
70
+ params = {
71
+ user: user,
72
+ event: FORGOT_PASSWORD,
73
+ ttl: 2.minutes,
74
+ invalid_redirect: RailsBase.url_routes.unauthenticated_root_path,
75
+ redirect: RailsBase.url_routes.reset_password_input_path(data:),
76
+ flash_notice: "MFA success. You may now reset your forgotten password",
77
+ access_count_max: 1,
78
+ }
79
+
80
+ new(**params)
81
+ end
82
+
83
+ def initialize(event:, flash_notice:, redirect:, only_mfa: nil, phone_number: nil, ttl: nil, death_time: nil, user_id: nil, user: nil, invalid_redirect: nil, sign_in_user: false, access_count: 0, access_count_max: nil, satiated: false, set_satiated_on_success: true)
84
+ @death_time = begin
85
+ raw = (death_time || ttl&.from_now)
86
+ Time.zone.parse(raw.to_s) rescue nil
87
+ end
88
+
89
+ @access_count = access_count
90
+ @access_count_max = access_count_max
91
+ @event = event
92
+ @flash_notice = flash_notice
93
+ @invalid_redirect = invalid_redirect || RailsBase.url_routes.authenticated_root_path
94
+ @only_mfa = only_mfa
95
+ @phone_number = phone_number
96
+ @redirect = redirect
97
+ @satiated = satiated
98
+ @set_satiated_on_success = set_satiated_on_success
99
+ @sign_in_user = sign_in_user
100
+ @user_id = user_id || user.id rescue nil
101
+
102
+ validate_data!
103
+ end
104
+
105
+ def to_hash
106
+ {
107
+ access_count:,
108
+ access_count_max:,
109
+ death_time:,
110
+ event:,
111
+ flash_notice:,
112
+ invalid_redirect:,
113
+ only_mfa:,
114
+ phone_number:,
115
+ redirect:,
116
+ satiated:,
117
+ set_satiated_on_success:,
118
+ sign_in_user:,
119
+ user_id:,
120
+ }
121
+ end
122
+
123
+ def access_count
124
+ @access_count
125
+ end
126
+
127
+ def satiated!
128
+ @satiated = true
129
+ end
130
+
131
+ def satiated?
132
+ @satiated
133
+ end
134
+
135
+ def increase_access_count!
136
+ @access_count += 1
137
+ end
138
+
139
+ def valid?
140
+ valid_by_death_time? && valid_by_access_count?
141
+ end
142
+
143
+ def valid_by_death_time?
144
+ death_time >= Time.now
145
+ end
146
+
147
+ def valid_by_access_count?
148
+ return true if @access_count_max.nil?
149
+
150
+ @access_count_max
151
+ end
152
+
153
+ def invalid_reasons
154
+ arr = []
155
+ arr << "Max Access count reached" unless valid_by_death_time?
156
+ arr << "#{event} has expired" unless valid_by_access_count?
157
+
158
+ arr
159
+ end
160
+
161
+ private
162
+
163
+ def validate_data!
164
+ raise_event!(value: @event, name: :event, klass: [String, Symbol])
165
+ raise_event!(value: @death_time, name: :death_time, klass: [ActiveSupport::TimeWithZone])
166
+ raise_event!(value: @redirect, name: :redirect, klass: [String])
167
+ raise_event!(value: @user_id, name: :user, klass: [Integer])
168
+ raise_event!(value: @flash_notice, name: :flash_notice, klass: [String])
169
+ raise_event!(value: @access_count, name: :access_count, klass: [Integer])
170
+ raise_event!(value: @access_count_max, name: :access_count_max, klass: [Integer, NilClass])
171
+ end
172
+
173
+ def raise_event!(value:, name:, klass:, &blk)
174
+ boolean = klass.include?(value.class)
175
+ raise_message = nil
176
+ if boolean && block_given?
177
+ raise_message = yield(value)
178
+ end
179
+ boolean = false if raise_message
180
+ return if boolean
181
+
182
+ message = raise_message || "@#{name}=#{value}. Value is expected to be in #{klass}"
183
+ raise InvalidParameter, message
184
+ end
185
+ end
186
+ end
@@ -1,7 +1,7 @@
1
1
  module RailsBase
2
- MAJOR = '0'
3
- MINOR = '75'
4
- PATCH = '6'
2
+ MAJOR = "0"
3
+ MINOR = "80"
4
+ PATCH = "0"
5
5
  VERSION = "#{MAJOR}.#{MINOR}.#{PATCH}"
6
6
 
7
7
  def self.print_version
data/lib/rails_base.rb CHANGED
@@ -15,6 +15,7 @@ require 'switch_user'
15
15
 
16
16
  require 'rails_base/admin/action_cache'
17
17
  require 'rails_base/config'
18
+ require 'rails_base/mfa_event'
18
19
 
19
20
  module RailsBase
20
21
 
data/lib/twilio_helper.rb CHANGED
@@ -2,9 +2,9 @@ require 'twilio-ruby'
2
2
 
3
3
  class TwilioHelper
4
4
  class << self
5
- TWILIO_ACCOUNT_SID = RailsBase.config.mfa.twilio_sid
6
- TWILIO_AUTH_TOKEN = RailsBase.config.mfa.twilio_auth_token
7
- TWILIO_FROM_NUMBER = RailsBase.config.mfa.twilio_from_number
5
+ TWILIO_ACCOUNT_SID = RailsBase.config.twilio.twilio_sid
6
+ TWILIO_AUTH_TOKEN = RailsBase.config.twilio.twilio_auth_token
7
+ TWILIO_FROM_NUMBER = RailsBase.config.twilio.twilio_from_number
8
8
 
9
9
  def send_sms(message:, to:)
10
10
  Rails.logger.info "Sending Twilio message:[#{message}] to [#{to}]"