rodauth-rails 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/README.md +10 -18
  4. data/lib/generators/rodauth/install_generator.rb +1 -1
  5. data/lib/generators/rodauth/migration/active_record/active_sessions.erb +2 -2
  6. data/lib/generators/rodauth/migration/active_record/audit_logging.erb +2 -2
  7. data/lib/generators/rodauth/migration/active_record/email_auth.erb +1 -1
  8. data/lib/generators/rodauth/migration/active_record/otp.erb +1 -1
  9. data/lib/generators/rodauth/migration/active_record/password_expiration.erb +1 -1
  10. data/lib/generators/rodauth/migration/active_record/reset_password.erb +1 -1
  11. data/lib/generators/rodauth/migration/active_record/sms_codes.erb +1 -1
  12. data/lib/generators/rodauth/migration/active_record/verify_account.erb +2 -2
  13. data/lib/generators/rodauth/migration/active_record/webauthn.erb +1 -1
  14. data/lib/generators/rodauth/migration_generator.rb +2 -22
  15. data/lib/generators/rodauth/templates/app/mailers/rodauth_mailer.rb.tt +7 -7
  16. data/lib/generators/rodauth/templates/app/misc/rodauth_main.rb.tt +1 -1
  17. data/lib/generators/rodauth/templates/app/views/rodauth/_login_form.html.erb +1 -1
  18. data/lib/generators/rodauth/templates/app/views/rodauth/login.html.erb +2 -2
  19. data/lib/generators/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +2 -2
  20. data/lib/generators/rodauth/templates/app/views/rodauth/tailwind/_login_form.html.erb +1 -1
  21. data/lib/generators/rodauth/templates/app/views/rodauth/tailwind/login.html.erb +2 -2
  22. data/lib/generators/rodauth/templates/app/views/rodauth/tailwind/multi_phase_login.html.erb +2 -2
  23. data/lib/generators/rodauth/templates/app/views/rodauth/tailwind/webauthn_autofill.html.erb +10 -0
  24. data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_autofill.html.erb +10 -0
  25. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/unlock_account.text.erb +1 -1
  26. data/lib/generators/rodauth/templates/db/migrate/create_rodauth.rb.tt +1 -1
  27. data/lib/generators/rodauth/views_generator.rb +3 -12
  28. data/lib/rodauth/rails/app.rb +7 -9
  29. data/lib/rodauth/rails/feature/base.rb +5 -29
  30. data/lib/rodauth/rails/feature/render.rb +1 -1
  31. data/lib/rodauth/rails/railtie.rb +2 -6
  32. data/lib/rodauth/rails/version.rb +1 -1
  33. data/lib/rodauth/rails.rb +0 -10
  34. data/rodauth-rails.gemspec +2 -2
  35. metadata +9 -9
  36. data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_header.html.erb +0 -3
  37. data/lib/generators/rodauth/templates/app/views/rodauth/tailwind/_login_form_header.html.erb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df597e01d85bea28254330ac00e288d569fe709744e11ade3ada370784034b6a
4
- data.tar.gz: 2934d9ea6177fa55e383cfbcbfdca6b4b27a36a1afdb7c9971e918fbca76e604
3
+ metadata.gz: 8f73ab003a11054b2534802c0de9224c867b7a173d8d553888918fa792ee3da4
4
+ data.tar.gz: 07136b1748df5970d5d263d5d9439596c3c2e083ccd88269ab7145a8cd73fefc
5
5
  SHA512:
6
- metadata.gz: bf30eabb2fb372e96caf39ceb0e01696dcc45003db00703fd4eaa127bba8378a0e76c4194b0f2161851df82a066f0147ed72cedea25429657a287734f76d4e49
7
- data.tar.gz: 40f773856e54971d573995e7f6c11b9a67c42c881ce95e458739fc5a12151a954233b3e80339beff622b82e79bc5485fc6497f7dd90c09cfd42ed2ca1abe3912
6
+ metadata.gz: bc8c1a0ef2cd7d9c49f9fed9dd6423e92ec4112ddaa65b5a8fa63134f35d5fa9b5f2f1679c4d4d7f4d9f3cd5a71acf840d4d59ce2731b52d82914c200744eb03
7
+ data.tar.gz: 41f707560dd3ce232f54c80bc83f2210d4667d715c5f25aab812382a54f4115cab03d3e8e23d1c8c8b1e5e572404c91b332b040b741648c2577499779c0bf6a1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 1.9.0 (2023-05-22)
2
+
3
+ * Add support for webauthn_autofill feature to the views generator (@janko)
4
+
5
+ * Generate view templates for two_factor_base feature only if explicitly specified (@janko)
6
+
7
+ * Set `login_param "email"` in generated Rodauth configuration (@janko)
8
+
9
+ * Handle Trilogy adapter in generators (@janko)
10
+
11
+ * Use `email_subject_prefix` in generated mailer (@janko)
12
+
13
+ * Fix typo in `unlock_account` email template (@zavan)
14
+
15
+ * Retrieve current account using `account!` in `#rails_account` method (@janko)
16
+
17
+ * Drop support for Rails 4.2 (@janko)
18
+
1
19
  ## 1.8.0 (2023-02-25)
