rodauth-rails 1.14.1 → 1.15.1

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +48 -46
  3. data/lib/generators/rodauth/install_generator.rb +7 -23
  4. data/lib/generators/rodauth/mailer/email_auth.erb +6 -0
  5. data/lib/generators/rodauth/mailer/otp_disabled.erb +6 -0
  6. data/lib/generators/rodauth/mailer/otp_locked_out.erb +6 -0
  7. data/lib/generators/rodauth/mailer/otp_setup.erb +6 -0
  8. data/lib/generators/rodauth/mailer/otp_unlock_failed.erb +6 -0
  9. data/lib/generators/rodauth/mailer/otp_unlocked.erb +6 -0
  10. data/lib/generators/rodauth/mailer/password_changed.erb +6 -0
  11. data/lib/generators/rodauth/mailer/reset_password.erb +6 -0
  12. data/lib/generators/rodauth/mailer/reset_password_notify.erb +6 -0
  13. data/lib/generators/rodauth/mailer/unlock_account.erb +6 -0
  14. data/lib/generators/rodauth/mailer/verify_account.erb +6 -0
  15. data/lib/generators/rodauth/mailer/verify_login_change.erb +7 -0
  16. data/lib/generators/rodauth/mailer/webauthn_authenticator_added.erb +6 -0
  17. data/lib/generators/rodauth/mailer/webauthn_authenticator_removed.erb +6 -0
  18. data/lib/generators/rodauth/mailer_generator.rb +126 -0
  19. data/lib/generators/rodauth/migration/active_record/audit_logging.erb +2 -2
  20. data/lib/generators/rodauth/migration/active_record/jwt_refresh.erb +0 -1
  21. data/lib/generators/rodauth/migration/active_record/otp_unlock.erb +7 -0
  22. data/lib/generators/rodauth/migration/sequel/audit_logging.erb +2 -2
  23. data/lib/generators/rodauth/migration/sequel/jwt_refresh.erb +1 -1
  24. data/lib/generators/rodauth/migration/sequel/otp_unlock.erb +6 -0
  25. data/lib/generators/rodauth/migration_generator.rb +4 -3
  26. data/lib/generators/rodauth/templates/INSTRUCTIONS +17 -38
  27. data/lib/generators/rodauth/templates/app/mailers/rodauth_mailer.rb.tt +4 -50
  28. data/lib/generators/rodauth/templates/app/misc/rodauth_main.rb.tt +5 -29
  29. data/lib/generators/rodauth/templates/app/models/account.rb.tt +2 -2
  30. data/lib/generators/rodauth/templates/app/views/rodauth/otp_unlock.html.erb +21 -0
  31. data/lib/generators/rodauth/templates/app/views/rodauth/otp_unlock_not_available.html.erb +5 -0
  32. data/lib/generators/rodauth/templates/app/views/rodauth/tailwind/otp_unlock.html.erb +22 -0
  33. data/lib/generators/rodauth/templates/app/views/rodauth/tailwind/otp_unlock_not_available.html.erb +14 -0
  34. data/lib/generators/rodauth/templates/app/views/rodauth/tailwind/webauthn_remove.html.erb +1 -0
  35. data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +1 -0
  36. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_disabled.text.erb +2 -0
  37. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_locked_out.text.erb +9 -0
  38. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_setup.text.erb +2 -0
  39. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_unlock_failed.text.erb +8 -0
  40. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_unlocked.text.erb +2 -0
  41. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/webauthn_authenticator_added.text.erb +3 -0
  42. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/webauthn_authenticator_removed.text.erb +3 -0
  43. data/lib/generators/rodauth/views_generator.rb +2 -1
  44. data/lib/rodauth/rails/feature/base.rb +2 -1
  45. data/lib/rodauth/rails/feature/instrumentation.rb +23 -7
  46. data/lib/rodauth/rails/feature/internal_request.rb +16 -6
  47. data/lib/rodauth/rails/version.rb +1 -1
  48. data/rodauth-rails.gemspec +4 -4
  49. metadata +35 -8
  50. data/CHANGELOG.md +0 -570
@@ -1,61 +1,15 @@
1
1
  class RodauthMailer < ApplicationMailer
2
2
  default to: -> { @rodauth.email_to }, from: -> { @rodauth.email_from }
3
3
 
