rodauth-rails 0.16.0 → 0.18.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -0
  3. data/README.md +97 -36
  4. data/lib/generators/rodauth/install_generator.rb +11 -3
  5. data/lib/generators/rodauth/migration/base.erb +8 -2
  6. data/lib/generators/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +7 -4
  7. data/lib/generators/rodauth/templates/app/views/rodauth/_login_form.html.erb +26 -9
  8. data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +7 -6
  9. data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_header.html.erb +3 -3
  10. data/lib/generators/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +7 -5
  11. data/lib/generators/rodauth/templates/app/views/rodauth/change_login.html.erb +29 -6
  12. data/lib/generators/rodauth/templates/app/views/rodauth/change_password.html.erb +29 -6
  13. data/lib/generators/rodauth/templates/app/views/rodauth/close_account.html.erb +15 -4
  14. data/lib/generators/rodauth/templates/app/views/rodauth/confirm_password.html.erb +13 -4
  15. data/lib/generators/rodauth/templates/app/views/rodauth/create_account.html.erb +37 -7
  16. data/lib/generators/rodauth/templates/app/views/rodauth/email_auth.html.erb +7 -3
  17. data/lib/generators/rodauth/templates/app/views/rodauth/login.html.erb +5 -3
  18. data/lib/generators/rodauth/templates/app/views/rodauth/logout.html.erb +16 -4
  19. data/lib/generators/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +5 -3
  20. data/lib/generators/rodauth/templates/app/views/rodauth/otp_auth.html.erb +17 -4
  21. data/lib/generators/rodauth/templates/app/views/rodauth/otp_disable.html.erb +15 -4
  22. data/lib/generators/rodauth/templates/app/views/rodauth/otp_setup.html.erb +30 -10
  23. data/lib/generators/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +13 -4
  24. data/lib/generators/rodauth/templates/app/views/rodauth/recovery_codes.html.erb +15 -1
  25. data/lib/generators/rodauth/templates/app/views/rodauth/remember.html.erb +14 -9
  26. data/lib/generators/rodauth/templates/app/views/rodauth/reset_password.html.erb +21 -5
  27. data/lib/generators/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +19 -9
  28. data/lib/generators/rodauth/templates/app/views/rodauth/sms_auth.html.erb +17 -4
  29. data/lib/generators/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +17 -4
  30. data/lib/generators/rodauth/templates/app/views/rodauth/sms_disable.html.erb +15 -4
  31. data/lib/generators/rodauth/templates/app/views/rodauth/sms_request.html.erb +7 -3
  32. data/lib/generators/rodauth/templates/app/views/rodauth/sms_setup.html.erb +25 -5
  33. data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +5 -3
  34. data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +15 -4
  35. data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +17 -15
  36. data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account.html.erb +17 -5
  37. data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +11 -5
  38. data/lib/generators/rodauth/templates/app/views/rodauth/verify_account.html.erb +23 -5
  39. data/lib/generators/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +19 -9
  40. data/lib/generators/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +7 -3
  41. data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +13 -9
  42. data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +21 -9
  43. data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +21 -9
  44. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/email_auth.text.erb +1 -1
  45. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/reset_password.text.erb +1 -1
  46. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/unlock_account.text.erb +1 -1
  47. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/verify_account.text.erb +1 -1
  48. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/verify_login_change.text.erb +3 -3
  49. data/lib/generators/rodauth/views_generator.rb +55 -93
  50. data/lib/rodauth/rails/app.rb +4 -0
  51. data/lib/rodauth/rails/controller_methods.rb +1 -2
  52. data/lib/rodauth/rails/feature/base.rb +9 -0
  53. data/lib/rodauth/rails/feature/csrf.rb +15 -4
  54. data/lib/rodauth/rails/feature/internal_request.rb +16 -20
  55. data/lib/rodauth/rails/feature/render.rb +1 -1
  56. data/lib/rodauth/rails/model.rb +1 -1
  57. data/lib/rodauth/rails/railtie.rb +4 -2
  58. data/lib/rodauth/rails/version.rb +1 -1
  59. data/lib/rodauth/rails.rb +14 -7
  60. data/rodauth-rails.gemspec +1 -1
  61. metadata +4 -20
  62. data/lib/generators/rodauth/templates/app/views/rodauth/_field.html.erb +0 -10
  63. data/lib/generators/rodauth/templates/app/views/rodauth/_field_error.html.erb +0 -3
  64. data/lib/generators/rodauth/templates/app/views/rodauth/_global_logout_field.html.erb +0 -6
  65. data/lib/generators/rodauth/templates/app/views/rodauth/_login_confirm_field.html.erb +0 -4
  66. data/lib/generators/rodauth/templates/app/views/rodauth/_login_display.html.erb +0 -4
  67. data/lib/generators/rodauth/templates/app/views/rodauth/_login_field.html.erb +0 -4
  68. data/lib/generators/rodauth/templates/app/views/rodauth/_login_hidden_field.html.erb +0 -1
  69. data/lib/generators/rodauth/templates/app/views/rodauth/_new_password_field.html.erb +0 -4
  70. data/lib/generators/rodauth/templates/app/views/rodauth/_otp_auth_code_field.html.erb +0 -8
  71. data/lib/generators/rodauth/templates/app/views/rodauth/_password_confirm_field.html.erb +0 -4
  72. data/lib/generators/rodauth/templates/app/views/rodauth/_password_field.html.erb +0 -4
  73. data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_code_field.html.erb +0 -4
  74. data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_codes_form.html.erb +0 -6
  75. data/lib/generators/rodauth/templates/app/views/rodauth/_sms_code_field.html.erb +0 -8
  76. data/lib/generators/rodauth/templates/app/views/rodauth/_sms_phone_field.html.erb +0 -8
  77. data/lib/generators/rodauth/templates/app/views/rodauth/_submit.html.erb +0 -3
