rodauth-rails 0.15.0 → 0.18.0

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 +62 -0
  3. data/README.md +114 -53
  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 -90
  50. data/lib/rodauth/rails/app.rb +4 -0
  51. data/lib/rodauth/rails/auth.rb +2 -2
  52. data/lib/rodauth/rails/controller_methods.rb +42 -1
  53. data/lib/rodauth/rails/feature/base.rb +9 -0
  54. data/lib/rodauth/rails/feature/csrf.rb +15 -4
  55. data/lib/rodauth/rails/feature/internal_request.rb +16 -20
  56. data/lib/rodauth/rails/feature/render.rb +1 -1
  57. data/lib/rodauth/rails/model.rb +1 -1
  58. data/lib/rodauth/rails/railtie.rb +4 -2
  59. data/lib/rodauth/rails/version.rb +1 -1
  60. data/lib/rodauth/rails.rb +15 -10
  61. metadata +2 -18
  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,9 +1,19 @@
1
- <%%= form_tag <%= rodauth %>.verify_account_resend_path, method: :post do %>
2
- <p>If you no longer have the email to verify the account, you can request that it be resent to you:</p>
3
- <%% if params[<%= rodauth %>.login_param] %>
4
- <%%= render "login_hidden_field" %>
5
- <%% else %>
6
- <%%= render "login_field" %>
7
- <%% end %>
8
- <%%= render "submit", value: "Send Verification Login Again" %>
9
- <%% end %>
1
+ <% content_for :title, rodauth.resend_verify_account_page_title %>
2
+
3
+ <%= form_with url: rodauth.verify_account_resend_path, method: :post do |form| %>
4
+ <%== rodauth.verify_account_resend_explanatory_text %>
5
+
6
+ <% if params[rodauth.login_param] %>
7
+ <%= form.hidden_field rodauth.login_param, value: params[rodauth.login_param] %>
8
+ <% else %>
9
+ <div class="form-group mb-3">
10
+ <%= form.label "login", rodauth.login_label, class: "form-label" %>
11
+ <%= 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)) %>
12
+ <%= content_tag(:span, rodauth.field_error(rodauth.login_param), class: "invalid-feedback", id: "login_error_message") if rodauth.field_error(rodauth.login_param) %>
13
+ </div>
14
+ <% end %>
15
+
16
+ <div class="form-group mb-3">
17
+ <%= form.submit rodauth.verify_account_resend_button, class: "btn btn-primary" %>
18
+ </div>
19
+ <% end %>
@@ -1,3 +1,7 @@
1
- <%%= form_tag <%= rodauth %>.verify_login_change_path, method: :post do %>
2
- <%%= render "submit", value: "Verify Login Change" %>
3
- <%% end %>
1
+ <% content_for :title, rodauth.verify_login_change_page_title %>
2
+
3
+ <%= form_with url: rodauth.verify_login_change_path, method: :post do |form| %>
4
+ <div class="form-group mb-3">
5
+ <%= form.submit rodauth.verify_login_change_button, class: "btn btn-primary" %>
6
+ </div>
7
+ <% end %>
@@ -1,13 +1,17 @@
1
- <%% cred = <%= rodauth %>.webauth_credential_options_for_get %>
1
+ <% content_for :title, rodauth.webauthn_auth_page_title %>
2
2
 
3
- <%%= form_tag <%= rodauth %>.webauthn_auth_form_path, method: :post, id: "webauthn-auth-form", data: { credential_options: cred.as_json.to_json } do %>
4
- <%%= render "login_hidden_field" if params[<%= rodauth %>.login_param] %>
5
- <%%= hidden_field_tag <%= rodauth %>.webauthn_auth_challenge_param, cred.challenge %>
6
- <%%= hidden_field_tag <%= rodauth %>.webauthn_auth_challenge_hmac_param, <%= rodauth %>.compute_hmac(cred.challenge) %>
7
- <%%= text_field_tag <%= rodauth %>.webauthn_auth_param, "", id: "webauthn-auth", aria: { hidden: "true" } %>
3
+ <% cred = rodauth.webauth_credential_options_for_get %>
4
+
5
+ <%= form_with url: rodauth.webauthn_auth_form_path, method: :post, id: "webauthn-auth-form", data: { credential_options: cred.as_json.to_json } do |form| %>
6
+ <%= form.hidden_field rodauth.login_param, value: params[rodauth.login_param] %>
7
+ <%= form.hidden_field rodauth.webauthn_auth_challenge_param, value: cred.challenge %>
8
+ <%= form.hidden_field rodauth.webauthn_auth_challenge_hmac_param, value: rodauth.compute_hmac(cred.challenge) %>
9
+ <%= form.text_field rodauth.webauthn_auth_param, value: "", id: "webauthn-auth", aria: { hidden: "true" } %>
8
10
  <div id="webauthn-auth-button">
9
- <%%= render "submit", value: "Authenticate Using WebAuthn" %>
11
+ <div class="form-group mb-3">
12
+ <%= form.submit rodauth.webauthn_auth_button, class: "btn btn-primary" %>
13
+ </div>
10
14
  </div>
11
- <%% end %>
15
+ <% end %>
12
16
 