4
- def verify_account(name, account_id, key)
5
- @rodauth = rodauth(name, account_id) { @verify_account_key_value = key }
6
- @account = @rodauth.rails_account
7
-
8
- mail subject: @rodauth.email_subject_prefix + @rodauth.verify_account_email_subject
9
- end
10
-
11
- def reset_password(name, account_id, key)
12
- @rodauth = rodauth(name, account_id) { @reset_password_key_value = key }
13
- @account = @rodauth.rails_account
14
-
15
- mail subject: @rodauth.email_subject_prefix + @rodauth.reset_password_email_subject
16
- end
17
-
18
- def verify_login_change(name, account_id, key)
19
- @rodauth = rodauth(name, account_id) { @verify_login_change_key_value = key }
20
- @account = @rodauth.rails_account
21
- @new_email = @account.login_change_key.login
22
-
23
- mail to: @new_email, subject: @rodauth.email_subject_prefix + @rodauth.verify_login_change_email_subject
24
- end
25
-
26
- def password_changed(name, account_id)
27
- @rodauth = rodauth(name, account_id)
28
- @account = @rodauth.rails_account
29
-
30
- mail subject: @rodauth.email_subject_prefix + @rodauth.password_changed_email_subject
31
- end
32
-
33
- # def reset_password_notify(name, account_id)
34
- # @rodauth = rodauth(name, account_id)
35
- # @account = @rodauth.rails_account
36
-
37
- # mail subject: @rodauth.email_subject_prefix + @rodauth.reset_password_notify_email_subject
38
- # end
39
-
40
- # def email_auth(name, account_id, key)
41
- # @rodauth = rodauth(name, account_id) { @email_auth_key_value = key }
42
- # @account = @rodauth.rails_account
43
-
44
- # mail subject: @rodauth.email_subject_prefix + @rodauth.email_auth_email_subject
45
- # end
46
-
47
- # def unlock_account(name, account_id, key)
48
- # @rodauth = rodauth(name, account_id) { @unlock_account_key_value = key }
49
- # @account = @rodauth.rails_account
50
-
51
- # mail subject: @rodauth.email_subject_prefix + @rodauth.unlock_account_email_subject
52
- # end
4
+ <%= mailer_content -%>
53
5
 
54
6
  private
55
7
 
8
+ # Default URL options are inherited from Action Mailer, but you can override them
9
+ # ad-hoc by modifying the `rodauth.rails_url_options` hash.
56
10
  def rodauth(name, account_id, &block)
57
11
  instance = RodauthApp.rodauth(name).allocate
58
- instance.instance_eval { @account = account_ds(account_id).first! }
12
+ instance.account_from_id(account_id)
59
13
  instance.instance_eval(&block) if block
60
14
  instance
61
15
  end
@@ -5,23 +5,24 @@ class RodauthMain < Rodauth::Rails::Auth
5
5
  # List of authentication features that are loaded.
6
6
  enable :create_account, :verify_account, :verify_account_grace_period,
7
7
  :login, :logout<%= ", :remember" unless jwt? %><%= ", :json" if json? %><%= ", :jwt" if jwt? %>,
8
- :reset_password, :change_password, :change_password_notify,
9
- :change_login, :verify_login_change, :close_account<%= ", :argon2" if argon2? %>
8
+ :reset_password, :change_password, :change_login, :verify_login_change,
9
+ :close_account<%= ", :argon2" if argon2? %>
10
10
 
11
11
  # See the Rodauth documentation for the list of available config options:
12
12
  # http://rodauth.jeremyevans.net/documentation.html
13
13
 
14
14
  # ==> General
15
- <% if sequel_activerecord_integration? -%>
15
+ <% if activerecord? && !sequel? -%>
16
16
  # Initialize Sequel and have it reuse Active Record's database connection.
17
17
  <% if RUBY_ENGINE == "jruby" -%>
18
18
  db Sequel.connect("jdbc:<%= sequel_adapter %>://", extensions: :activerecord_connection, keep_reference: false)
19
19
  <% else -%>
20
20
  db Sequel.<%= sequel_adapter %>(extensions: :activerecord_connection, keep_reference: false)
21
21
  <% end -%>
22
-
22
+ <% if activerecord? -%>
23
23
  # Avoid DB query that checks accounts table schema at boot time.
24
24
  convert_token_id_to_integer? { <%= table_prefix.camelize %>.columns_hash["id"].type == :integer }
25
+ <% end -%>
25
26
 
26
27
  <% end -%>
27
28
  # Change prefix of table and foreign key column names from default "account"
@@ -107,28 +108,6 @@ class RodauthMain < Rodauth::Rails::Auth
107
108
 