@@ -1,13 +1,25 @@
1
- <%%= form_tag <%= rodauth %>.webauthn_remove_path, method: :post, id: "webauthn-remove-form" do %>
2
- <%%= render "password_field" if <%= rodauth %>.two_factor_modifications_require_password? %>
1
+ <% content_for :title, rodauth.webauthn_remove_page_title %>
2
+
3
+ <%= form_with url: rodauth.webauthn_remove_path, method: :post, id: "webauthn-remove-form" do |form| %>
4
+ <% if rodauth.two_factor_modifications_require_password? %>
5
+ <div class="form-group mb-3">
6
+ <%= form.label "password", rodauth.password_label, class: "form-label" %>
7
+ <%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.password_param)}", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
8
+ <%= content_tag(:span, rodauth.field_error(rodauth.password_param), class: "invalid-feedback", id: "password_error_message") if rodauth.field_error(rodauth.password_param) %>
9
+ </div>
10
+ <% end %>
11
+
3
12
  <fieldset class="form-group mb-3">
4
- <%% (usage = <%= rodauth %>.account_webauthn_usage).each do |id, last_use| %>
13
+ <% (usage = rodauth.account_webauthn_usage).each do |id, last_use| %>
5
14
  <div class="form-check">
6
- <%%= render "field", name: <%= rodauth %>.webauthn_remove_param, id: "webauthn-remove-#{id}", type: :radio, class: "form-check-input", skip_error_message: true, value: id, required: false %>
7
- <%%= label_tag "webauthn-remove-#{id}", "Last use: #{last_use}", class: "form-check-label" %>
8
- <%%= render "field_error", name: <%= rodauth %>.webauthn_remove_param if id == usage.keys.last %>
15
+ <%= 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)) %>
16
+ <%= form.label "webauthn-remove-#{id}", "Last use: #{last_use}", class: "form-check-label" %>
17
+ <%= 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 %>
9
18
  </div>
10
- <%% end %>
19
+ <% end %>
11
20
  </fieldset>
