rodauth-rails 1.14.1 → 1.15.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -40
  3. data/lib/generators/rodauth/install_generator.rb +6 -22
  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 +3 -3
  26. data/lib/generators/rodauth/templates/INSTRUCTIONS +8 -2
  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 -26
  29. data/lib/generators/rodauth/templates/app/models/account.rb.tt +1 -1
  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 +12 -6
  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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c1c699a9d7a18673c641d2fe236bfdb2b9537ade7c6212e9f2f386738308d67
4
- data.tar.gz: b30b4195d46e461f0235caaa1e2e453fb70260bda7d9174cbf60be8f43796f94
3
+ metadata.gz: 12ac51c0ef57f053d8bdc843eef7a846554defb7e37403b9ccf2ab83bd52fb6b
4
+ data.tar.gz: 5854a05239bfbb92f2b0aecc5c0e9dd1de22388d364afc6f4fe601e4900c54c5
5
5
  SHA512:
6
- metadata.gz: f8d67d9e2a738d66d9ba37bcf1f71f69c546d6a361e91248255966bdd8b49fadfff717ab28e44bd2cd0ad0cad784740ef631a7863b1403e56c267b8434c2d8e3
7
- data.tar.gz: 0b501ebf1306bbf9780ec86fd9267e75b3bcae3ee69f0b7f56f0c19132f1d8a96a8d7cfcae31dbb07b5636b42064833d5d8543ceb55d3d4432d22cb28ae9aa72
6
+ metadata.gz: bbf3d3cc5f453756a8a52a73409de3134569aa12908be81a505e637b0a05f890735a9589df237fb1e7f2f9687a5df2ac6821586d0e4cd52995d9efd3b0989e46
7
+ data.tar.gz: 6c1725dc4b64c498a6d840aba77c61c273df112bb712610b8342ebded946c7dfdb7a4e7fe33ffac69303ff8020223902040a66ebb58d6cd7247a085ceebdd448
data/README.md CHANGED
@@ -68,7 +68,7 @@ $ rails generate rodauth:install
68
68
 
69
69
  This generator will create a Rodauth app and configuration with common
70
70
  authentication features enabled, a database migration with tables required by
71
- those features, a mailer with default templates, and a few other files.
71
+ those features, and a few other files.
72
72
 
73
73
  Feel free to remove any features you don't need, along with their corresponding
74
74
  tables. Afterwards, run the migration:
@@ -77,14 +77,6 @@ tables. Afterwards, run the migration:
77
77
  $ rails db:migrate
78
78
  ```
79
79
 
80
- For your mailer to be able to generate email links, you'll need to set up
81
- default URL options in each environment. Here is a possible configuration for
82
- `config/environments/development.rb`:
83
-
84
- ```rb
85
- config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
86
- ```
87
-
88
80
  ### Install options
89
81
 
90
82
  The install generator will use the `accounts` table by default. You can specify a different table name:
@@ -316,42 +308,41 @@ $ rails generate rodauth:views webauthn two_factor_base --name admin
316
308
 
317
309
  ## Mailer
318
310
 
319
- The install generator will create `RodauthMailer` with default email templates,
320
- and configure Rodauth features that send emails as part of the authentication
321
- flow to use it.
311
+ When you're ready to modify the default email templates and safely deliver them
312
+ in a background job, you can run the following command to generate the mailer
313
+ integration:
322
314
 
323
- ```rb
324
- # app/mailers/rodauth_mailer.rb
325
- class RodauthMailer < ApplicationMailer
326
- def verify_account(account_id, key) ... end
327
- def reset_password(account_id, key) ... end
328
- def verify_login_change(account_id, key) ... end
329
- def password_changed(account_id) ... end
330
- # def email_auth(account_id, key) ... end
331
- # def unlock_account(account_id, key) ... end
332
- end
315
+ ```sh
316
+ $ rails generate rodauth:mailer
333
317
  ```