108
109
  <% if defined?(ActionMailer) -%>
109
110
  # ==> Emails
110
- # Use a custom mailer for delivering authentication emails.
111
- create_reset_password_email do
112
- RodauthMailer.reset_password(self.class.configuration_name, account_id, reset_password_key_value)
113
- end
114
- create_verify_account_email do
115
- RodauthMailer.verify_account(self.class.configuration_name, account_id, verify_account_key_value)
116
- end
117
- create_verify_login_change_email do |_login|
118
- RodauthMailer.verify_login_change(self.class.configuration_name, account_id, verify_login_change_key_value)
119
- end
120
- create_password_changed_email do
121
- RodauthMailer.password_changed(self.class.configuration_name, account_id)
122
- end
123
- # create_reset_password_notify_email do
124
- # RodauthMailer.reset_password_notify(self.class.configuration_name, account_id)
125
- # end
126
- # create_email_auth_email do
127
- # RodauthMailer.email_auth(self.class.configuration_name, account_id, email_auth_key_value)
128
- # end
129
- # create_unlock_account_email do
130
- # RodauthMailer.unlock_account(self.class.configuration_name, account_id, unlock_account_key_value)
131
- # end
132
111
  send_email do |email|
133
112
  # queue email delivery on the mailer after the transaction commits
134
113
  db.after_commit { email.deliver_later }
@@ -214,9 +193,6 @@ class RodauthMain < Rodauth::Rails::Auth
214
193
 
215
194
  # Redirect to login page after password reset.
216
195
  reset_password_redirect { login_path }
217
-
218
- # Ensure requiring login follows login route changes.
219
- require_login_redirect { login_path }
220
196
  <% end -%>
221
197
 
222
198
  # ==> Deadlines
@@ -1,8 +1,8 @@
1
- <% if defined?(ActiveRecord::Railtie) -%>
1
+ <% if activerecord? -%>
2
2
  class <%= table_prefix.camelize %> < ApplicationRecord
3
3
  include Rodauth::Rails.model
4
4
  <% if ActiveRecord.version >= Gem::Version.new("7.0") -%>
5
- enum :status, unverified: 1, verified: 2, closed: 3
5
+ enum :status, { unverified: 1, verified: 2, closed: 3 }
6
6
  <% else -%>
7
7
  enum status: { unverified: 1, verified: 2, closed: 3 }
8
8
  <% end -%>
