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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c1c699a9d7a18673c641d2fe236bfdb2b9537ade7c6212e9f2f386738308d67
4
- data.tar.gz: b30b4195d46e461f0235caaa1e2e453fb70260bda7d9174cbf60be8f43796f94
3
+ metadata.gz: d6f6be6f7643a5ee8a8c249c4c4a5591df43a63d32c85a2b3ee1427394b7becf
4
+ data.tar.gz: a838f4ddb1eab3b8e39acdeacac4830d5eb4024b4a44a3606c5de4c754c488de
5
5
  SHA512:
6
- metadata.gz: f8d67d9e2a738d66d9ba37bcf1f71f69c546d6a361e91248255966bdd8b49fadfff717ab28e44bd2cd0ad0cad784740ef631a7863b1403e56c267b8434c2d8e3
7
- data.tar.gz: 0b501ebf1306bbf9780ec86fd9267e75b3bcae3ee69f0b7f56f0c19132f1d8a96a8d7cfcae31dbb07b5636b42064833d5d8543ceb55d3d4432d22cb28ae9aa72
6
+ metadata.gz: da215ea65e513b90b41203d1652955b378e1c8b1145c476d4d0a15ef9b0a1f9ebc86f6818a4e35a2405805c663047c85a309e62de41af5c4e0259645f7326596
7
+ data.tar.gz: 11770055b40a703d6e7640c6c80f192a5eccaa0605d6b7c46fe24d9d61d8438224c763571d69a86ba767a222460db90b795407756ad112def5af27aff8f79052
data/README.md CHANGED
@@ -12,11 +12,13 @@ Provides Rails integration for the [Rodauth] authentication framework.
12
12
  * [OmniAuth guide](https://github.com/janko/rodauth-rails/wiki/OmniAuth)
13
13
  * [JSON Request Documentation for Rodauth](https://documenter.getpostman.com/view/26686011/2s9YC7SWn9)
14
14
 
15
- 🎥 Screencasts:
15
+ 🎥 Screencasts / Streams:
16
16
 
17
- * [Rails Authentication with Rodauth](https://www.youtube.com/watch?v=2hDpNikacf0)
18
- * [Multifactor Authentication with Rodauth](https://www.youtube.com/watch?v=9ON-kgXpz2A&list=PLkGQXZLACDTGKsaRWstkHQdm2CUmT3SZ-) ([TOTP](https://youtu.be/9ON-kgXpz2A), [Recovery Codes](https://youtu.be/lkFCcE1Q5-w))
19
- * [Add Admin Accounts](https://www.youtube.com/watch?v=N6z7AtKSpNI)
17
+ * [Rails Authentication with Rodauth](https://www.youtube.com/watch?v=2hDpNikacf0) \[8:23\]
18
+ * [Multifactor Authentication via TOTP with Rodauth](https://youtu.be/9ON-kgXpz2A) \[4:36\]
19
+ * [Multifactor Authentication via Recovery Codes with Rodauth](https://youtu.be/lkFCcE1Q5-w) \[4:24\]
20
+ * [Adding Admin Accounts with Rodauth](https://www.youtube.com/watch?v=N6z7AtKSpNI) \[1:25:55\]
21
+ * [Integrating Passkeys into Rails with Rodauth](https://www.youtube.com/watch?v=kGzgmfCmnmY) \[59:47\]
20
22
 
21
23
  📚 Articles:
22
24
 
@@ -68,7 +70,7 @@ $ rails generate rodauth:install
68
70
 
69
71
  This generator will create a Rodauth app and configuration with common
70
72
  authentication features enabled, a database migration with tables required by
71
- those features, a mailer with default templates, and a few other files.
73
+ those features, and a few other files.
72
74
 
73
75
  Feel free to remove any features you don't need, along with their corresponding
74
76
  tables. Afterwards, run the migration:
@@ -77,14 +79,6 @@ tables. Afterwards, run the migration:
77
79
  $ rails db:migrate
78
80
  ```
79
81
 
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
82
  ### Install options
89
83
 
90
84
  The install generator will use the `accounts` table by default. You can specify a different table name:
@@ -316,46 +310,45 @@ $ rails generate rodauth:views webauthn two_factor_base --name admin
316
310
 
317
311
  ## Mailer
318
312
 
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.
313
+ When you're ready to modify the default email templates and safely deliver them
314
+ in a background job, you can run the following command to generate the mailer
315
+ integration:
322
316
 
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
317
+ ```sh
318
+ $ rails generate rodauth:mailer
333
319
  ```
320
+
321
+ This will create a `RodauthMailer`, email templates, and necessary Rodauth
322
+ configuration for the features you have enabled. For email links to work, you
323
+ need to have `config.action_mailer.default_url_options` set for each
324
+ environment.
325
+
334
326
  ```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
327
+ # config/environments/development.rb
328
+ config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
329
+ ```
330
+
331
+ The generator accepts various options:
332
+
333
+ ```sh
334
+ # generate mailer integration for specified features
335
+ $ rails generate rodauth:mailer email_auth lockout webauthn_modify_email
336
+
337
+ # generate mailer integration for all Rodauth features
338
+ $ rails generate rodauth:mailer --all
339
+
340
+ # specify different Rodauth configuration to select enabled features
341
+ $ rails generate rodauth:mailer --name admin
350
342
  ```
351
343
 
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.
344
+ Note that the generated Rodauth configuration calls `#deliver_later`, which
345
+ uses Active Job to deliver emails in a background job. If you want to deliver
346
+ emails synchronously, you can modify the configuration to call `#deliver_now`
347
+ instead.
355
348
 
356
349
  If you're using a background processing library without an Active Job adapter,
357
350
  or a 3rd-party service for sending transactional emails, see [this wiki
358
- page][custom mailer worker] on how to set it up.
351
+ page][custom mailer job] on how to set it up.
359
352
 
360
353
  ## Migrations
361
354
 
@@ -535,6 +528,14 @@ Rodauth::Rails.rodauth(session: { two_factor_auth_setup: true })
535
528
  Rodauth::Rails.rodauth(:admin, params: { "param" => "value" })
536
529
  ```
537
530
 
531
+ You can override default URL options ad-hoc by modifying `#rails_url_options`:
532
+
533
+ ```rb
534
+ rodauth.base_url #=> "https://example.com"
535
+ rodauth.rails_url_options[:host] = "subdomain.example.com"
536
+ rodauth.base_url #=> "https://subdomain.example.com"
537
+ ```
538
+
538
539
  ### Using as a library
539
540
 
540
541
  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 +634,7 @@ The `rails` feature rodauth-rails loads provides the following configuration met
633
634
  | `rails_controller_instance` | Instance of the controller with the request env context. |
634
635
  | `rails_controller` | Controller class to use for rendering and CSRF protection. |
635
636
  | `rails_account_model` | Model class connected with the accounts table. |
637
+ | `rails_url_options` | Options used for generating URLs outside of a request (defaults to `config.action_mailer.default_url_options`) |
636
638
 
637
639
  ```rb
638
640
  class RodauthMain < Rodauth::Rails::Auth
@@ -786,7 +788,7 @@ conduct](CODE_OF_CONDUCT.md).
786
788
  [internal_request]: http://rodauth.jeremyevans.net/rdoc/files/doc/internal_request_rdoc.html
787
789
  [path_class_methods]: https://rodauth.jeremyevans.net/rdoc/files/doc/path_class_methods_rdoc.html
788
790
  [account types]: https://github.com/janko/rodauth-rails/wiki/Account-Types
789
- [custom mailer worker]: https://github.com/janko/rodauth-rails/wiki/Custom-Mailer-Worker
791
+ [custom mailer job]: https://github.com/janko/rodauth-rails/wiki/Custom-Mailer-Job
790
792
  [Turbo]: https://turbo.hotwired.dev/
791
793
  [rodauth-model]: https://github.com/janko/rodauth-model
792
794
  [JSON API]: https://github.com/janko/rodauth-rails/wiki/JSON-API
@@ -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?
@@ -74,7 +55,7 @@ module Rodauth
74
55
  end
75
56
 
76
57
  def show_instructions
77
- readme "INSTRUCTIONS" if behavior == :invoke
58
+ readme "INSTRUCTIONS" if behavior == :invoke && !api_only?
78
59
  end
79
60
 
80
61
  private
@@ -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
@@ -93,6 +93,7 @@ module Rodauth
93
93
  reset_password: { reset_password_table: "%{singular}_password_reset_keys" },
94
94
  email_auth: { email_auth_table: "%{singular}_email_auth_keys" },
95
95
  otp: { otp_keys_table: "%{singular}_otp_keys" },
96
+ otp_unlock: { otp_unlock_table: "%{singular}_otp_unlocks" },
96
97
  sms_codes: { sms_codes_table: "%{singular}_sms_codes" },
97
98
  recovery_codes: { recovery_codes_table: "%{singular}_recovery_codes" },
98
99
  webauthn: { webauthn_keys_table: "%{singular}_webauthn_keys", webauthn_user_ids_table: "%{singular}_webauthn_user_ids", webauthn_keys_account_id_column: "%{singular}_id" },
@@ -1,52 +1,31 @@
1
1
  ===============================================================================
2
2
 
3
- Depending on your application's configuration some manual setup may be required:
3
+ * Ensure you have defined a root path in your config/routes.rb. For example:
4
4
 
5
- 1. Ensure you have defined default url options in your environments files. Here
6
- is an example of default_url_options appropriate for a development environment
7
- in config/environments/development.rb:
5
+ root to: "pages#home"
8
6
 
9
- config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
7
+ * Ensure you're displaying flash messages in your layout template. For example:
10
8
 
11
- In production, :host should be set to the actual host of your application.
9
+ <% if notice %>
10
+ <div class="alert alert-success"><%= notice %></div>
11
+ <% end %>
12
+ <% if alert %>
13
+ <div class="alert alert-danger"><%= alert %></div>
14
+ <% end %>
12
15
 
13
- * Required for all applications. *
16
+ * Titles for Rodauth pages are available via @page_title instance variable
17
+ by default, you can use it in your layout file:
14
18
 
15
- 2. Ensure you have defined root_url to *something* in your config/routes.rb.
16
- For example:
19
+ <title><%= @page_title || "Default title" %></title>
17
20
 
18
- root to: "home#index"
21
+ * You can copy Rodauth views into your app by running:
19
22
 
20
- * Not required for API-only Applications *
23
+ rails g rodauth:views # default bootstrap views
21
24
 
22
- 3. Ensure you have flash messages in app/views/layouts/application.html.erb.
23
- For example:
25
+ rails g rodauth:views --css=tailwind # tailwind views (requires @tailwindcss/forms plugin)
24
26
 
25
- <% if notice %>
26
- <div class="alert alert-success"><%= notice %></div>
27
- <% end %>
28
- <% if alert %>
29
- <div class="alert alert-danger"><%= alert %></div>
30
- <% end %>
27
+ * You can copy email templates and generate mailer integration by running:
31
28
 
32
- * Not required for API-only Applications *
33
-
34
- 4. Titles for Rodauth pages are available via @page_title instance variable
35
- by default, you can use it in your layout file:
36
-
37
- <head>
38
- <title><%= @page_title || "Default title" %></title>
39
- ...
40
- </head>
41
-
42
- * Not required *
43
-
44
- 5. You can copy Rodauth views (for customization) to your app by running:
45
-
46
- rails g rodauth:views # default bootstrap views
47
-
48
- rails g rodauth:views --css=tailwind # tailwind views (requires @tailwindcss/forms plugin)
49
-
50
- * Not required *
29
+ rails g rodauth:mailer
51
30
 
52
31
  ===============================================================================