12
- <%%= render "submit", value: "Remove WebAuthn Authenticator" %>
13
- <%% end %>
21
+
22
+ <div class="form-group mb-3">
23
+ <%= form.submit rodauth.webauthn_remove_button, class: "btn btn-primary" %>
24
+ </div>
25
+ <% end %>
@@ -1,13 +1,25 @@
1
- <%% cred = <%= rodauth %>.new_webauthn_credential %>
1
+ <% content_for :title, rodauth.webauthn_setup_page_title %>
2
+
3
+ <% cred = rodauth.new_webauthn_credential %>
4
+
5
+ <%= form_with url: rodauth.webauthn_setup_path, method: :post, id: "webauthn-setup-form", data: { credential_options: cred.as_json.to_json } do |form| %>
6
+ <%= form.hidden_field rodauth.webauthn_setup_challenge_param, value: cred.challenge %>
7
+ <%= form.hidden_field rodauth.webauthn_setup_challenge_hmac_param, value: rodauth.compute_hmac(cred.challenge) %>
8
+ <%= form.text_field rodauth.webauthn_setup_param, value: "", id: "webauthn-setup", aria: { hidden: "true" } %>
9
+
10
+ <% if rodauth.two_factor_modifications_require_password? %>
11
+ <div class="form-group mb-3">
12
+ <%= form.label "password", rodauth.password_label, class: "form-label" %>
13
+ <%= form.password_field rodauth.password_param, value: "", id: "password", autocomplete: rodauth.password_field_autocomplete_value, required: true, class: "form-control #{"is-invalid" if rodauth.field_error(rodauth.password_param)}", aria: ({ invalid: true, describedby: "password_error_message" } if rodauth.field_error(rodauth.password_param)) %>
14
+ <%= content_tag(:span, rodauth.field_error(rodauth.password_param), class: "invalid-feedback", id: "password_error_message") if rodauth.field_error(rodauth.password_param) %>
15
+ </div>
16
+ <% end %>
2
17
 
3
- <%%= form_tag <%= rodauth %>.webauthn_setup_path, method: :post, id: "webauthn-setup-form", data: { credential_options: cred.as_json.to_json } do %>
4
- <%%= hidden_field_tag <%= rodauth %>.webauthn_setup_challenge_param, cred.challenge %>
5
- <%%= hidden_field_tag <%= rodauth %>.webauthn_setup_challenge_hmac_param, <%= rodauth %>.compute_hmac(cred.challenge) %>
6
- <%%= text_field_tag <%= rodauth %>.webauthn_setup_param, "", id: "webauthn-setup", aria: { hidden: "true" } %>
7
- <%%= render "password_field" if <%= rodauth %>.two_factor_modifications_require_password? %>
8
18
  <div id="webauthn-setup-button">
9
- <%%= render "submit", value: "Setup WebAuthn Authentication" %>
19
+ <div class="form-group mb-3">
20
+ <%= form.submit rodauth.webauthn_setup_button, class: "btn btn-primary" %>
21
+ </div>
10
22
  </div>
11
- <%% end %>
23
+ <% end %>
12
24
 
13
- <%%= javascript_include_tag <%= rodauth %>.webauthn_setup_js_path %>
25
+ <%= javascript_include_tag rodauth.webauthn_setup_js_path %>
@@ -1,5 +1,5 @@
1
1
  Someone has requested a login link for the account with this email
2
2
  address. If you did not request a login link, please ignore this
3
3
  message. If you requested a login link, please go to
4
- <%%= @email_link %>
4
+ <%= @email_link %>
5
5
  to login to this account.
@@ -1,5 +1,5 @@
1
1
  Someone has requested a password reset for the account with this email
2
2
  address. If you did not request a password reset, please ignore this
3
3
  message. If you requested a password reset, please go to
4
- <%%= @email_link %>
4
+ <%= @email_link %>
5
5
  to reset the password for the account.
@@ -1,5 +1,5 @@
1
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
- <%%= @email_link %>
4
+ <%= @email_link %>
5
5
  to unlock this account.
@@ -1,4 +1,4 @@
1
1
  Someone has created an account with this email address. If you did not create
2
2
  this account, please ignore this message. If you created this account, please go to
3
- <%%= @email_link %>
3
+ <%= @email_link %>
4
4
  to verify the account.
@@ -1,10 +1,10 @@
1
1
  Someone with an account has requested their login be changed to this email address:
2
2
 
3
- Old email: <%%= @old_login %>
3
+ Old email: <%= @old_login %>
4
4
 
5
- New email: <%%= @new_login %>
5
+ New email: <%= @new_login %>
6
6
 
7
7
  If you did not request this login change, please ignore this message. If you
8
8
  requested this login change, please go to
9
- <%%= @email_link %>
9
+ <%= @email_link %>
10
10
  to verify the login change.