@@ -0,0 +1,21 @@
1
+ <%= form_with url: rodauth.otp_unlock_path, method: :post, data: { turbo: false } do |form| %>
2
+ <p><%= rodauth.otp_unlock_consecutive_successes_label %>: <%= rodauth.otp_unlock_num_successes %></p>
3
+ <p><%= rodauth.otp_unlock_required_consecutive_successes_label %>: <%= rodauth.otp_unlock_auths_required %></p>
4
+ <p><%= rodauth.otp_unlock_next_auth_deadline_label %>: <%= rodauth.otp_unlock_deadline.strftime(rodauth.strftime_format) %></p>
5
+
6
+ <div class="form-group mb-3">
7
+ <%= form.label "otp-auth-code", rodauth.otp_auth_label, class: "form-label" %>
8
+ <div class="row">
9
+ <div class="col-sm-3">
10
+ <%= form.text_field rodauth.otp_auth_param, value: "", id: "otp-auth-code", autocomplete: "off", inputmode: "numeric", required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.otp_auth_param)}", aria: ({ invalid: true, describedby: "otp-auth-code_error_message" } if rodauth.field_error(rodauth.otp_auth_param)) %>
11
+ <%= content_tag(:span, rodauth.field_error(rodauth.otp_auth_param), class: "invalid-feedback", id: "otp-auth-code_error_message") if rodauth.field_error(rodauth.otp_auth_param) %>
12
+ </div>
13
+ </div>
14
+ </div>
15
+
16
+ <div class="form-group mb-3">
17
+ <%= form.submit rodauth.otp_unlock_button, class: "btn btn-primary" %>
18
+ </div>
19
+ <% end %>
20
+
21
+ <%== rodauth.otp_unlock_form_footer %>
@@ -0,0 +1,5 @@
1
+ <p><%= rodauth.otp_unlock_consecutive_successes_label %>: <%= rodauth.otp_unlock_num_successes %></p>
2
+ <p><%= rodauth.otp_unlock_required_consecutive_successes_label %>: <%= rodauth.otp_unlock_auths_required %></p>
3
+ <p><%= rodauth.otp_unlock_next_auth_attempt_label %>: <%= rodauth.otp_unlock_next_auth_attempt_after.strftime(rodauth.strftime_format) %></p>
4
+ <p><%= rodauth.otp_unlock_next_auth_attempt_refresh_label %></p>
5
+ <%== rodauth.otp_unlock_refresh_tag %>
@@ -0,0 +1,22 @@
1
+ <%= form_with url: rodauth.otp_unlock_path, method: :post, data: { turbo: false }, class: "w-full max-w-sm" do |form| %>
2
+ <dl class="mb-6 text-sm space-y-2">
3
+ <dt class="font-semibold"><%= rodauth.otp_unlock_consecutive_successes_label %>:</dt>
4
+ <dd><%= rodauth.otp_unlock_num_successes %></dd>
5
+
6
+ <dt class="font-semibold"><%= rodauth.otp_unlock_required_consecutive_successes_label %>:</dt>
7
+ <dd><%= rodauth.otp_unlock_auths_required %></dd>
8
+
9
+ <dt class="font-semibold"><%= rodauth.otp_unlock_next_auth_deadline_label %>:</dt>
10
+ <dd><%= rodauth.otp_unlock_deadline.strftime(rodauth.strftime_format) %></dd>
11
+ </dl>
12
+
13
+ <div class="mb-6">
14
+ <%= form.label "otp-auth-code", rodauth.otp_auth_label, class: "block text-sm font-semibold" %>
15
+ <%= form.text_field rodauth.otp_auth_param, value: "", id: "otp-auth-code", autocomplete: "off", inputmode: "numeric", required: true, class: "mt-2 text-sm w-1/2 px-3 py-2 border rounded-md dark:bg-gray-900 dark:text-gray-100 dark:focus:bg-gray-800 #{rodauth.field_error(rodauth.otp_auth_param) ? "border-red-600 focus:ring-red-600 focus:border-red-600 dark:border-red-400 dark:focus:ring-red-400" : "border-gray-300 dark:border-gray-700 dark:focus:border-emerald-400 dark:focus:ring-emerald-400" }", aria: ({ invalid: true, describedby: "otp-auth-code_error_message" } if rodauth.field_error(rodauth.otp_auth_param)) %>
16
+ <%= content_tag(:span, rodauth.field_error(rodauth.otp_auth_param), class: "block mt-1 text-red-600 text-xs dark:text-red-400", id: "otp-auth-code_error_message") if rodauth.field_error(rodauth.otp_auth_param) %>
17
+ </div>
18
+
19
+ <%= form.submit rodauth.otp_unlock_button, class: "w-full px-8 py-3 cursor-pointer font-semibold text-sm rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-600 dark:bg-emerald-400 dark:hover:bg-emerald-500 dark:text-gray-900 dark:focus:ring-emerald-400 dark:focus:ring-offset-current" %>
20
+ <% end %>
21
+
22
+ <%== rodauth.otp_unlock_form_footer %>
@@ -0,0 +1,14 @@
1
+ <dl class="mb-6 text-sm space-y-2">
2
+ <dt class="font-semibold"><%= rodauth.otp_unlock_consecutive_successes_label %>:</dt>
3
+ <dd><%= rodauth.otp_unlock_num_successes %></dd>
4
+
5
+ <dt class="font-semibold"><%= rodauth.otp_unlock_required_consecutive_successes_label %>:</dt>
6
+ <dd><%= rodauth.otp_unlock_auths_required %></dd>
7
+
8
+ <dt class="font-semibold"><%= rodauth.otp_unlock_next_auth_attempt_label %>:</dt>
9
+ <dd><%= rodauth.otp_unlock_deadline.strftime(rodauth.strftime_format) %></dd>
10
+ </dl>
11
+
12
+ <p class="mt-2"><%= rodauth.otp_unlock_next_auth_attempt_refresh_label %></p>
13
+
14
+ <%== rodauth.otp_unlock_refresh_tag %>
@@ -10,6 +10,7 @@
10
10
  <fieldset class="mb-6">
11
11
  <% rodauth.account_webauthn_usage.each do |id, last_use| %>
12
12
  <div class="flex items-center space-x-2">
13
+ <% last_use = last_use.strftime(rodauth.strftime_format) if last_use.is_a?(Time) %>
13
14
  <%= form.radio_button rodauth.webauthn_remove_param, id, id: "webauthn-remove-#{id}", class: "dark:bg-gray-900 dark:border-gray-600 dark:checked:bg-current dark:checked:border-current dark:checked:text-emerald-400 dark:focus:ring-emerald-400 dark:focus:ring-offset-gray-900" %>
