rodauth-rails 1.14.1 → 1.15.1

Sign up to get free protection for your applications and to get access to all the features.
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: []