2
20
 
3
21
  * Add table argument to `rodauth:install` generator (@janko)
data/README.md CHANGED
@@ -31,16 +31,13 @@ There are already several popular authentication solutions for Rails (Devise,
31
31
  Sorcery, Clearance, Authlogic), so why would you choose Rodauth? Here are some
32
32
  of the advantages that stand out for me:
33
33
 
34
- * multifactor authentication ([TOTP][otp], [SMS codes][sms_codes], [recovery codes][recovery_codes], [WebAuthn][webauthn])
34
+ * multifactor authentication ([TOTP][otp], [SMS codes][sms_codes], [recovery codes][recovery_codes], [passkeys][webauthn])
35
35
  * standardized [JSON API support][json] for every feature (including [JWT][jwt])
36
36
  * enterprise security features ([password complexity][password_complexity], [disallow password reuse][disallow_password_reuse], [password expiration][password_expiration], [session expiration][session_expiration], [single session][single_session], [account expiration][account_expiration])
37
- * [email authentication][email_auth] (aka "passwordless")
38
- * [audit logging][audit_logging] (for any action)
37
+ * passwordless authentication ([email][email_auth], [passkeys][webauthn_login])
38
+ * [audit logging][audit_logging] for any action
39
39
  * ability to protect password hashes even in case of SQL injection ([more details][password protection])
40
- * additional bruteforce protection for tokens ([more details][bruteforce tokens])
41
- * uniform configuration DSL (any setting can be static or dynamic)
42
- * consistent before/after hooks around everything
43
- * dedicated object encapsulating all authentication logic
40
+ * uniform configuration DSL with before/after hooks around everything
44
41
 
45
42
  ### Sequel
46
43
 
@@ -349,7 +346,7 @@ $ rails generate rodauth:views --all
349
346
  Use `--name` to generate views for a different Rodauth configuration:
350
347
 
351
348
  ```sh
352
- $ rails generate rodauth:views webauthn --name admin
349
+ $ rails generate rodauth:views webauthn two_factor_base --name admin
353
350
  ```
354
351
 
355
352
  #### Page titles
@@ -855,32 +852,27 @@ documentation].
855
852
  ### Defining custom methods
856
853
 
857
854
  All Rodauth configuration methods are just syntax sugar for defining instance
858
- methods on the auth class. You can also define your own custom methods on the
859
- auth class:
855
+ methods on the auth class. You can also define your own custom methods:
860
856
 
861
857
  ```rb
862
858
  class RodauthMain < Rodauth::Rails::Auth
863
859
  configure do
864
- # ...
865
860
  password_match? { |password| ldap_valid?(password) }
866
- # ...
867
861
  end
868
862
 
869
- # Example external identities table
870
- def identities
871
- db[:account_identities].where(account_id: account_id).all
863
+ def admin?
864
+ rails_account.admin?
872
865
  end
873
866
 
874
867
  private
875
868
 
876
- # Example LDAP authentication
877
869
  def ldap_valid?(password)
878
870
  SimpleLdapAuthenticator.valid?(account[:email], password)
879
871
  end
880
872
  end
881
873
  ```
882
874
  ```rb
883
- rodauth.identities #=> [{ provider: "facebook", uid: "abc123", ... }, ...]
875
+ rodauth.admin? #=> true
884
876
  ```
885
877
 
886
878
  ### Rails URL helpers
@@ -1227,12 +1219,12 @@ conduct](CODE_OF_CONDUCT.md).
1227
1219
  [sms_codes]: http://rodauth.jeremyevans.net/rdoc/files/doc/sms_codes_rdoc.html
1228
1220
  [recovery_codes]: http://rodauth.jeremyevans.net/rdoc/files/doc/recovery_codes_rdoc.html
1229
1221
  [webauthn]: http://rodauth.jeremyevans.net/rdoc/files/doc/webauthn_rdoc.html
1222
+ [webauthn_login]: http://rodauth.jeremyevans.net/rdoc/files/doc/webauthn_login_rdoc.html
1230
1223
  [json]: http://rodauth.jeremyevans.net/rdoc/files/doc/json_rdoc.html