14
15
  <%= form.label "webauthn-remove-#{id}", "Last use: #{last_use}", class: "text-sm" %>
15
16
  </div>
@@ -10,6 +10,7 @@
10
10
  <fieldset class="form-group mb-3">
11
11
  <% (usage = rodauth.account_webauthn_usage).each do |id, last_use| %>
12
12
  <div class="form-check">
13
+ <% last_use = last_use.strftime(rodauth.strftime_format) if last_use.is_a?(Time) %>
13
14
  <%= form.radio_button rodauth.webauthn_remove_param, id, id: "webauthn-remove-#{id}", class: "form-check-input #{"is-invalid" if rodauth.field_error(rodauth.webauthn_remove_param)}", aria: ({ invalid: true, describedby: "webauthn_remove_error_message" } if rodauth.field_error(rodauth.webauthn_remove_param)) %>
14
15
  <%= form.label "webauthn-remove-#{id}", "Last use: #{last_use}", class: "form-check-label" %>
15
16
  <%= content_tag(:span, rodauth.field_error(rodauth.webauthn_remove_param), class: "invalid-feedback", id: "webauthn_remove_error_message") if rodauth.field_error(rodauth.webauthn_remove_param) && id == usage.keys.last %>
@@ -0,0 +1,2 @@
1
+ Someone (hopefully you) has disabled TOTP authentication for the account
2
+ associated to this email address.
@@ -0,0 +1,9 @@
1
+ TOTP authentication has been locked out on your account due to too many
2
+ consecutive authentication failures. You can attempt to unlock TOTP
3
+ authentication for your account by consecutively authenticating via
4
+ TOTP multiple times.
5
+
6
+ If you did not initiate the TOTP authentication failures that
7
+ caused TOTP authentication to be locked out, that means someone already
8
+ has partial access to your account, but is unable to use TOTP
9
+ authentication to fully authenticate themselves.
@@ -0,0 +1,2 @@
1
+ Someone (hopefully you) has setup TOTP authentication for the account
2
+ associated to this email address.
@@ -0,0 +1,8 @@
1
+ Someone (hopefully you) attempted to unlock TOTP authentication for the
2
+ account associated to this email address, but failed as the
3
+ authentication code submitted was not correct.
4
+
5
+ If you did not initiate the TOTP authentication failure that generated
6
+ this email, that means someone already has partial access to your
7
+ account, but is unable to use TOTP authentication to fully authenticate
8
+ themselves.
@@ -0,0 +1,2 @@
1
+ Someone (hopefully you) has unlocked TOTP authentication for the account
2
+ associated to this email address.
@@ -0,0 +1,3 @@
1
+ Someone (hopefully you) has added a WebAuthn authenticator to the
2
+ account associated to this email address. There are now <%= @account.webauthn_keys.count %> WebAuthn
3
+ authenticator(s) with access to the account.
@@ -0,0 +1,3 @@
1
+ Someone (hopefully you) has removed a WebAuthn authenticator from the
2
+ account associated to this email address. There are now <%= @account.webauthn_keys.count %> WebAuthn
3
+ authenticator(s) with access to the account.
@@ -37,6 +37,7 @@ module Rodauth
37
37
  lockout: %w[unlock_account_request unlock_account],
38
38
  two_factor_base: %w[two_factor_manage two_factor_auth two_factor_disable],
39
39
  otp: %w[otp_setup otp_auth otp_disable],
40
+ otp_unlock: %w[otp_unlock otp_unlock_not_available],
40
41
  sms_codes: %w[sms_setup sms_confirm sms_auth sms_request sms_disable],
41
42
  recovery_codes: %w[recovery_codes add_recovery_codes recovery_auth],
42
43
  webauthn: %w[webauthn_setup webauthn_auth webauthn_remove],
@@ -45,7 +46,7 @@ module Rodauth
45
46
  }
46
47
 
47
48
  def create_views
48
- validate_features or return
49
+ return unless validate_features
49
50
 
50
51
  views.each do |view|
51
52
  copy_file view_location(view), "app/views/#{directory}/#{view}.html.erb" do |content|
@@ -13,6 +13,7 @@ module Rodauth
13
13
  end
14
14
 
15
15
  def rails_account