@@ -7,12 +7,8 @@ module Rodauth
7
7
  source_root "#{__dir__}/templates"
8
8
  namespace "rodauth:views"
9
9
 
10
- argument :features, optional: true, type: :array,
11
- desc: "Rodauth features to generate views for (login, create_account, reset_password, verify_account etc.)",
12
- default: %w[login logout create_account verify_account reset_password change_password change_login verify_login_change close_account]
13
-
14
- class_option :features, type: :array,
15
- desc: "[DEPRECATED] Rodauth features to generate views for (login, create_account, reset_password, verify_account etc.)"
10
+ argument :selected_features, optional: true, type: :array,
11
+ desc: "Rodauth features to generate views for (login, create_account, reset_password, verify_account etc.)"
16
12
 
17
13
  class_option :all, aliases: "-a", type: :boolean,
18
14
  desc: "Generates views for all Rodauth features",
@@ -23,99 +19,57 @@ module Rodauth
23
19
  default: nil
24
20
 
25
21
  VIEWS = {
26
- login: %w[
27
- _field _field_error _login_field _login_display _password_field
28
- _submit _login_form _login_form_footer _login_form_header login
29
- multi_phase_login
30
- ],
31
- create_account: %w[
32
- _field _field_error _login_field _login_confirm_field
33
- _password_field _password_confirm_field _submit create_account
34
- ],
35
- logout: %w[
36
- _submit logout
37
- ],
38
- reset_password: %w[
39
- _field _field_error _login_field _login_hidden_field
40
- _password_field _password_confirm_field _submit
41
- reset_password_request reset_password
42
- ],
43
- remember: %w[
44
- _submit remember
45
- ],
46
- change_login: %w[
47
- _field _field_error _login_field _login_confirm_field
48
- _password_field _submit change_login
49
- ],
50
- change_password: %w[
51
- _field _field_error _password_field _new_password_field
52
- _password_confirm_field _submit change_password
53
- ],
54
- close_account: %w[
55
- _field _field_error _password_field _submit close_account
56
- ],
57
- email_auth: %w[
58
- _login_hidden_field _submit _email_auth_request_form email_auth
59
- ],
60
- verify_account: %w[
61
- _field _field_error _login_hidden_field _login_field _submit
62
- verify_account_resend verify_account
63
- ],
64
- verify_login_change: %w[
65
- _submit verify_login_change
66
- ],
67
- lockout: %w[
68
- _login_hidden_field _submit unlock_account_request unlock_account
69
- ],
70
- active_sessions: %w[
71
- _global_logout_field
72
- ],
73
- two_factor_base: %w[
74
- _field _field_error _password_field _submit
75
- two_factor_manage two_factor_auth two_factor_disable
76
- ],
77
- otp: %w[
78
- _field _field_error _otp_auth_code_field _password_field _submit
79
- otp_setup otp_auth otp_disable
80
- ],
81
- sms_codes: %w[
82
- _field _field_error _sms_code_field _sms_phone_field
83
- _password_field _submit
84
- sms_setup sms_confirm sms_auth sms_request sms_disable
85
- ],
86
- recovery_codes: %w[
87
- _field _field_error _recovery_code_field _recovery_codes_form
88
- recovery_codes add_recovery_codes recovery_auth
89
- ],
90
- webauthn: %w[
91
- _field _field_error _login_hidden_field _password_field _submit
92
- webauthn_setup webauthn_auth webauthn_remove
93
- ]
22
+ login: %w[_login_form _login_form_footer _login_form_header login multi_phase_login],
23
+ create_account: %w[create_account],
24
+ logout: %w[logout],
25
+ reset_password: %w[reset_password_request reset_password],
26
+ remember: %w[remember],
27
+ change_login: %w[change_login],
28
+ change_password: %w[change_password],
29
+ close_account: %w[close_account],
30
+ email_auth: %w[_email_auth_request_form email_auth],
31
+ verify_account: %w[verify_account_resend verify_account],
32
+ verify_login_change: %w[verify_login_change],
33
+ lockout: %w[unlock_account_request unlock_account],
34
+ two_factor_base: %w[two_factor_manage two_factor_auth two_factor_disable],
35
+ otp: %w[otp_setup otp_auth otp_disable],
36
+ sms_codes: %w[sms_setup sms_confirm sms_auth sms_request sms_disable],
37
+ recovery_codes: %w[recovery_codes add_recovery_codes recovery_auth],
38
+ webauthn: %w[webauthn_setup webauthn_auth webauthn_remove],
94
39
  }