1231
1224
  [jwt]: http://rodauth.jeremyevans.net/rdoc/files/doc/jwt_rdoc.html
1232
1225
  [email_auth]: http://rodauth.jeremyevans.net/rdoc/files/doc/email_auth_rdoc.html
1233
1226
  [audit_logging]: http://rodauth.jeremyevans.net/rdoc/files/doc/audit_logging_rdoc.html
1234
1227
  [password protection]: https://github.com/jeremyevans/rodauth#label-Password+Hash+Access+Via+Database+Functions
1235
- [bruteforce tokens]: https://github.com/jeremyevans/rodauth#label-Tokens
1236
1228
  [password_complexity]: http://rodauth.jeremyevans.net/rdoc/files/doc/password_complexity_rdoc.html
1237
1229
  [disallow_password_reuse]: http://rodauth.jeremyevans.net/rdoc/files/doc/disallow_password_reuse_rdoc.html
1238
1230
  [password_expiration]: http://rodauth.jeremyevans.net/rdoc/files/doc/password_expiration_rdoc.html
@@ -111,7 +111,7 @@ module Rodauth
111
111
  end
112
112
 
113
113
  def api_only?
114
- Rodauth::Rails.api_only?
114
+ ::Rails.application.config.api_only
115
115
  end
116
116
 
117
117
  def sequel_adapter
@@ -2,6 +2,6 @@
2
2
  create_table :<%= table_prefix %>_active_session_keys, primary_key: [:<%= table_prefix %>_id, :session_id] do |t|
3
3
  t.references :<%= table_prefix %>, foreign_key: true<%= primary_key_type(:type) %>
4
4
  t.string :session_id
5
- t.datetime :created_at, null: false, default: <%= current_timestamp %>
6
- t.datetime :last_use, null: false, default: <%= current_timestamp %>
5
+ t.datetime :created_at, null: false, default: -> { "<%= current_timestamp %>" }
6
+ t.datetime :last_use, null: false, default: -> { "<%= current_timestamp %>" }
7
7
  end
@@ -1,12 +1,12 @@
1
1
  # Used by the audit logging feature
2
2
  create_table :<%= table_prefix %>_authentication_audit_logs<%= primary_key_type %> do |t|
3
3
  t.references :<%= table_prefix %>, foreign_key: true, null: false<%= primary_key_type(:type) %>
4
- t.datetime :at, null: false, default: <%= current_timestamp %>
4
+ t.datetime :at, null: false, default: -> { "<%= current_timestamp %>" }
5
5
  t.text :message, null: false
6
6
  <% case activerecord_adapter -%>
7
7
  <% when "postgresql" -%>
8
8
  t.jsonb :metadata
9
- <% when "sqlite3", "mysql2" -%>
9
+ <% when "sqlite3", "mysql2", "trilogy" -%>
10
10
  t.json :metadata
11
11
  <% else -%>
12
12
  t.string :metadata
@@ -4,5 +4,5 @@ create_table :<%= table_prefix %>_email_auth_keys, id: false do |t|
4
4
  t.foreign_key :<%= table_prefix.pluralize %>, column: :id
5
5
  t.string :key, null: false
6
6
  t.datetime :deadline, null: false
7
- t.datetime :email_last_sent, null: false, default: <%= current_timestamp %>
7
+ t.datetime :email_last_sent, null: false, default: -> { "<%= current_timestamp %>" }
8
8
  end
@@ -4,5 +4,5 @@ create_table :<%= table_prefix %>_otp_keys, id: false do |t|
4
4
  t.foreign_key :<%= table_prefix.pluralize %>, column: :id
5
5
  t.string :key, null: false
6
6
  t.integer :num_failures, null: false, default: 0
7
- t.datetime :last_use, null: false, default: <%= current_timestamp %>
7
+ t.datetime :last_use, null: false, default: -> { "<%= current_timestamp %>" }
8
8
  end
@@ -2,5 +2,5 @@
2
2
  create_table :<%= table_prefix %>_password_change_times, id: false do |t|
3
3
  t.<%= primary_key_type(nil) %> :id, primary_key: true
4
4
  t.foreign_key :<%= table_prefix.pluralize %>, column: :id
5
- t.datetime :changed_at, null: false, default: <%= current_timestamp %>
5
+ t.datetime :changed_at, null: false, default: -> { "<%= current_timestamp %>" }
6
6
  end
@@ -4,5 +4,5 @@ create_table :<%= table_prefix %>_password_reset_keys, id: false do |t|
4
4
  t.foreign_key :<%= table_prefix.pluralize %>, column: :id