16
+ @rails_account = nil if account.nil? || @rails_account&.id != account_id
16
17
  @rails_account ||= instantiate_rails_account if account!
17
18
  end
18
19
 
@@ -59,7 +60,7 @@ module Rodauth
59
60
 
60
61
  def instantiate_rails_account
61
62
  if defined?(ActiveRecord::Base) && rails_account_model < ActiveRecord::Base
62
- if account[account_id_column]
63
+ if account_id
63
64
  rails_account_model.instantiate(account.stringify_keys)
64
65
  else
65
66
  rails_account_model.new(account)
@@ -25,7 +25,7 @@ module Rodauth
25
25
  def rails_render(*)
26
26
  render_output = nil
27
27
  rails_controller_instance.view_runtime = rails_controller_instance.send(:cleanup_view_runtime) do
28
- Benchmark.ms { render_output = super }
28
+ rails_benchmark { render_output = super }
29
29
  end
30
30
  render_output
31
31
  end
@@ -49,9 +49,9 @@ module Rodauth
49
49
  ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
50
50
  result = catch(:halt) { yield }
51
51
 
52
- response = ActionDispatch::Response.new(*(result || [404, {}, []]))
53
- payload[:response] = response
54
- payload[:status] = response.status
52
+ rails_response = build_rails_response(result || [404, {}, []])
53
+ payload[:response] = rails_response
54
+ payload[:status] = rails_response.status
55
55
 
56
56
  throw :halt, result if result
57
57
  rescue => error
@@ -66,13 +66,29 @@ module Rodauth
66
66
  ActiveSupport::Notifications.instrument("redirect_to.action_controller", request: rails_request) do |payload|
67
67
  result = catch(:halt) { yield }
68
68
 
69
- response = ActionDispatch::Response.new(*result)
70
- payload[:status] = response.status
71
- payload[:location] = response.filtered_location
69
+ rails_response = build_rails_response(result)
70
+ payload[:status] = rails_response.status
71
+ payload[:location] = rails_response.filtered_location
72
72
 
73
73
  throw :halt, result
74
74
  end
75
75
  end
76
+
77
+ def build_rails_response(args)
78
+ response = ActionDispatch::Response.new(*args)
79
+ response.request = rails_request
80
+ response
81
+ end
82
+
83
+ if ActionPack.version >= Gem::Version.new("8.0.0.beta1")
84
+ def rails_benchmark(&block)
85
+ ActiveSupport::Benchmark.realtime(:float_millisecond, &block)
86
+ end
87
+ else
88
+ def rails_benchmark(&block)
89
+ Benchmark.ms(&block)
90
+ end
91
+ end
76
92
  end
77
93
  end
78
94
  end
@@ -4,14 +4,18 @@ module Rodauth
4
4
  module InternalRequest
5
5
  extend ActiveSupport::Concern
6
6
 
7
+ included do
8
+ auth_private_methods :rails_url_options
9
+ end
10
+
7
11
  def domain
8
- return super unless missing_host? && rails_url_options
12
+ return super unless missing_host? && rails_url_options!
9
13
 
10
14
  rails_url_options.fetch(:host)
11
15
  end
12
16
 
13
17
  def base_url
14
- return super unless missing_host? && domain && rails_url_options
18
+ return super unless missing_host? && domain && rails_url_options!
15
19
 
16
20
  scheme = rails_url_options[:protocol] || "http"
17
21
  port = rails_url_options[:port]
@@ -21,6 +25,11 @@ module Rodauth
21
25
  url
22
26
  end
23
27
 
28
+ def rails_url_options
29
+ return _rails_url_options if frozen? # handle path_class_methods feature
30
+ @rails_url_options ||= _rails_url_options
31
+ end
32
+
24
33
  private
25
34
 
26
35
  def rails_controller_around
@@ -44,11 +53,12 @@ module Rodauth
44
53
  internal_request? && (request.host.nil? || request.host == INVALID_DOMAIN) || scope.nil?
45
54
  end
46
55
 
47
- def rails_url_options
48
- return nil unless defined?(ActionMailer)
56
+ def rails_url_options!
57
+ rails_url_options.presence or fail Error, "There is no information to set the URL host from. Please set config.action_mailer.default_url_options in your Rails application, configure #domain and #base_url in your Rodauth configuration, or set #rails_url_options on the Rodauth instance."
58
+ end
49
59
 