95
40
 
96
41
  DEPENDENCIES = {
97
- active_sessions: :logout,
98
- otp: :two_factor_base,
99
- sms_codes: :two_factor_base,
100
- recovery_codes: :two_factor_base,
101
- webauthn: :two_factor_base,
42
+ otp: :two_factor_base,
43
+ sms_codes: :two_factor_base,
44
+ recovery_codes: :two_factor_base,
45
+ webauthn: :two_factor_base,
102
46
  }
103
47
 
104
48
  def create_views
105
- if options[:all]
106
- features = VIEWS.keys
107
- else
108
- features = (options[:features] || self.features).map(&:to_sym)
109
- end
110
-
111
49
  views = features.inject([]) do |list, feature|
112
50
  list |= VIEWS[feature] || []
113
51
  list |= VIEWS[DEPENDENCIES[feature]] || []
114
52
  end
115
53
 
116
54
  views.each do |view|
117
- template "app/views/rodauth/#{view}.html.erb",
118
- "app/views/#{directory}/#{view}.html.erb"
55
+ copy_file "app/views/rodauth/#{view}.html.erb", "app/views/#{directory}/#{view}.html.erb" do |content|
56
+ content = content.gsub("rodauth.", "rodauth(:#{configuration_name}).") if configuration_name
57
+ content = content.gsub("rodauth/", "#{directory}/")
58
+ content = form_helpers_compatibility(content) if ActionView.version < Gem::Version.new("5.1")
59
+ content
60
+ end
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def features
67
+ if options[:all]
68
+ VIEWS.keys
69
+ elsif selected_features
70
+ selected_features.map(&:to_sym)
71
+ else
72
+ rodauth_configuration.features
119
73
  end
120
74
  end
121
75
 
@@ -127,19 +81,27 @@ module Rodauth
127
81
  controller.controller_path
128
82
  end
129
83
 