5
5
  t.string :key, null: false
6
6
  t.datetime :deadline, null: false
7
- t.datetime :email_last_sent, null: false, default: <%= current_timestamp %>
7
+ t.datetime :email_last_sent, null: false, default: -> { "<%= current_timestamp %>" }
8
8
  end
@@ -5,5 +5,5 @@ create_table :<%= table_prefix %>_sms_codes, id: false do |t|
5
5
  t.string :phone_number, null: false
6
6
  t.integer :num_failures
7
7
  t.string :code
8
- t.datetime :code_issued_at, null: false, default: <%= current_timestamp %>
8
+ t.datetime :code_issued_at, null: false, default: -> { "<%= current_timestamp %>" }
9
9
  end
@@ -3,6 +3,6 @@ create_table :<%= table_prefix %>_verification_keys, id: false do |t|
3
3
  t.<%= primary_key_type(nil) %> :id, primary_key: true
4
4
  t.foreign_key :<%= table_prefix.pluralize %>, column: :id
5
5
  t.string :key, null: false
6
- t.datetime :requested_at, null: false, default: <%= current_timestamp %>
7
- t.datetime :email_last_sent, null: false, default: <%= current_timestamp %>
6
+ t.datetime :requested_at, null: false, default: -> { "<%= current_timestamp %>" }
7
+ t.datetime :email_last_sent, null: false, default: -> { "<%= current_timestamp %>" }
8
8
  end