50
- ::Rails.configuration.action_mailer.default_url_options or
51
- fail Error, "There is no information to set the URL host from. Please set config.action_mailer.default_url_options in your Rails application, or configure #domain and #base_url in your Rodauth configuration."
60
+ def _rails_url_options
61
+ defined?(ActionMailer) ? ActionMailer::Base.default_url_options.dup : {}
52
62
  end
53
63
  end
54
64
  end
@@ -1,5 +1,5 @@
1
1
  module Rodauth
2
2
  module Rails
3
- VERSION = "1.14.1"
3
+ VERSION = "1.15.1"
4
4
  end
5
5
  end
@@ -6,18 +6,18 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ["Janko Marohnić"]
7
7
  spec.email = ["janko.marohnic@gmail.com"]
8
8
 
9
- spec.summary = %q{Provides Rails integration for Rodauth.}
10
- spec.description = %q{Provides Rails integration for Rodauth.}
9
+ spec.summary = %q{Provides Rails integration for Rodauth authentication framework.}
10
+ spec.description = %q{Provides Rails integration for Rodauth authentication framework.}
11
11
  spec.homepage = "https://github.com/janko/rodauth-rails"
12
12
  spec.license = "MIT"
13
13
 
14
14
  spec.required_ruby_version = ">= 2.5"
15
15
 
16
- spec.files = Dir["README.md", "LICENSE.txt", "CHANGELOG.md", "lib/**/*", "*.gemspec"]
16
+ spec.files = Dir["README.md", "LICENSE.txt", "lib/**/*", "*.gemspec"]
17
17
  spec.require_paths = ["lib"]
18
18
 
19
19
  spec.add_dependency "railties", ">= 5.0", "< 8"
20
- spec.add_dependency "rodauth", "~> 2.34"
20
+ spec.add_dependency "rodauth", "~> 2.36"
21
21
  spec.add_dependency "roda", "~> 3.76"
22
22
  spec.add_dependency "sequel-activerecord_connection", "~> 1.1"
23
23
  spec.add_dependency "rodauth-model", "~> 0.2"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.14.1
4
+ version: 1.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-15 00:00:00.000000000 Z
11
+ date: 2024-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '2.34'
39
+ version: '2.36'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '2.34'
46
+ version: '2.36'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: roda
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -170,17 +170,31 @@ dependencies:
170
170
  - - ">="
171
171
  - !ruby/object:Gem::Version
172
172
  version: '0'
173
- description: Provides Rails integration for Rodauth.
173
+ description: Provides Rails integration for Rodauth authentication framework.
174
174
  email:
175
175
  - janko.marohnic@gmail.com
176
176
  executables: []
177
177
  extensions: []
178
178
  extra_rdoc_files: []
179
179
  files:
180
- - CHANGELOG.md
181
180
  - LICENSE.txt
182
181
  - README.md
183
182
  - lib/generators/rodauth/install_generator.rb
183
+ - lib/generators/rodauth/mailer/email_auth.erb
184
+ - lib/generators/rodauth/mailer/otp_disabled.erb
185
+ - lib/generators/rodauth/mailer/otp_locked_out.erb
186
+ - lib/generators/rodauth/mailer/otp_setup.erb
187
+ - lib/generators/rodauth/mailer/otp_unlock_failed.erb
188
+ - lib/generators/rodauth/mailer/otp_unlocked.erb
189
+ - lib/generators/rodauth/mailer/password_changed.erb
190
+ - lib/generators/rodauth/mailer/reset_password.erb
191
+ - lib/generators/rodauth/mailer/reset_password_notify.erb
192
+ - lib/generators/rodauth/mailer/unlock_account.erb
193
+ - lib/generators/rodauth/mailer/verify_account.erb
194
+ - lib/generators/rodauth/mailer/verify_login_change.erb
195
+ - lib/generators/rodauth/mailer/webauthn_authenticator_added.erb
196
+ - lib/generators/rodauth/mailer/webauthn_authenticator_removed.erb
197
+ - lib/generators/rodauth/mailer_generator.rb
184
198
  - lib/generators/rodauth/migration/active_record/account_expiration.erb
185
199
  - lib/generators/rodauth/migration/active_record/active_sessions.erb
186
200
  - lib/generators/rodauth/migration/active_record/audit_logging.erb
@@ -190,6 +204,7 @@ files:
190
204
  - lib/generators/rodauth/migration/active_record/jwt_refresh.erb
191
205
  - lib/generators/rodauth/migration/active_record/lockout.erb
192
206
  - lib/generators/rodauth/migration/active_record/otp.erb