130
- def rodauth
131
- "rodauth#{"(:#{configuration_name})" if configuration_name}"
84
+ def controller
85
+ rodauth_configuration.allocate.rails_controller
132
86
  end
133
87
 
134
- def controller
135
- rodauth = Rodauth::Rails.app.rodauth(configuration_name)
136
- fail ArgumentError, "unknown rodauth configuration: #{configuration_name.inspect}" unless rodauth
137
- rodauth.allocate.rails_controller
88
+ def rodauth_configuration
89
+ Rodauth::Rails.app.rodauth!(configuration_name)
138
90
  end
139
91
 
140
92
  def configuration_name
141
93
  options[:name]&.to_sym
142
94
  end
95
+
96
+ # We need to use the *_tag helpers on versions lower than Rails 5.1.
97
+ def form_helpers_compatibility(content)
98
+ content
99
+ .gsub(/form_with url: (.+) do \|form\|/, 'form_tag \1 do')
100
+ .gsub(/form\.(label|submit)/, '\1_tag')
101
+ .gsub(/form\.(email|password|text|telephone|hidden)_field (\S+), value:/, '\1_field_tag \2,')
102
+ .gsub(/form\.radio_button (\S+), (\S+),/, 'radio_button_tag \1, \2, false,')
103
+ .gsub(/form\.check_box (\S+), (.+) /, 'check_box_tag \1, "t", false, \2 ')
104
+ end
143
105
  end
144
106
  end
145
107
  end
@@ -43,6 +43,10 @@ module Rodauth
43
43
  def rails_request
44
44
  ActionDispatch::Request.new(env)
45
45
  end
46
+
47
+ def self.rodauth!(name)
48
+ rodauth(name) or fail ArgumentError, "unknown rodauth configuration: #{name.inspect}"
49
+ end
46
50
  end
47
51
  end
48
52
  end
@@ -13,8 +13,7 @@ module Rodauth
13
13
  end
14
14
 
15
15
  def current_account(name = nil)
16
- table = rodauth(name).accounts_table
17
- model = table.to_s.classify.constantize
16
+ model = rodauth(name).rails_account_model
18
17
  id = rodauth(name).session_value
19
18
 
20
19
  @current_account ||= {}
@@ -4,6 +4,7 @@ module Rodauth
4
4
  module Base
5
5
  def self.included(feature)
6
6
  feature.auth_methods :rails_controller
7
+ feature.auth_value_methods :rails_account_model
7
8
  feature.auth_cached_method :rails_controller_instance
8
9
  end
9
10
 
@@ -30,6 +31,14 @@ module Rodauth
30
31
  end
31
32
  end
32
33
 
34
+ def rails_account_model
35
+ table = accounts_table
36
+ table = table.column if table.is_a?(Sequel::SQL::QualifiedIdentifier) # schema is specified
37
+ table.to_s.classify.constantize
38
+ rescue NameError
39
+ raise Error, "cannot infer account model, please set `rails_account_model` in your rodauth configuration"
40
+ end
41
+
33
42
  delegate :rails_routes, :rails_request, to: :scope
34
43
 
35
44
  private
@@ -13,23 +13,23 @@ module Rodauth
13
13
 
14
14
  # Render Rails CSRF tags in Rodauth templates.
15
15
  def csrf_tag(*)
16
- rails_csrf_tag
16
+ rails_csrf_tag if rails_controller_csrf?
17
17
  end
18
18
 
19
19
  # Verify Rails' authenticity token.
20
20
  def check_csrf
21
- rails_check_csrf!
21
+ rails_check_csrf! if rails_controller_csrf?
22
22
  end
23
23
 
24
24
  # Have Rodauth call #check_csrf automatically.
25
25
  def check_csrf?
26
- true
26
+ rails_check_csrf? if rails_controller_csrf?
27
27
  end
28
28
 
29
29
  private
30
30
 
31
31
  def rails_controller_callbacks
32
- return super if rails_api_controller?
32
+ return super unless rails_controller_csrf?
33
33
 
34
34
  # don't verify CSRF token as part of callbacks, Rodauth will do that
35
35
  rails_controller_instance.allow_forgery_protection = false
@@ -40,6 +40,12 @@ module Rodauth
40
40
  end
41
41
  end
42
42
 
43
+ # Checks whether ActionController::RequestForgeryProtection is included
44
+ # and that protect_from_forgery was called.
45
+ def rails_check_csrf?
46
+ !!rails_controller_instance.forgery_protection_strategy
47
+ end
48
+
43
49
  # Calls the controller to verify the authenticity token.
44
50
  def rails_check_csrf!
45
51
  rails_controller_instance.send(:verify_authenticity_token)
@@ -59,6 +65,11 @@ module Rodauth
59
65
  def rails_csrf_token
60
66
  rails_controller_instance.send(:form_authenticity_token)
61
67
  end
68
+
69
+ # Checks whether ActionController::RequestForgeryProtection is included.
70
+ def rails_controller_csrf?
71
+ rails_controller.respond_to?(:protect_from_forgery)
72
+ end
62
73
  end
63
74
  end
64
75
  end
@@ -2,30 +2,20 @@ module Rodauth
2
2
  module Rails
3
3
  module Feature
4
4
  module InternalRequest
5
- def post_configure
6
- super
7
- return unless internal_request?
8
-
9
- self.class.define_singleton_method(:internal_request) do |route, opts = {}, &blk|
10
- url_options = ::Rails.application.config.action_mailer.default_url_options || {}
5
+ def domain
6
+ return super unless missing_host?
11
7
 
12
- scheme = url_options[:protocol]
13
- port = url_options[:port]
14
- port||= Rack::Request::DEFAULT_PORTS[scheme] if Rack.release < "2"
15
- host = url_options[:host]
16
- host_with_port = host && port ? "#{host}:#{port}" : host
8
+ Rodauth::Rails.url_options[:host]
9
+ end
17
10
 
18
- env = {
19
- "HTTP_HOST" => host_with_port,
20
- "rack.url_scheme" => scheme,
21
- "SERVER_NAME" => host,
22
- "SERVER_PORT" => port,
23
- }.compact
11
+ def base_url
12
+ return super unless missing_host? && domain
24
13
 
25
- opts = opts.merge(env: env) { |k, v1, v2| v2.merge(v1) }
14
+ url_options = Rodauth::Rails.url_options
26
15
 
27
- super(route, opts, &blk)
28
- end
16
+ url = "#{url_options[:protocol]}://#{domain}"
17
+ url << ":#{url_options[:port]}" if url_options[:port]
18
+ url
29
19
  end
30
20
 
31
21
  private
@@ -44,6 +34,12 @@ module Rodauth
44
34
  return yield if internal_request?
45
35
  super
46
36
  end
37
+
38
+ # Checks whether we're in an internal request and host was not set,
39
+ # or the request doesn't exist such as with path_class_methods feature.
40
+ def missing_host?
41
+ internal_request? && request.host == INVALID_DOMAIN || scope.nil?
42
+ end
47
43
  end
48
44
  end
49
45
  end
@@ -10,7 +10,7 @@ module Rodauth
10
10
  # template, otherwise falls back to Rodauth's template.
11
11
  def view(page, *)
12
12
  rails_render(action: page.tr("-", "_"), layout: true) ||
13
- rails_render(html: super.html_safe, layout: true)
13
+ rails_render(html: super.html_safe, layout: true, formats: :html)
14
14
  end
15
15
 
16
16
  # Renders templates without layout. First tries to render a user-defined
@@ -77,7 +77,7 @@ module Rodauth
77
77
  model.public_send type, name, scope,
78
78
  class_name: associated_model.name,
79
79
  foreign_key: foreign_key,
80
- dependent: :destroy,
80
+ dependent: type == :has_many ? :delete_all : :delete,
81
81
  inverse_of: :account,
82
82
  **options,
83
83
  **association_options(name)
@@ -6,8 +6,10 @@ require "rails"
6
6
  module Rodauth
7
7
  module Rails
8
8
  class Railtie < ::Rails::Railtie
9
- initializer "rodauth.middleware" do |app|
10
- app.middleware.use Rodauth::Rails::Middleware if Rodauth::Rails.middleware?
9
+ initializer "rodauth.middleware", after: :load_config_initializers do |app|
10
+ if Rodauth::Rails.middleware?
11
+ app.middleware.use Rodauth::Rails::Middleware
12
+ end
11
13
  end
12
14
 
13
15
  initializer "rodauth.controller" do
@@ -1,5 +1,5 @@
1
1
  module Rodauth
2
2
  module Rails
3
- VERSION = "0.16.0"
3
+ VERSION = "0.18.1"
4
4
  end
5
5
  end
data/lib/rodauth/rails.rb CHANGED
@@ -18,11 +18,7 @@ module Rodauth
18
18
 
19
19
  class << self
20
20
  def rodauth(name = nil, query: nil, form: nil, account: nil, **options)
21
- auth_class = app.rodauth(name)
22
-
23
- unless auth_class
24
- fail ArgumentError, "undefined rodauth configuration: #{name.inspect}"
25
- end
21
+ auth_class = app.rodauth!(name)
26
22
 
27
23
  LOCK.synchronize do
28
24
  unless auth_class.features.include?(:internal_request)
@@ -41,13 +37,18 @@ module Rodauth
41
37
  end
42
38
 
43
39
  auth_class.internal_request_eval(options) do
44
- @account = account.attributes.symbolize_keys if account
40
+ if defined?(ActiveRecord::Base) && account.is_a?(ActiveRecord::Base)
41
+ @account = account.attributes.symbolize_keys
42
+ elsif defined?(Sequel::Model) && account.is_a?(Sequel::Model)
43
+ @account = account.values
44
+ end
45
+
45
46
  self
46
47
  end
47
48
  end
48
49
 
49
50
  def model(name = nil, **options)
50
- Rodauth::Rails::Model.new(app.rodauth(name), **options)
51
+ Rodauth::Rails::Model.new(app.rodauth!(name), **options)
51
52
  end
52
53
 
53
54
  # routing constraint that requires authentication
@@ -79,6 +80,12 @@ module Rodauth
79
80
  end
80
81
  end
81
82
 
83
+ def url_options
84
+ options = ::Rails.application.config.action_mailer.default_url_options || {}
85
+ options[:protocol] ||= "http"
86
+ options
87
+ end
88
+
82
89
  def configure
83
90
  yield self
84
91
  end
@@ -16,7 +16,7 @@ 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", "< 7"
19
+ spec.add_dependency "railties", ">= 4.2", "< 8"
20
20
  spec.add_dependency "rodauth", "~> 2.15"
21
21
  spec.add_dependency "sequel-activerecord_connection", "~> 1.1"
22
22
  spec.add_dependency "tilt"
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: 0.16.0
4
+ version: 0.18.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: 2021-09-26 00:00:00.000000000 Z
11
+ date: 2021-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '4.2'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '7'
22
+ version: '8'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '4.2'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '7'
32
+ version: '8'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: rodauth
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -178,25 +178,9 @@ files:
178
178
  - lib/generators/rodauth/templates/app/mailers/rodauth_mailer.rb
179
179
  - lib/generators/rodauth/templates/app/models/account.rb
180
180
  - lib/generators/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb
181
- - lib/generators/rodauth/templates/app/views/rodauth/_field.html.erb
182
- - lib/generators/rodauth/templates/app/views/rodauth/_field_error.html.erb
183
- - lib/generators/rodauth/templates/app/views/rodauth/_global_logout_field.html.erb
184
- - lib/generators/rodauth/templates/app/views/rodauth/_login_confirm_field.html.erb
185
- - lib/generators/rodauth/templates/app/views/rodauth/_login_display.html.erb
186
- - lib/generators/rodauth/templates/app/views/rodauth/_login_field.html.erb
187
181
  - lib/generators/rodauth/templates/app/views/rodauth/_login_form.html.erb
188
182
  - lib/generators/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb
189
183
  - lib/generators/rodauth/templates/app/views/rodauth/_login_form_header.html.erb
190
- - lib/generators/rodauth/templates/app/views/rodauth/_login_hidden_field.html.erb
191
- - lib/generators/rodauth/templates/app/views/rodauth/_new_password_field.html.erb
192
- - lib/generators/rodauth/templates/app/views/rodauth/_otp_auth_code_field.html.erb
193
- - lib/generators/rodauth/templates/app/views/rodauth/_password_confirm_field.html.erb
194
- - lib/generators/rodauth/templates/app/views/rodauth/_password_field.html.erb
195
- - lib/generators/rodauth/templates/app/views/rodauth/_recovery_code_field.html.erb
196
- - lib/generators/rodauth/templates/app/views/rodauth/_recovery_codes_form.html.erb
197
- - lib/generators/rodauth/templates/app/views/rodauth/_sms_code_field.html.erb
198
- - lib/generators/rodauth/templates/app/views/rodauth/_sms_phone_field.html.erb
199
- - lib/generators/rodauth/templates/app/views/rodauth/_submit.html.erb
200
184
  - lib/generators/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb
201
185
  - lib/generators/rodauth/templates/app/views/rodauth/change_login.html.erb
202
186
  - lib/generators/rodauth/templates/app/views/rodauth/change_password.html.erb
@@ -1,10 +0,0 @@
1
- <%%= text_field_tag name, local_assigns[:value] || params[name],
2
- type: local_assigns[:type] || "text",
3
- id: local_assigns[:id],
4
- autocomplete: local_assigns[:autocomplete],
5
- inputmode: local_assigns[:inputmode],
6
- required: local_assigns[:required] != false,
7
- class: "#{local_assigns[:class] || "form-control"} #{"is-invalid" if <%= rodauth %>.field_error(name)}",
8
- aria: ({ invalid: "true", describedby: "#{name}_error_message" } if <%= rodauth %>.field_error(name)) %>
9
-
10
- <%%= render "field_error", name: name unless local_assigns[:skip_error_message] %>
@@ -1,3 +0,0 @@
1
- <%% if <%= rodauth %>.field_error(name) %>
2
- <div class="invalid-feedback" id="<%%= name %>_error_message"><%%= <%= rodauth %>.field_error(name) %></div>
3
- <%% end %>
@@ -1,6 +0,0 @@
1
- <div class="form-group mb-3">
2
- <div class="form-check">
3
- <%%= check_box_tag <%= rodauth %>.global_logout_param, "t", false, id: "global-logout", class: "form-check-input" %>
4
- <%%= label_tag "global-logout", "Logout all Logged In Sessons?", class: "form-check-label" %>
5
- </div>
6
- </div>