13
- <%%= javascript_include_tag <%= rodauth %>.webauthn_auth_js_path %>
17
+ <%= javascript_include_tag rodauth.webauthn_auth_js_path %>
@@ -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,96 +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
- lockout: %w[
65
- _login_hidden_field _submit unlock_account_request unlock_account
66
- ],
67
- active_sessions: %w[
68
- _global_logout_field
69
- ],
70
- two_factor_base: %w[
71
- _field _field_error _password_field _submit
72
- two_factor_manage two_factor_auth two_factor_disable
73
- ],
74
- otp: %w[
75
- _field _field_error _otp_auth_code_field _password_field _submit
76
- otp_setup otp_auth otp_disable
77
- ],
78
- sms_codes: %w[
79
- _field _field_error _sms_code_field _sms_phone_field
80
- _password_field _submit
81
- sms_setup sms_confirm sms_auth sms_request sms_disable
82
- ],
83
- recovery_codes: %w[
84
- _field _field_error _recovery_code_field _recovery_codes_form
85
- recovery_codes add_recovery_codes recovery_auth
86
- ],
87
- webauthn: %w[
88
- _field _field_error _login_hidden_field _password_field _submit
89
- webauthn_setup webauthn_auth webauthn_remove
90
- ]
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],
91
39
  }
92
40
 
93
41
  DEPENDENCIES = {
94
- active_sessions: :logout,
95
- otp: :two_factor_base,
96
- sms_codes: :two_factor_base,
97
- recovery_codes: :two_factor_base,
98
- 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,
99
46
  }
100
47
 
101
48
  def create_views
102
- if options[:all]
103
- features = VIEWS.keys
104
- else
105
- features = (options[:features] || self.features).map(&:to_sym)
106
- end
107
-
108
49
  views = features.inject([]) do |list, feature|
109
50
  list |= VIEWS[feature] || []
110
51
  list |= VIEWS[DEPENDENCIES[feature]] || []
111
52
  end
112
53
 
113
54
  views.each do |view|
114
- template "app/views/rodauth/#{view}.html.erb",
115
- "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
116
73
  end
117
74
  end
118
75
 
@@ -124,19 +81,27 @@ module Rodauth
124
81
  controller.controller_path
125
82
  end
126
83
 
127
- def rodauth
128
- "rodauth#{"(:#{configuration_name})" if configuration_name}"
84
+ def controller
85
+ rodauth_configuration.allocate.rails_controller
129
86
  end
130
87
 
131
- def controller
132
- rodauth = Rodauth::Rails.app.rodauth(configuration_name)
133
- fail ArgumentError, "unknown rodauth configuration: #{configuration_name.inspect}" unless rodauth
134
- rodauth.allocate.rails_controller
88
+ def rodauth_configuration
89
+ Rodauth::Rails.app.rodauth!(configuration_name)
135
90
  end
136
91
 
137
92
  def configuration_name
138
93
  options[:name]&.to_sym
139
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
140
105
  end
141
106
  end
142
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
@@ -6,10 +6,10 @@ module Rodauth
6
6
  # Base auth class that applies some default configuration and supports
7
7
  # multi-level inheritance.
8
8
  class Auth < Rodauth::Auth
9
- def self.inherited(auth_class)
9
+ def self.inherited(subclass)
10
10
  super
11
11
  superclass = self
12
- auth_class.class_eval do
12
+ subclass.class_eval do
13
13
  @roda_class = Rodauth::Rails.app
14
14
  @features = superclass.features.clone
15
15
  @routes = superclass.routes.clone
@@ -4,13 +4,54 @@ module Rodauth
4
4
  def self.included(controller)
5
5
  # ActionController::API doesn't have helper methods
6
6
  if controller.respond_to?(:helper_method)
7
- controller.helper_method :rodauth
7
+ controller.helper_method :rodauth, :current_account
8
8
  end
9
9
  end
10
10
 
11
11
  def rodauth(name = nil)
12
12
  request.env.fetch ["rodauth", *name].join(".")
13
13
  end
14
+
15
+ def current_account(name = nil)
16
+ model = rodauth(name).rails_account_model
17
+ id = rodauth(name).session_value
18
+
19
+ @current_account ||= {}
20
+ @current_account[name] ||= fetch_account(model, id) do
21
+ rodauth(name).clear_session
22
+ rodauth(name).login_required
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def fetch_account(model, id, &not_found)
29
+ if defined?(ActiveRecord::Base) && model < ActiveRecord::Base
30
+ begin
31
+ model.find(id)
32
+ rescue ActiveRecord::RecordNotFound
33
+ not_found.call
34
+ end
35
+ elsif model < Sequel::Model
36
+ begin
37
+ model.with_pk!(id)
38
+ rescue Sequel::NoMatchingRow
39
+ not_found.call
40
+ end
41
+ else
42
+ fail Error, "unsupported model type: #{model}"
43
+ end
44
+ end
45
+
46
+ def rodauth_response
47
+ res = catch(:halt) { return yield }
48
+
49
+ self.status = res[0]
50
+ self.headers.merge! res[1]
51
+ self.response_body = res[2]
52
+
53
+ res
54
+ end
14
55
  end
15
56
  end
16
57
  end
@@ -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.15.0"
3
+ VERSION = "0.18.0"
4
4
  end
5
5
  end