207
+ - lib/generators/rodauth/migration/active_record/otp_unlock.erb
193
208
  - lib/generators/rodauth/migration/active_record/password_expiration.erb
194
209
  - lib/generators/rodauth/migration/active_record/recovery_codes.erb
195
210
  - lib/generators/rodauth/migration/active_record/remember.erb
@@ -208,6 +223,7 @@ files:
208
223
  - lib/generators/rodauth/migration/sequel/jwt_refresh.erb
209
224
  - lib/generators/rodauth/migration/sequel/lockout.erb
210
225
  - lib/generators/rodauth/migration/sequel/otp.erb
226
+ - lib/generators/rodauth/migration/sequel/otp_unlock.erb
211
227
  - lib/generators/rodauth/migration/sequel/password_expiration.erb
212
228
  - lib/generators/rodauth/migration/sequel/recovery_codes.erb
213
229
  - lib/generators/rodauth/migration/sequel/remember.erb
@@ -240,6 +256,8 @@ files:
240
256
  - lib/generators/rodauth/templates/app/views/rodauth/otp_auth.html.erb
241
257
  - lib/generators/rodauth/templates/app/views/rodauth/otp_disable.html.erb
242
258
  - lib/generators/rodauth/templates/app/views/rodauth/otp_setup.html.erb
259
+ - lib/generators/rodauth/templates/app/views/rodauth/otp_unlock.html.erb
260
+ - lib/generators/rodauth/templates/app/views/rodauth/otp_unlock_not_available.html.erb
243
261
  - lib/generators/rodauth/templates/app/views/rodauth/recovery_auth.html.erb
244
262
  - lib/generators/rodauth/templates/app/views/rodauth/recovery_codes.html.erb
245
263
  - lib/generators/rodauth/templates/app/views/rodauth/remember.html.erb
@@ -266,6 +284,8 @@ files:
266
284
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/otp_auth.html.erb
267
285
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/otp_disable.html.erb
268
286
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/otp_setup.html.erb
287
+ - lib/generators/rodauth/templates/app/views/rodauth/tailwind/otp_unlock.html.erb
288
+ - lib/generators/rodauth/templates/app/views/rodauth/tailwind/otp_unlock_not_available.html.erb
269
289
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/recovery_auth.html.erb
270
290
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/recovery_codes.html.erb
271
291
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/remember.html.erb
@@ -301,12 +321,19 @@ files:
301
321
  - lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb
302
322
  - lib/generators/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb
303
323
  - lib/generators/rodauth/templates/app/views/rodauth_mailer/email_auth.text.erb
324
+ - lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_disabled.text.erb
325
+ - lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_locked_out.text.erb
326
+ - lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_setup.text.erb
327
+ - lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_unlock_failed.text.erb
328
+ - lib/generators/rodauth/templates/app/views/rodauth_mailer/otp_unlocked.text.erb
304
329
  - lib/generators/rodauth/templates/app/views/rodauth_mailer/password_changed.text.erb
305
330
  - lib/generators/rodauth/templates/app/views/rodauth_mailer/reset_password.text.erb
306
331
  - lib/generators/rodauth/templates/app/views/rodauth_mailer/reset_password_notify.text.erb
307
332
  - lib/generators/rodauth/templates/app/views/rodauth_mailer/unlock_account.text.erb
308
333
  - lib/generators/rodauth/templates/app/views/rodauth_mailer/verify_account.text.erb
309
334
  - lib/generators/rodauth/templates/app/views/rodauth_mailer/verify_login_change.text.erb
335
+ - lib/generators/rodauth/templates/app/views/rodauth_mailer/webauthn_authenticator_added.text.erb
336
+ - lib/generators/rodauth/templates/app/views/rodauth_mailer/webauthn_authenticator_removed.text.erb
310
337
  - lib/generators/rodauth/templates/config/initializers/rodauth.rb.tt
311
338
  - lib/generators/rodauth/templates/db/migrate/create_rodauth.rb.tt
312
339
  - lib/generators/rodauth/templates/test/fixtures/accounts.yml.tt
@@ -352,8 +379,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
352
379
  - !ruby/object:Gem::Version
353
380
  version: '0'
354
381
  requirements: []
355
- rubygems_version: 3.5.9
382
+ rubygems_version: 3.5.11
356
383
  signing_key:
357
384
  specification_version: 4
358
- summary: Provides Rails integration for Rodauth.
385
+ summary: Provides Rails integration for Rodauth authentication framework.
359
386
  test_files: []