@@ -9,5 +9,5 @@ create_table :<%= table_prefix %>_webauthn_keys, primary_key: [:<%= table_prefix
9
9
  t.string :webauthn_id
10
10
  t.string :public_key, null: false
11
11
  t.integer :sign_count, null: false
12
- t.datetime :last_use, null: false, default: <%= current_timestamp %>
12
+ t.datetime :last_use, null: false, default: -> { "<%= current_timestamp %>" }
13
13
  end
@@ -111,18 +111,6 @@ module Rodauth
111
111
 
112
112
  MIGRATION_DIR = "#{__dir__}/migration/active_record"
113
113
 
114
- def db_migrate_path
115
- return "db/migrate" unless ActiveRecord.version >= Gem::Version.new("5.0")
116
-
117
- super
118
- end
119
-
120
- def migration_version
121
- return unless ActiveRecord.version >= Gem::Version.new("5.0")
122
-
123
- "[#{ActiveRecord::Migration.current_version}]"
124
- end
125
-
126
114
  def activerecord_adapter
127
115
  if ActiveRecord::Base.respond_to?(:connection_db_config)
128
116
  ActiveRecord::Base.connection_db_config.adapter
@@ -150,18 +138,10 @@ module Rodauth
150
138
  end
151
139
  end
152
140
 
153
- def current_timestamp
154
- if ActiveRecord.version >= Gem::Version.new("5.0")
155
- %(-> { "#{current_timestamp_literal}" })
156
- else
157
- %(OpenStruct.new(quoted_id: "#{current_timestamp_literal}"))
158
- end
159
- end
160
-
161
141
  # Active Record 7+ sets default precision to 6 for timestamp columns,
162
142
  # so we need to ensure we match this when setting the default value.
163
- def current_timestamp_literal
164
- if ActiveRecord.version >= Gem::Version.new("7.0") && activerecord_adapter == "mysql2" && ActiveRecord::Base.connection.supports_datetime_with_precision?
143
+ def current_timestamp
144
+ if ActiveRecord.version >= Gem::Version.new("7.0") && ["mysql2", "trilogy"].include?(activerecord_adapter) && ActiveRecord::Base.connection.supports_datetime_with_precision?
165
145
  "CURRENT_TIMESTAMP(6)"
166
146
  else
167
147
  "CURRENT_TIMESTAMP"
@@ -5,14 +5,14 @@ class RodauthMailer < ApplicationMailer
5
5
  @rodauth = rodauth(name, account_id) { @verify_account_key_value = key }
6
6
  @account = @rodauth.rails_account
7
7
 
8
- mail subject: @rodauth.verify_account_email_subject
8
+ mail subject: @rodauth.email_subject_prefix + @rodauth.verify_account_email_subject
9
9
  end
10
10
 
11
11
  def reset_password(name, account_id, key)
12
12
  @rodauth = rodauth(name, account_id) { @reset_password_key_value = key }
13
13
  @account = @rodauth.rails_account
14
14
 
15
- mail subject: @rodauth.reset_password_email_subject
15
+ mail subject: @rodauth.email_subject_prefix + @rodauth.reset_password_email_subject
16
16
  end
17
17
 
18
18
  def verify_login_change(name, account_id, key)
@@ -20,35 +20,35 @@ class RodauthMailer < ApplicationMailer
20
20
  @account = @rodauth.rails_account
21
21
  @new_email = @account.login_change_key.login
22
22
 
23
- mail to: @new_email, subject: @rodauth.verify_login_change_email_subject
23
+ mail to: @new_email, subject: @rodauth.email_subject_prefix + @rodauth.verify_login_change_email_subject
24
24
  end
25
25
 
26
26
  def password_changed(name, account_id)
27
27
  @rodauth = rodauth(name, account_id)
28
28
  @account = @rodauth.rails_account
29
29
 
30
- mail subject: @rodauth.password_changed_email_subject
30
+ mail subject: @rodauth.email_subject_prefix + @rodauth.password_changed_email_subject
31
31
  end
32
32
 
33
33
  # def reset_password_notify(name, account_id)
34
34
  # @rodauth = rodauth(name, account_id)
35
35
  # @account = @rodauth.rails_account
36
36
 
37
- # mail subject: @rodauth.reset_password_notify_email_subject
37
+ # mail subject: @rodauth.email_subject_prefix + @rodauth.reset_password_notify_email_subject
38
38
  # end
39
39
 
40
40
  # def email_auth(name, account_id, key)
41
41
  # @rodauth = rodauth(name, account_id) { @email_auth_key_value = key }
42
42
  # @account = @rodauth.rails_account
43
43
 
44
- # mail subject: @rodauth.email_auth_email_subject
44
+ # mail subject: @rodauth.email_subject_prefix + @rodauth.email_auth_email_subject
45
45
  # end
46
46
 
47
47
  # def unlock_account(name, account_id, key)
48
48
  # @rodauth = rodauth(name, account_id) { @unlock_account_key_value = key }
49
49
  # @account = @rodauth.rails_account
50
50
 
51
- # mail subject: @rodauth.unlock_account_email_subject
51
+ # mail subject: @rodauth.email_subject_prefix + @rodauth.unlock_account_email_subject
52
52
  # end
53
53
 
54
54
  private
@@ -85,7 +85,7 @@ class RodauthMain < Rodauth::Rails::Auth
85
85
  verify_account_set_password? false
86
86
 
87
87
  # Change some default param keys.
88
- # login_param "email"
88
+ login_param "email"
89
89
  # password_confirm_param "confirm_password"
90
90
 
91
91
  # Redirect back to originally requested location after authentication.
@@ -7,7 +7,7 @@
7
7
  <% else %>
8
8
  <div class="form-group mb-3">
9
9
  <%= form.label "login", rodauth.login_label, class: "form-label" %>
10
- <%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", autocomplete: "email", required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.login_param)}", aria: ({ invalid: true, describedby: "login_error_message" } if rodauth.field_error(rodauth.login_param)) %>
10
+ <%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", autocomplete: rodauth.login_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.login_param)}", aria: ({ invalid: true, describedby: "login_error_message" } if rodauth.field_error(rodauth.login_param)) %>
11
11
  <%= content_tag(:span, rodauth.field_error(rodauth.login_param), class: "invalid-feedback", id: "login_error_message") if rodauth.field_error(rodauth.login_param) %>
12
12
  </div>
13
13
  <% end %>
@@ -1,3 +1,3 @@
1
- <%= render "login_form_header" %>
1
+ <%== rodauth.login_form_header %>
2
2
  <%= render "login_form" %>
3
- <%= render "login_form_footer" %>
3
+ <%== rodauth.login_form_footer %>
@@ -1,3 +1,3 @@
1
- <%= render "login_form_header" %>
1
+ <%== rodauth.login_form_header %>
2
2
  <%== rodauth.render_multi_phase_login_forms %>
3
- <%= render "login_form_footer" %>
3
+ <%== rodauth.login_form_footer %>
@@ -7,7 +7,7 @@
7
7
  <% else %>
8
8
  <div class="mb-6">
9
9
  <%= form.label "login", rodauth.login_label, class: "block text-sm font-semibold" %>
10
- <%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", autocomplete: "email", required: true, class: "mt-2 text-sm w-full px-3 py-2 border rounded-md dark:bg-gray-900 dark:text-gray-100 dark:focus:bg-gray-800 #{rodauth.field_error(rodauth.login_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: "login_error_message" } if rodauth.field_error(rodauth.login_param)) %>
10
+ <%= form.email_field rodauth.login_param, value: params[rodauth.login_param], id: "login", autocomplete: rodauth.login_field_autocomplete_value, required: true, class: "mt-2 text-sm w-full px-3 py-2 border rounded-md dark:bg-gray-900 dark:text-gray-100 dark:focus:bg-gray-800 #{rodauth.field_error(rodauth.login_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: "login_error_message" } if rodauth.field_error(rodauth.login_param)) %>
11
11
  <%= content_tag(:span, rodauth.field_error(rodauth.login_param), class: "block mt-1 text-red-600 text-xs dark:text-red-400", id: "login_error_message") if rodauth.field_error(rodauth.login_param) %>
12
12
  </div>
13
13
  <% end %>
@@ -1,5 +1,5 @@
1
1
  <div class="flex-1 space-y-4">
2
- <%= render "login_form_header" %>
2
+ <%== rodauth.login_form_header %>
3
3
  <%= render "login_form" %>
4
- <%= render "login_form_footer" %>
4
+ <%== rodauth.login_form_footer %>
5
5
  </div>
@@ -1,5 +1,5 @@
1
1
  <div class="flex-1 space-y-4">
2
- <%= render "login_form_header" %>
2
+ <%== rodauth.login_form_header %>
3
3
  <%== rodauth.render_multi_phase_login_forms %>
4
- <%= render "login_form_footer" %>
4
+ <%== rodauth.login_form_footer %>
5
5
  </div>
@@ -0,0 +1,10 @@
1
+ <% cred = rodauth.webauthn_credential_options_for_get %>
2
+
3
+ <%= form_with url: rodauth.webauthn_login_path, method: :post, id: "webauthn-login-form", data: { credential_options: cred.as_json.to_json, turbo: false } do |form| %>
4
+ <%= form.hidden_field rodauth.webauthn_auth_challenge_param, value: cred.challenge %>
5
+ <%= form.hidden_field rodauth.webauthn_auth_challenge_hmac_param, value: rodauth.compute_hmac(cred.challenge) %>
6
+ <%= form.text_field rodauth.webauthn_auth_param, value: "", id: "webauthn-auth", class: "hidden", aria: { hidden: "true" } %>
7
+ <%= form.submit rodauth.webauthn_auth_button, class: "hidden" %>
8
+ <% end %>
9
+
10
+ <%= javascript_include_tag rodauth.webauthn_autofill_js_path, extname: false %>
@@ -0,0 +1,10 @@
1
+ <% cred = rodauth.webauthn_credential_options_for_get %>
2
+
3
+ <%= form_with url: rodauth.webauthn_login_path, method: :post, id: "webauthn-login-form", data: { credential_options: cred.as_json.to_json, turbo: false } do |form| %>
4
+ <%= form.hidden_field rodauth.webauthn_auth_challenge_param, value: cred.challenge %>
5
+ <%= form.hidden_field rodauth.webauthn_auth_challenge_hmac_param, value: rodauth.compute_hmac(cred.challenge) %>
6
+ <%= form.text_field rodauth.webauthn_auth_param, value: "", id: "webauthn-auth", class: "d-none", aria: { hidden: "true" } %>
7
+ <%= form.submit rodauth.webauthn_auth_button, class: "d-none" %>
8
+ <% end %>
9
+
10
+ <%= javascript_include_tag rodauth.webauthn_autofill_js_path, extname: false %>
@@ -1,4 +1,4 @@
1
- Someone has requested a that the account with this email be unlocked.
1
+ Someone has requested that the account with this email be unlocked.
2
2
  If you did not request the unlocking of this account, please ignore this
3
3
  message. If you requested the unlocking of this account, please go to
4
4
  <%= @rodauth.unlock_account_email_link %>
@@ -1,5 +1,5 @@
1
1
  <% if defined?(::ActiveRecord::Railtie) -%>
2
- class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
2
+ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
3
3
  def change
4
4
  <%= migration_content -%>
5
5
  end
@@ -23,7 +23,7 @@ module Rodauth
23
23
  default: nil
24
24
 
25
25
  VIEWS = {
26
- login: %w[_login_form _login_form_footer _login_form_header login multi_phase_login],
26
+ login: %w[_login_form _login_form_footer login multi_phase_login],
27
27
  create_account: %w[create_account],
28
28
  logout: %w[logout],
29
29
  reset_password: %w[reset_password_request reset_password],
@@ -40,13 +40,7 @@ module Rodauth
40
40
  sms_codes: %w[sms_setup sms_confirm sms_auth sms_request sms_disable],
41
41
  recovery_codes: %w[recovery_codes add_recovery_codes recovery_auth],
42
42
  webauthn: %w[webauthn_setup webauthn_auth webauthn_remove],
43
- }
44
-
45
- DEPENDENCIES = {
46
- otp: :two_factor_base,
47
- sms_codes: :two_factor_base,
48
- recovery_codes: :two_factor_base,
49
- webauthn: :two_factor_base,
43
+ webauthn_autofill: %w[webauthn_autofill],
50
44
  }
51
45
 
52
46
  def create_views
@@ -65,10 +59,7 @@ module Rodauth
65
59
  private
66
60
 
67
61
  def views
68
- features.inject([]) do |list, feature|
69
- list |= VIEWS.fetch(feature)
70
- list |= VIEWS[DEPENDENCIES[feature]] || []
71
- end
62
+ features.flat_map { |feature| VIEWS.fetch(feature) }
72
63
  end
73
64
 
74
65
  def validate_features
@@ -43,7 +43,7 @@ module Rodauth
43
43
 
44
44
  after do
45
45
  rails_request.commit_flash
46
- end unless ActionPack.version < Gem::Version.new("5.0")
46
+ end
47
47
 
48
48
  def flash
49
49
  rails_request.flash
@@ -92,14 +92,12 @@ module Rodauth
92
92
  super
93
93
  end
94
94
 
95
- unless ActionPack.version < Gem::Version.new("5.0")
96
- # When calling a Rodauth method that redirects inside the Rails
97
- # router, Roda's after hook that commits the flash would never get
98
- # called, so we make sure to commit the flash beforehand.
99
- def redirect(*)
100
- scope.rails_request.commit_flash
101
- super
102
- end
95
+ # When calling a Rodauth method that redirects inside the Rails
96
+ # router, Roda's after hook that commits the flash would never get
97
+ # called, so we make sure to commit the flash beforehand.
98
+ def redirect(*)
99
+ scope.rails_request.commit_flash
100
+ super
103
101
  end
104
102
  end
105
103
  end
@@ -13,16 +13,7 @@ module Rodauth
13
13
  end
14
14
 
15
15
  def rails_account
16
- return unless account || logged_in?
17
-
18
- account_from_session unless account
19
-
20
- unless account
21
- clear_session
22
- return
23
- end
24
-
25
- @rails_account ||= instantiate_rails_account
16
+ @rails_account ||= instantiate_rails_account if account!
26
17
  end
27
18
 
28
19
  # Reset Rails session to protect from session fixation attacks.
@@ -41,7 +32,7 @@ module Rodauth
41
32
  end
42
33
 
43
34
  def rails_controller
44
- if only_json? && Rodauth::Rails.api_only?
35
+ if only_json? && ::Rails.application.config.api_only
45
36
  ActionController::API
46
37
  else
47
38
  ActionController::Base
@@ -70,28 +61,13 @@ module Rodauth
70
61
  end
71
62
  end
72
63
 
73
- # Instances of the configured controller with current request's env hash.
64
+ # Instance of the configured controller with current request's env hash.
74
65
  def _rails_controller_instance
75
66
  controller = rails_controller.new
76
- prepare_rails_controller(controller, rails_request)
67
+ controller.set_request! rails_request
68
+ controller.set_response! rails_controller.make_response!(controller.request)
77
69
  controller
78
70
  end
79
-
80
- if ActionPack.version >= Gem::Version.new("5.0")
81
- def prepare_rails_controller(controller, rails_request)
82
- controller.set_request! rails_request
83
- controller.set_response! rails_controller.make_response!(rails_request)
84
- end
85
- else
86
- def prepare_rails_controller(controller, rails_request)
87
- controller.send(:set_response!, rails_request)
88
- controller.instance_variable_set(:@_request, rails_request)
89
- end
90
- end
91
-
92
- def rails_api_controller?
93
- defined?(ActionController::API) && rails_controller <= ActionController::API
94
- end
95
71
  end
96
72
  end
97
73
  end
@@ -32,7 +32,7 @@ module Rodauth
32
32
 
33
33
  # Calls the Rails renderer, returning nil if a template is missing.
34
34
  def rails_render(*args)
35
- return if rails_api_controller?
35
+ return if rails_controller <= ActionController::API
36
36
 
37
37
  rails_controller_instance.render_to_string(*args)
38
38
  rescue ActionView::MissingTemplate
@@ -23,12 +23,8 @@ module Rodauth
23
23
  # Rodauth uses RACK_ENV to set the default bcrypt hash cost
24
24
  ENV["RACK_ENV"] = "test" if ::Rails.env.test?
25
25
 
26
- if ActionPack.version >= Gem::Version.new("5.0")
27
- ActiveSupport.on_load(:action_controller_test_case) do
28
- include Rodauth::Rails::Test::Controller
29
- end
30
- else
31
- ActionController::TestCase.include Rodauth::Rails::Test::Controller
26
+ ActiveSupport.on_load(:action_controller_test_case) do
27
+ include Rodauth::Rails::Test::Controller
32
28
  end
33
29
  end
34
30
 
@@ -1,5 +1,5 @@
1
1
  module Rodauth
2
2
  module Rails
3
- VERSION = "1.8.0"
3
+ VERSION = "1.9.0"
4
4
  end
5
5
  end
data/lib/rodauth/rails.rb CHANGED
@@ -66,16 +66,6 @@ module Rodauth
66
66
  end
67
67
  end
68
68
 
69
- if ::Rails.gem_version >= Gem::Version.new("5.0")
70
- def api_only?
71
- ::Rails.application.config.api_only
72
- end
73
- else
74
- def api_only?
75
- false
76
- end
77
- end
78
-
79
69
  def configure
80
70
  yield self
81
71
  end
@@ -16,8 +16,8 @@ Gem::Specification.new do |spec|
16
16
  spec.files = Dir["README.md", "LICENSE.txt", "CHANGELOG.md", "lib/**/*", "*.gemspec"]
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency "railties", ">= 4.2", "< 8"
20
- spec.add_dependency "rodauth", "~> 2.28"
19
+ spec.add_dependency "railties", ">= 5.0", "< 8"
20
+ spec.add_dependency "rodauth", "~> 2.30"
21
21
  spec.add_dependency "roda", "~> 3.55"
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.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-25 00:00:00.000000000 Z
11
+ date: 2023-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.2'
19
+ version: '5.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '8'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '4.2'
29
+ version: '5.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '8'
@@ -36,14 +36,14 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '2.28'
39
+ version: '2.30'
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.28'
46
+ version: '2.30'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: roda
49
49
  requirement: !ruby/object:Gem::Requirement
@@ -227,7 +227,6 @@ files:
227
227
  - lib/generators/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb
228
228
  - lib/generators/rodauth/templates/app/views/rodauth/_login_form.html.erb
229
229
  - lib/generators/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb
230
- - lib/generators/rodauth/templates/app/views/rodauth/_login_form_header.html.erb
231
230
  - lib/generators/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb
232
231
  - lib/generators/rodauth/templates/app/views/rodauth/change_login.html.erb
233
232
  - lib/generators/rodauth/templates/app/views/rodauth/change_password.html.erb
@@ -254,7 +253,6 @@ files:
254
253
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/_email_auth_request_form.html.erb
255
254
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/_login_form.html.erb
256
255
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/_login_form_footer.html.erb
257
- - lib/generators/rodauth/templates/app/views/rodauth/tailwind/_login_form_header.html.erb
258
256
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/add_recovery_codes.html.erb
259
257
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/change_login.html.erb
260
258
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/change_password.html.erb
@@ -287,6 +285,7 @@ files:
287
285
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/verify_account_resend.html.erb
288
286
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/verify_login_change.html.erb
289
287
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/webauthn_auth.html.erb
288
+ - lib/generators/rodauth/templates/app/views/rodauth/tailwind/webauthn_autofill.html.erb
290
289
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/webauthn_remove.html.erb
291
290
  - lib/generators/rodauth/templates/app/views/rodauth/tailwind/webauthn_setup.html.erb
292
291
  - lib/generators/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb
@@ -298,6 +297,7 @@ files:
298
297
  - lib/generators/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb
299
298
  - lib/generators/rodauth/templates/app/views/rodauth/verify_login_change.html.erb
300
299
  - lib/generators/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb
300
+ - lib/generators/rodauth/templates/app/views/rodauth/webauthn_autofill.html.erb
301
301
  - lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb
302
302
  - lib/generators/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb
303
303
  - lib/generators/rodauth/templates/app/views/rodauth_mailer/email_auth.text.erb
@@ -351,7 +351,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
351
351
  - !ruby/object:Gem::Version
352
352
  version: '0'
353
353
  requirements: []
354
- rubygems_version: 3.4.6
354
+ rubygems_version: 3.4.12
355
355
  signing_key:
356
356
  specification_version: 4
357
357
  summary: Provides Rails integration for Rodauth.
@@ -1,3 +0,0 @@
1
- <% if rodauth.field_error(rodauth.password_param) && rodauth.features.include?(:reset_password) %>
2
- <%= render template: "rodauth/reset_password_request", layout: false %>
3
- <% end %>
@@ -1,3 +0,0 @@
1
- <% if rodauth.field_error(rodauth.password_param) && rodauth.features.include?(:reset_password) %>
2
- <%= render template: "rodauth/reset_password_request", layout: false %>
3
- <% end %>