318
+
319
+ This will create a `RodauthMailer`, email templates, and necessary Rodauth
320
+ configuration for the features you have enabled. For email links to work, you
321
+ need to have `config.action_mailer.default_url_options` set for each
322
+ environment.
323
+
334
324
  ```rb
335
- # app/misc/rodauth_main.rb
336
- class RodauthMain < Rodauth::Rails::Auth
337
- configure do
338
- create_reset_password_email { RodauthMailer.reset_password(account_id, reset_password_key_value) }
339
- create_verify_account_email { RodauthMailer.verify_account(account_id, verify_account_key_value) }
340
- create_verify_login_change_email { |_login| RodauthMailer.verify_login_change(account_id, verify_login_change_key_value) }
341
- create_password_changed_email { RodauthMailer.password_changed(account_id) }
342
- # create_email_auth_email { RodauthMailer.email_auth(account_id, email_auth_key_value) }
343
- # create_unlock_account_email { RodauthMailer.unlock_account(account_id, unlock_account_key_value) }
344
- send_email do |email|
345
- # queue email delivery on the mailer after the transaction commits
346
- db.after_commit { email.deliver_later }
347
- end
348
- end
349
- end
325
+ # config/environments/development.rb
326
+ config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
327
+ ```
328
+
329
+ The generator accepts various options:
330
+
331
+ ```sh
332
+ # generate mailer integration for specified features
333
+ $ rails generate rodauth:mailer email_auth lockout webauthn_modify_email
334
+
335
+ # generate mailer integration for all Rodauth features
336
+ $ rails generate rodauth:mailer --all
337
+
338
+ # specify different Rodauth configuration to select enabled features
339
+ $ rails generate rodauth:mailer --name admin
350
340
  ```
351
341
 
352
- This configuration calls `#deliver_later`, which uses Active Job to deliver
353
- emails in a background job. If you want to send emails synchronously, you can
354
- modify the configuration to call `#deliver_now` instead.
342
+ Note that the generated Rodauth configuration calls `#deliver_later`, which
343
+ uses Active Job to deliver emails in a background job. If you want to deliver
344
+ emails synchronously, you can modify the configuration to call `#deliver_now`
345
+ instead.
355
346
 
356
347
  If you're using a background processing library without an Active Job adapter,
357
348
  or a 3rd-party service for sending transactional emails, see [this wiki
@@ -535,6 +526,14 @@ Rodauth::Rails.rodauth(session: { two_factor_auth_setup: true })
535
526
  Rodauth::Rails.rodauth(:admin, params: { "param" => "value" })
536
527
  ```
537
528
 
529
+ You can override default URL options ad-hoc by modifying `#rails_url_options`:
530
+
531
+ ```rb
532
+ rodauth.base_url #=> "https://example.com"
533
+ rodauth.rails_url_options[:host] = "subdomain.example.com"
534
+ rodauth.base_url #=> "https://subdomain.example.com"
535
+ ```
536
+
538
537
  ### Using as a library
539
538
 
540
539
  Rodauth offers a [`Rodauth.lib`][library] method for when you want to use it as a library (via [internal requests][internal_request]), as opposed to having it route requests. This gem provides a `Rodauth::Rails.lib` counterpart that does the same but with Rails integration:
@@ -633,6 +632,7 @@ The `rails` feature rodauth-rails loads provides the following configuration met
633
632
  | `rails_controller_instance` | Instance of the controller with the request env context. |
634
633
  | `rails_controller` | Controller class to use for rendering and CSRF protection. |
635
634
  | `rails_account_model` | Model class connected with the accounts table. |
635
+ | `rails_url_options` | Options used for generating URLs outside of a request (defaults to `config.action_mailer.default_url_options`) |
636
636
 
637
637
  ```rb
638
638
  class RodauthMain < Rodauth::Rails::Auth
@@ -13,15 +13,6 @@ module Rodauth
13
13
  "sqlserver" => RUBY_ENGINE == "jruby" ? "mssql" : "tinytds",
14
14
  }
15
15
 
16
- MAILER_VIEWS = %w[
17
- email_auth
18
- password_changed
19
- reset_password
20
- unlock_account
21
- verify_account
22
- verify_login_change
23
- ]
24
-
25
16
  source_root "#{__dir__}/templates"
26
17
  namespace "rodauth:install"
27
18
 
@@ -55,16 +46,6 @@ module Rodauth
55
46
  template "app/models/account.rb", "app/models/#{table_prefix}.rb"
56
47
  end
57
48
 
58
- def create_mailer
59
- return unless defined?(ActionMailer)
60
-
61
- template "app/mailers/rodauth_mailer.rb"
62
-
63
- MAILER_VIEWS.each do |view|
64
- copy_file "app/views/rodauth_mailer/#{view}.text.erb"
65
- end
66
- end
67
-
68
49
  def create_fixtures
69
50
  generator_options = ::Rails.configuration.generators.options
70
51
  if generator_options[:test_unit][:fixture] && generator_options[:test_unit][:fixture_replacement].nil?
@@ -101,9 +82,12 @@ module Rodauth
101
82
  options[:argon2]
102
83
  end
103
84
 
104
- def sequel_activerecord_integration?
105
- defined?(ActiveRecord::Railtie) &&
106
- (!defined?(Sequel) || Sequel::DATABASES.empty?)
85
+ def activerecord?
86
+ defined?(ActiveRecord::Railtie)
87
+ end
88
+
89
+ def sequel?
90
+ defined?(Sequel) && Sequel::DATABASES.any?
107
91
  end
108
92
 
109
93
  def session_store?
@@ -0,0 +1,6 @@
1
+ def email_auth(name, account_id, key)
2
+ @rodauth = rodauth(name, account_id) { @email_auth_key_value = key }
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.email_auth_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def otp_disabled(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.otp_disabled_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def otp_locked_out(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.otp_locked_out_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def otp_setup(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.otp_setup_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def otp_unlock_failed(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.otp_unlock_failed_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def otp_unlocked(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.otp_unlocked_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def password_changed(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.password_changed_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def reset_password(name, account_id, key)
2
+ @rodauth = rodauth(name, account_id) { @reset_password_key_value = key }
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.reset_password_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def reset_password_notify(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.reset_password_notify_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def unlock_account(name, account_id, key)
2
+ @rodauth = rodauth(name, account_id) { @unlock_account_key_value = key }
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.unlock_account_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def verify_account(name, account_id, key)
2
+ @rodauth = rodauth(name, account_id) { @verify_account_key_value = key }
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.verify_account_email_subject
6
+ end
@@ -0,0 +1,7 @@
1
+ def verify_login_change(name, account_id, key)
2
+ @rodauth = rodauth(name, account_id) { @verify_login_change_key_value = key }
3
+ @account = @rodauth.rails_account
4
+ @new_email = @account.login_change_key.login
5
+
6
+ mail to: @new_email, subject: @rodauth.email_subject_prefix + @rodauth.verify_login_change_email_subject
7
+ end
@@ -0,0 +1,6 @@
1
+ def webauthn_authenticator_added(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.webauthn_authenticator_added_email_subject
6
+ end
@@ -0,0 +1,6 @@
1
+ def webauthn_authenticator_removed(name, account_id)
2
+ @rodauth = rodauth(name, account_id)
3
+ @account = @rodauth.rails_account
4
+
5
+ mail subject: @rodauth.email_subject_prefix + @rodauth.webauthn_authenticator_removed_email_subject
6
+ end
@@ -0,0 +1,126 @@
1
+ require "rails/generators/base"
2
+
3
+ module Rodauth
4
+ module Rails
5
+ module Generators
6
+ class MailerGenerator < ::Rails::Generators::Base
7
+ source_root "#{__dir__}/templates"
8
+ namespace "rodauth:mailer"
9
+
10
+ argument :selected_features, optional: true, type: :array,
11
+ desc: "Rodauth features to generate mailer integration for (verify_account, verify_login_change, reset_password etc.)"
12
+
13
+ class_option :all, aliases: "-a", type: :boolean,
14
+ desc: "Generates mailer integration for all Rodauth features",
15
+ default: false
16
+
17
+ class_option :name, aliases: "-n", type: :string,
18
+ desc: "The configuration name for which to generate mailer configuration",
19
+ default: nil
20
+
21
+ EMAILS = {
22
+ verify_account: %w[verify_account],
23
+ reset_password: %w[reset_password],
24
+ verify_login_change: %w[verify_login_change],
25
+ email_auth: %w[email_auth],
26
+ lockout: %w[unlock_account],
27
+ reset_password_notify: %w[reset_password_notify],
28
+ change_password_notify: %w[password_changed],
29
+ otp_modify_email: %w[otp_setup otp_disabled],
30
+ otp_lockout_email: %w[otp_locked_out otp_unlocked otp_unlock_failed],
31
+ webauthn_modify_email: %w[webauthn_authenticator_added webauthn_authenticator_removed],
32
+ }
33
+
34
+ TOKENS = %w[reset_password verify_account verify_login_change email_auth unlock_account]
35
+
36
+ def copy_mailer_views
37
+ return unless validate_features
38
+
39
+ emails.each do |email|
40
+ copy_file "app/views/rodauth_mailer/#{email}.text.erb"
41
+ end
42
+ end
43
+
44
+ def copy_mailer
45
+ return unless validate_features
46
+
47
+ if File.exist?("#{destination_root}/app/mailers/rodauth_mailer.rb") && options.fetch(:skip, true) && !options[:force] && behavior == :invoke
48
+ say "\nCopy the following lines into your Rodauth mailer:\n\n#{mailer_content}"
49
+ else
50
+ template "app/mailers/rodauth_mailer.rb"
51
+ end
52
+ end
53
+
54
+ def show_configuration
55
+ return unless behavior == :invoke && validate_features
56
+
57
+ say "\nCopy the following lines into your Rodauth configuration:\n\n#{configuration_content}"
58
+ end
59
+
60
+ private
61
+
62
+ def mailer_content
63
+ emails
64
+ .map { |email| File.read("#{__dir__}/mailer/#{email}.erb") }
65
+ .map { |content| erb_eval(content) }
66
+ .join("\n")
67
+ .indent(2)
68
+ end
69
+
70
+ def configuration_content
71
+ emails
72
+ .map { |email| configuration_chunk(email) }
73
+ .join
74
+ .indent(2)
75
+ end
76
+
77
+ def configuration_chunk(email)
78
+ <<~RUBY
79
+ create_#{email}_email do#{" |_login|" if email == "verify_login_change"}
80
+ RodauthMailer.#{email}(self.class.configuration_name, account_id#{", #{email}_key_value" if TOKENS.include?(email)})
81
+ end
82
+ RUBY
83
+ end
84
+
85
+ def erb_eval(content)
86
+ if ERB.version[/\d+\.\d+\.\d+/].to_s >= "2.2.0"
87
+ ERB.new(content, trim_mode: "-").result(binding)
88
+ else
89
+ ERB.new(content, 0, "-").result(binding)
90
+ end
91
+ end
92
+
93
+ def emails
94
+ features.flat_map { |feature| EMAILS.fetch(feature) }
95
+ end
96
+
97
+ def validate_features
98
+ if (features - EMAILS.keys).any?
99
+ say "No available email template for feature(s): #{(features - EMAILS.keys).join(", ")}", :error
100
+ false
101
+ else
102
+ true
103
+ end
104
+ end
105
+
106
+ def features
107
+ if options[:all]
108
+ EMAILS.keys
109
+ elsif selected_features
110
+ selected_features.map(&:to_sym)
111
+ else
112
+ rodauth_configuration.features & EMAILS.keys
113
+ end
114
+ end
115
+
116
+ def rodauth_configuration
117
+ Rodauth::Rails.app.rodauth!(configuration_name)
118
+ end
119
+
120
+ def configuration_name
121
+ options[:name]&.to_sym
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -11,6 +11,6 @@ create_table :<%= table_prefix %>_authentication_audit_logs<%= primary_key_type
11
11
  <% else -%>
12
12
  t.string :metadata
13
13
  <% end -%>
14
- t.index [:<%= table_prefix %>_id, :at], name: "audit_<%= table_prefix %>_at_idx"
15
- t.index :at, name: "audit_at_idx"
14
+ t.index [:<%= table_prefix %>_id, :at]
15
+ t.index :at
16
16
  end
@@ -3,5 +3,4 @@ create_table :<%= table_prefix %>_jwt_refresh_keys<%= primary_key_type %> do |t|
3
3
  t.references :<%= table_prefix %>, foreign_key: true, null: false<%= primary_key_type(:type) %>
4
4
  t.string :key, null: false
5
5
  t.datetime :deadline, null: false
6
- t.index :<%= table_prefix %>_id, name: "<%= table_prefix %>_jwt_rk_<%= table_prefix %>_id_idx"
7
6
  end
@@ -0,0 +1,7 @@
1
+ # Used by the otp_unlock feature
2
+ create_table :<%= table_prefix %>_otp_unlocks, id: false do |t|
3
+ t.<%= primary_key_type(nil) %> :id, primary_key: true
4
+ t.foreign_key :<%= table_prefix.pluralize %>, column: :id
5
+ t.integer :num_successes, null: false, default: 1
6
+ t.datetime :next_auth_attempt_after, null: false, default: -> { "<%= current_timestamp %>" }
7
+ end
@@ -12,6 +12,6 @@ create_table :<%= table_prefix %>_authentication_audit_logs do
12
12
  <% else -%>
13
13
  String :metadata
14
14
  <% end -%>
15
- index [:<%= table_prefix %>_id, :at], name: :audit_<%= table_prefix %>_at_idx
16
- index :at, name: :audit_at_idx
15
+ index [:<%= table_prefix %>_id, :at]
16
+ index :at
17
17
  end
@@ -4,5 +4,5 @@ create_table :<%= table_prefix %>_jwt_refresh_keys do
4
4
  foreign_key :<%= table_prefix %>_id, :<%= table_prefix.pluralize %>, null: false, type: :Bignum
5
5
  String :key, null: false
6
6
  DateTime :deadline, null: false
7
- index :<%= table_prefix %>_id, name: :<%= table_prefix %>_jwt_rk_<%= table_prefix %>_id_idx
7
+ index :<%= table_prefix %>_id
8
8
  end
@@ -0,0 +1,6 @@
1
+ # Used by the otp_unlock feature
2
+ create_table :<%= table_prefix %>_otp_unlocks do
3
+ foreign_key :id, :<%= table_prefix.pluralize %>, primary_key: true, type: :Bignum
4
+ Integer :num_successes, null: false, default: 1
5
+ Time :next_auth_attempt_after, null: false, default: Sequel::CURRENT_TIMESTAMP
6
+ end
@@ -20,12 +20,12 @@ module Rodauth
20
20
  desc: "Name of the generated migration file"
21
21
 
22
22
  def create_rodauth_migration
23
- validate_features or return
23
+ return unless validate_features
24
24
 
25
25
  migration_template "db/migrate/create_rodauth.rb", File.join(db_migrate_path, "#{migration_name}.rb")
26
26
  end
27
27
 
28
- def show_instructions
28
+ def show_configuration
29
29
  # skip if called from install generator, it already adds configuration
30
30
  return if current_command_chain.include?(:generate_rodauth_migration)
31
31
  return unless options[:prefix] && behavior == :invoke
@@ -36,7 +36,7 @@ module Rodauth
36
36
  .join("\n")
37
37
  .indent(2)
38
38
 
39
- say "\nAdd the following to your Rodauth configuration:\n\n#{configuration}"
39
+ say "\nCopy the following lines into your Rodauth configuration:\n\n#{configuration}"
40
40
  end
41
41
 
42
42
  private
@@ -39,7 +39,7 @@ Depending on your application's configuration some manual setup may be required:
39
39
  ...
40
40
  </head>
41
41
 
42
- * Not required *
42
+ * Not required *
43
43
 
44
44
  5. You can copy Rodauth views (for customization) to your app by running:
45
45
 
@@ -47,6 +47,12 @@ Depending on your application's configuration some manual setup may be required:
47
47
 
48
48
  rails g rodauth:views --css=tailwind # tailwind views (requires @tailwindcss/forms plugin)
49
49
 
50
- * Not required *
50
+ * Not required *
51
+
52
+ 6. You can generate email templates and mailer integration by running:
53
+
54
+ rails g rodauth:mailer
55
+
56
+ * Not required *
51
57
 
52
58
  ===============================================================================
@@ -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 }
@@ -1,4 +1,4 @@
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") -%>