rodauth-rails 0.11.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +316 -218
- data/lib/generators/rodauth/templates/app/lib/rodauth_app.rb +8 -4
- data/lib/generators/rodauth/templates/app/models/account.rb +1 -0
- data/lib/generators/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_field_error.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_global_logout_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_confirm_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_display.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_header.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_hidden_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_new_password_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_otp_auth_code_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_password_confirm_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_password_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_code_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_codes_form.html.erb +4 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_sms_code_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_sms_phone_field.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_submit.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/change_login.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/change_password.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/close_account.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/confirm_password.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/create_account.html.erb +4 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/email_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/logout.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_disable.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_setup.html.erb +9 -9
- data/lib/generators/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/remember.html.erb +5 -5
- data/lib/generators/rodauth/templates/app/views/rodauth/reset_password.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_disable.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_request.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_setup.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +6 -6
- data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_account.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +7 -7
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +6 -6
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +7 -7
- data/lib/generators/rodauth/views_generator.rb +26 -4
- data/lib/rodauth/rails.rb +32 -13
- data/lib/rodauth/rails/auth.rb +9 -12
- data/lib/rodauth/rails/feature.rb +19 -230
- data/lib/rodauth/rails/feature/base.rb +62 -0
- data/lib/rodauth/rails/feature/callbacks.rb +65 -0
- data/lib/rodauth/rails/feature/csrf.rb +65 -0
- data/lib/rodauth/rails/feature/email.rb +30 -0
- data/lib/rodauth/rails/feature/instrumentation.rb +71 -0
- data/lib/rodauth/rails/feature/internal_request.rb +50 -0
- data/lib/rodauth/rails/feature/render.rb +48 -0
- data/lib/rodauth/rails/model.rb +101 -0
- data/lib/rodauth/rails/model/associations.rb +195 -0
- data/lib/rodauth/rails/railtie.rb +0 -5
- data/lib/rodauth/rails/tasks.rake +5 -5
- data/lib/rodauth/rails/version.rb +1 -1
- data/rodauth-rails.gemspec +4 -1
- metadata +56 -6
- data/lib/rodauth/rails/log_subscriber.rb +0 -34
@@ -1,5 +1,5 @@
|
|
1
|
-
<%%= form_tag rodauth
|
2
|
-
<%%= render "password_field" if rodauth
|
1
|
+
<%%= form_tag <%= rodauth %>.sms_setup_path, method: :post do %>
|
2
|
+
<%%= render "password_field" if <%= rodauth %>.two_factor_modifications_require_password? %>
|
3
3
|
<%%= render "sms_phone_field" %>
|
4
4
|
<%%= render "submit", value: "Setup SMS Backup Number" %>
|
5
5
|
<%% end %>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%%= form_tag rodauth
|
2
|
-
<%%= render "password_field" if rodauth
|
1
|
+
<%%= form_tag <%= rodauth %>.two_factor_disable_path, method: :post do %>
|
2
|
+
<%%= render "password_field" if <%= rodauth %>.two_factor_modifications_require_password? %>
|
3
3
|
<%%= render "submit", value: "Remove All Multifactor Authentication Methods" %>
|
4
4
|
<%% end %>
|
@@ -1,22 +1,22 @@
|
|
1
|
-
<%% if rodauth
|
1
|
+
<%% if <%= rodauth %>.two_factor_setup_links.any? %>
|
2
2
|
<h2>Setup Multifactor Authentication</h2>
|
3
3
|
|
4
4
|
<ul>
|
5
|
-
<%% rodauth
|
5
|
+
<%% <%= rodauth %>.two_factor_setup_links.sort.each do |_, link, text| %>
|
6
6
|
<li><%%= link_to text, link %></li>
|
7
7
|
<%% end %>
|
8
8
|
</ul>
|
9
9
|
<%% end %>
|
10
10
|
|
11
|
-
<%% if rodauth
|
11
|
+
<%% if <%= rodauth %>.two_factor_remove_links.any? %>
|
12
12
|
<h2>Remove Multifactor Authentication</h2>
|
13
13
|
|
14
14
|
<ul>
|
15
|
-
<%% rodauth
|
15
|
+
<%% <%= rodauth %>.two_factor_remove_links.sort.each do |_, link, text| %>
|
16
16
|
<li><%%= link_to text, link %></li>
|
17
17
|
<%% end %>
|
18
|
-
<%% if rodauth
|
19
|
-
<li><%%= link_to "Remove All Multifactor Authentication Methods", rodauth
|
18
|
+
<%% if <%= rodauth %>.two_factor_remove_links.length > 1 %>
|
19
|
+
<li><%%= link_to "Remove All Multifactor Authentication Methods", <%= rodauth %>.two_factor_disable_path %></li>
|
20
20
|
<%% end %>
|
21
21
|
</ul>
|
22
22
|
<%% end %>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<%%= form_tag rodauth
|
1
|
+
<%%= form_tag <%= rodauth %>.unlock_account_path, method: :post do %>
|
2
2
|
<p>This account is currently locked out. You can unlock the account:</p>
|
3
|
-
<%%= render "password_field" if rodauth
|
3
|
+
<%%= render "password_field" if <%= rodauth %>.unlock_account_requires_password? %>
|
4
4
|
<%%= render "submit", value: "Unlock Account" %>
|
5
5
|
<%% end %>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%%= form_tag rodauth
|
1
|
+
<%%= form_tag <%= rodauth %>.unlock_account_request_path, method: :post do %>
|
2
2
|
<p>This account is currently locked out. You can request that the account be unlocked:</p>
|
3
3
|
<%%= render "login_hidden_field" %>
|
4
4
|
<%%= render "submit", value: "Request Account Unlock" %>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<%%= form_tag rodauth
|
2
|
-
<%%= render "password_field" if rodauth
|
3
|
-
<%%= render "password_confirm_field" if rodauth
|
1
|
+
<%%= form_tag <%= rodauth %>.verify_account_path, method: :post do %>
|
2
|
+
<%%= render "password_field" if <%= rodauth %>.verify_account_set_password? %>
|
3
|
+
<%%= render "password_confirm_field" if <%= rodauth %>.verify_account_set_password? && <%= rodauth %>.require_password_confirmation? %>
|
4
4
|
<%%= render "submit", value: "Verify Account" %>
|
5
5
|
<%% end %>
|
@@ -1,6 +1,6 @@
|
|
1
|
-
<%%= form_tag rodauth
|
1
|
+
<%%= form_tag <%= rodauth %>.verify_account_resend_path, method: :post do %>
|
2
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
|
3
|
+
<%% if params[<%= rodauth %>.login_param] %>
|
4
4
|
<%%= render "login_hidden_field" %>
|
5
5
|
<%% else %>
|
6
6
|
<%%= render "login_field" %>
|
@@ -1,13 +1,13 @@
|
|
1
|
-
<%% cred = rodauth
|
1
|
+
<%% cred = <%= rodauth %>.webauth_credential_options_for_get %>
|
2
2
|
|
3
|
-
<%%= form_tag rodauth
|
4
|
-
<%%= render "login_hidden_field" if params[rodauth
|
5
|
-
<%%= hidden_field_tag rodauth
|
6
|
-
<%%= hidden_field_tag rodauth
|
7
|
-
<%%= text_field_tag rodauth
|
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" } %>
|
8
8
|
<div id="webauthn-auth-button">
|
9
9
|
<%%= render "submit", value: "Authenticate Using WebAuthn" %>
|
10
10
|
</div>
|
11
11
|
<%% end %>
|
12
12
|
|
13
|
-
<%%= javascript_include_tag rodauth
|
13
|
+
<%%= javascript_include_tag <%= rodauth %>.webauthn_auth_js_path %>
|
@@ -1,11 +1,11 @@
|
|
1
|
-
<%%= form_tag rodauth
|
2
|
-
<%%= render "password_field" if rodauth
|
3
|
-
<fieldset class="form-group">
|
4
|
-
<%% (usage = rodauth
|
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? %>
|
3
|
+
<fieldset class="form-group mb-3">
|
4
|
+
<%% (usage = <%= rodauth %>.account_webauthn_usage).each do |id, last_use| %>
|
5
5
|
<div class="form-check">
|
6
|
-
<%%= render "field", name: rodauth
|
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
7
|
<%%= label_tag "webauthn-remove-#{id}", "Last use: #{last_use}", class: "form-check-label" %>
|
8
|
-
<%%= render "field_error", name: rodauth
|
8
|
+
<%%= render "field_error", name: <%= rodauth %>.webauthn_remove_param if id == usage.keys.last %>
|
9
9
|
</div>
|
10
10
|
<%% end %>
|
11
11
|
</fieldset>
|
@@ -1,13 +1,13 @@
|
|
1
|
-
<%% cred = rodauth
|
1
|
+
<%% cred = <%= rodauth %>.new_webauthn_credential %>
|
2
2
|
|
3
|
-
<%%= form_tag rodauth
|
4
|
-
<%%= hidden_field_tag rodauth
|
5
|
-
<%%= hidden_field_tag rodauth
|
6
|
-
<%%= text_field_tag rodauth
|
7
|
-
<%%= render "password_field" if rodauth
|
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
8
|
<div id="webauthn-setup-button">
|
9
9
|
<%%= render "submit", value: "Setup WebAuthn Authentication" %>
|
10
10
|
</div>
|
11
11
|
<%% end %>
|
12
12
|
|
13
|
-
<%%= javascript_include_tag rodauth
|
13
|
+
<%%= javascript_include_tag <%= rodauth %>.webauthn_setup_js_path %>
|
@@ -18,9 +18,9 @@ module Rodauth
|
|
18
18
|
desc: "Generates views for all Rodauth features",
|
19
19
|
default: false
|
20
20
|
|
21
|
-
class_option :
|
22
|
-
desc: "The
|
23
|
-
default:
|
21
|
+
class_option :name, aliases: "-n", type: :string,
|
22
|
+
desc: "The configuration name for which to generate views",
|
23
|
+
default: nil
|
24
24
|
|
25
25
|
VIEWS = {
|
26
26
|
login: %w[
|
@@ -112,9 +112,31 @@ module Rodauth
|
|
112
112
|
|
113
113
|
views.each do |view|
|
114
114
|
template "app/views/rodauth/#{view}.html.erb",
|
115
|
-
"app/views/#{
|
115
|
+
"app/views/#{directory}/#{view}.html.erb"
|
116
116
|
end
|
117
117
|
end
|
118
|
+
|
119
|
+
def directory
|
120
|
+
if controller.abstract?
|
121
|
+
fail Error, "no controller configured for configuration: #{configuration_name.inspect}"
|
122
|
+
end
|
123
|
+
|
124
|
+
controller.controller_path
|
125
|
+
end
|
126
|
+
|
127
|
+
def rodauth
|
128
|
+
"rodauth#{"(:#{configuration_name})" if configuration_name}"
|
129
|
+
end
|
130
|
+
|
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
|
135
|
+
end
|
136
|
+
|
137
|
+
def configuration_name
|
138
|
+
options[:name]&.to_sym
|
139
|
+
end
|
118
140
|
end
|
119
141
|
end
|
120
142
|
end
|
data/lib/rodauth/rails.rb
CHANGED
@@ -9,28 +9,47 @@ module Rodauth
|
|
9
9
|
# This allows the developer to avoid loading Rodauth at boot time.
|
10
10
|
autoload :App, "rodauth/rails/app"
|
11
11
|
autoload :Auth, "rodauth/rails/auth"
|
12
|
+
autoload :Model, "rodauth/rails/model"
|
12
13
|
|
13
14
|
@app = nil
|
14
15
|
@middleware = true
|
15
16
|
|
17
|
+
LOCK = Mutex.new
|
18
|
+
|
16
19
|
class << self
|
17
|
-
def rodauth(name = nil)
|
18
|
-
|
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
|
26
|
+
|
27
|
+
LOCK.synchronize do
|
28
|
+
unless auth_class.features.include?(:internal_request)
|
29
|
+
auth_class.configure { enable :internal_request }
|
30
|
+
warn "Rodauth::Rails.rodauth requires the internal_request feature to be enabled. For now it was enabled automatically, but this behaviour will be removed in version 1.0."
|
31
|
+
end
|
32
|
+
end
|
19
33
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
host += ":#{port}" if port
|
34
|
+
if query || form
|
35
|
+
warn "The :query and :form keyword arguments for Rodauth::Rails.rodauth have been deprecated. Please use the :params argument supported by internal_request feature instead."
|
36
|
+
options[:params] = query || form
|
37
|
+
end
|
25
38
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
}
|
39
|
+
if account
|
40
|
+
options[:account_id] = account.id
|
41
|
+
end
|
30
42
|
|
31
|
-
|
43
|
+
instance = auth_class.internal_request_eval(options) do
|
44
|
+
@account = account.attributes.symbolize_keys if account
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
instance
|
49
|
+
end
|
32
50
|
|
33
|
-
|
51
|
+
def model(name = nil, **options)
|
52
|
+
Rodauth::Rails::Model.new(app.rodauth(name), **options)
|
34
53
|
end
|
35
54
|
|
36
55
|
# routing constraint that requires authentication
|
data/lib/rodauth/rails/auth.rb
CHANGED
@@ -6,20 +6,17 @@ 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
|
-
class << self
|
10
|
-
attr_writer :features
|
11
|
-
attr_writer :routes
|
12
|
-
attr_accessor :configuration
|
13
|
-
end
|
14
|
-
|
15
9
|
def self.inherited(auth_class)
|
16
10
|
super
|
17
|
-
|
18
|
-
auth_class.
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
superclass = self
|
12
|
+
auth_class.class_eval do
|
13
|
+
@roda_class = Rodauth::Rails.app
|
14
|
+
@features = superclass.features.clone
|
15
|
+
@routes = superclass.routes.clone
|
16
|
+
@route_hash = superclass.route_hash.clone
|
17
|
+
@configuration = superclass.instance_variable_get(:@configuration).clone
|
18
|
+
@configuration.instance_variable_set(:@auth, self)
|
19
|
+
end
|
23
20
|
end
|
24
21
|
|
25
22
|
# apply default configuration
|
@@ -1,234 +1,23 @@
|
|
1
1
|
module Rodauth
|
2
2
|
Feature.define(:rails) do
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
# Renders templates without layout. First tries to render a user-defined
|
25
|
-
# template or partial, otherwise falls back to Rodauth's template.
|
26
|
-
def render(page)
|
27
|
-
rails_render(partial: page.tr("-", "_"), layout: false) ||
|
28
|
-
rails_render(action: page.tr("-", "_"), layout: false) ||
|
29
|
-
super.html_safe
|
30
|
-
end
|
31
|
-
|
32
|
-
# Render Rails CSRF tags in Rodauth templates.
|
33
|
-
def csrf_tag(*)
|
34
|
-
rails_csrf_tag
|
35
|
-
end
|
36
|
-
|
37
|
-
# Verify Rails' authenticity token.
|
38
|
-
def check_csrf
|
39
|
-
rails_check_csrf!
|
40
|
-
end
|
41
|
-
|
42
|
-
# Have Rodauth call #check_csrf automatically.
|
43
|
-
def check_csrf?
|
44
|
-
true
|
45
|
-
end
|
46
|
-
|
47
|
-
# Reset Rails session to protect from session fixation attacks.
|
48
|
-
def clear_session
|
49
|
-
rails_controller_instance.reset_session
|
50
|
-
end
|
51
|
-
|
52
|
-
# Default the flash error key to Rails' default :alert.
|
53
|
-
def flash_error_key
|
54
|
-
:alert
|
55
|
-
end
|
56
|
-
|
57
|
-
# Evaluates the block in context of a Rodauth controller instance.
|
58
|
-
def rails_controller_eval(&block)
|
59
|
-
rails_controller_instance.instance_exec(&block)
|
60
|
-
end
|
61
|
-
|
62
|
-
def button(*)
|
63
|
-
super.html_safe
|
64
|
-
end
|
65
|
-
|
66
|
-
delegate :rails_routes, :rails_request, to: :scope
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
# Runs controller callbacks and rescue handlers around Rodauth actions.
|
71
|
-
def _around_rodauth(&block)
|
72
|
-
result = nil
|
73
|
-
|
74
|
-
rails_instrument_request do
|
75
|
-
rails_controller_rescue do
|
76
|
-
rails_controller_callbacks do
|
77
|
-
result = catch(:halt) { super(&block) }
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
result = handle_rails_controller_response(result)
|
82
|
-
end
|
83
|
-
|
84
|
-
throw :halt, result if result
|
85
|
-
end
|
86
|
-
|
87
|
-
# Handles controller rendering a response or setting response headers.
|
88
|
-
def handle_rails_controller_response(result)
|
89
|
-
if rails_controller_instance.performed?
|
90
|
-
rails_controller_response
|
91
|
-
elsif result
|
92
|
-
result[1].merge!(rails_controller_instance.response.headers)
|
93
|
-
result
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
# Runs any #(before|around|after)_action controller callbacks.
|
98
|
-
def rails_controller_callbacks
|
99
|
-
# don't verify CSRF token as part of callbacks, Rodauth will do that
|
100
|
-
rails_controller_forgery_protection { false }
|
101
|
-
|
102
|
-
rails_controller_instance.run_callbacks(:process_action) do
|
103
|
-
# turn the setting back to default so that form tags generate CSRF tags
|
104
|
-
rails_controller_forgery_protection { rails_controller.allow_forgery_protection }
|
105
|
-
|
106
|
-
yield
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# Runs any registered #rescue_from controller handlers.
|
111
|
-
def rails_controller_rescue
|
112
|
-
yield
|
113
|
-
rescue Exception => exception
|
114
|
-
rails_controller_instance.rescue_with_handler(exception) || raise
|
115
|
-
|
116
|
-
unless rails_controller_instance.performed?
|
117
|
-
raise Rodauth::Rails::Error, "rescue_from handler didn't write any response"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def rails_instrument_request
|
122
|
-
ActiveSupport::Notifications.instrument("start_processing.rodauth", rodauth: self)
|
123
|
-
ActiveSupport::Notifications.instrument("process_request.rodauth", rodauth: self) do |payload|
|
124
|
-
begin
|
125
|
-
status, headers, body = yield
|
126
|
-
payload[:status] = status || 404
|
127
|
-
payload[:headers] = headers
|
128
|
-
payload[:body] = body
|
129
|
-
ensure
|
130
|
-
rails_controller_instance.send(:append_info_to_payload, payload)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
# Returns Roda response from controller response if set.
|
136
|
-
def rails_controller_response
|
137
|
-
controller_response = rails_controller_instance.response
|
138
|
-
|
139
|
-
response.status = controller_response.status
|
140
|
-
response.headers.merge! controller_response.headers
|
141
|
-
response.write controller_response.body
|
142
|
-
|
143
|
-
response.finish
|
144
|
-
end
|
145
|
-
|
146
|
-
# Create emails with ActionMailer which uses configured delivery method.
|
147
|
-
def create_email_to(to, subject, body)
|
148
|
-
Mailer.create_email(to: to, from: email_from, subject: "#{email_subject_prefix}#{subject}", body: body)
|
149
|
-
end
|
150
|
-
|
151
|
-
# Delivers the given email.
|
152
|
-
def send_email(email)
|
153
|
-
email.deliver_now
|
154
|
-
end
|
155
|
-
|
156
|
-
# Calls the Rails renderer, returning nil if a template is missing.
|
157
|
-
def rails_render(*args)
|
158
|
-
return if rails_api_controller?
|
159
|
-
|
160
|
-
rails_controller_instance.render_to_string(*args)
|
161
|
-
rescue ActionView::MissingTemplate
|
162
|
-
nil
|
163
|
-
end
|
164
|
-
|
165
|
-
# Calls the controller to verify the authenticity token.
|
166
|
-
def rails_check_csrf!
|
167
|
-
rails_controller_instance.send(:verify_authenticity_token)
|
168
|
-
end
|
169
|
-
|
170
|
-
# Hidden tag with Rails CSRF token inserted into Rodauth templates.
|
171
|
-
def rails_csrf_tag
|
172
|
-
%(<input type="hidden" name="#{rails_csrf_param}" value="#{rails_csrf_token}">)
|
173
|
-
end
|
174
|
-
|
175
|
-
# The request parameter under which to send the Rails CSRF token.
|
176
|
-
def rails_csrf_param
|
177
|
-
rails_controller.request_forgery_protection_token
|
178
|
-
end
|
179
|
-
|
180
|
-
# The Rails CSRF token value inserted into Rodauth templates.
|
181
|
-
def rails_csrf_token
|
182
|
-
rails_controller_instance.send(:form_authenticity_token)
|
183
|
-
end
|
184
|
-
|
185
|
-
# allows/disables forgery protection
|
186
|
-
def rails_controller_forgery_protection(&value)
|
187
|
-
return if rails_api_controller?
|
188
|
-
|
189
|
-
rails_controller_instance.allow_forgery_protection = value.call
|
190
|
-
end
|
191
|
-
|
192
|
-
# Instances of the configured controller with current request's env hash.
|
193
|
-
def _rails_controller_instance
|
194
|
-
controller = rails_controller.new
|
195
|
-
prepare_rails_controller(controller, rails_request)
|
196
|
-
controller
|
197
|
-
end
|
198
|
-
|
199
|
-
if ActionPack.version >= Gem::Version.new("5.0")
|
200
|
-
def prepare_rails_controller(controller, rails_request)
|
201
|
-
controller.set_request! rails_request
|
202
|
-
controller.set_response! rails_controller.make_response!(rails_request)
|
203
|
-
end
|
204
|
-
else
|
205
|
-
def prepare_rails_controller(controller, rails_request)
|
206
|
-
controller.send(:set_response!, rails_request)
|
207
|
-
controller.instance_variable_set(:@_request, rails_request)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def rails_api_controller?
|
212
|
-
defined?(ActionController::API) && rails_controller <= ActionController::API
|
213
|
-
end
|
214
|
-
|
215
|
-
def rails_controller
|
216
|
-
if only_json? && Rodauth::Rails.api_only?
|
217
|
-
ActionController::API
|
218
|
-
else
|
219
|
-
ActionController::Base
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
# ActionMailer subclass for correct email delivering.
|
224
|
-
class Mailer < ActionMailer::Base
|
225
|
-
def create_email(**options)
|
226
|
-
mail(**options)
|
227
|
-
end
|
228
|
-
end
|
3
|
+
# Assign feature and feature configuration to constants for introspection.
|
4
|
+
Rodauth::Rails::Feature = self
|
5
|
+
Rodauth::Rails::FeatureConfiguration = self.configuration
|
6
|
+
|
7
|
+
require "rodauth/rails/feature/base"
|
8
|
+
require "rodauth/rails/feature/callbacks"
|
9
|
+
require "rodauth/rails/feature/csrf"
|
10
|
+
require "rodauth/rails/feature/render"
|
11
|
+
require "rodauth/rails/feature/email"
|
12
|
+
require "rodauth/rails/feature/instrumentation"
|
13
|
+
require "rodauth/rails/feature/internal_request"
|
14
|
+
|
15
|
+
include Rodauth::Rails::Feature::Base
|
16
|
+
include Rodauth::Rails::Feature::Callbacks
|
17
|
+
include Rodauth::Rails::Feature::Csrf
|
18
|
+
include Rodauth::Rails::Feature::Render
|
19
|
+
include Rodauth::Rails::Feature::Email
|
20
|
+
include Rodauth::Rails::Feature::Instrumentation
|
21
|
+
include Rodauth::Rails::Feature::InternalRequest
|
229
22
|
end
|
230
|
-
|
231
|
-
# Assign feature and feature configuration to constants for introspection.
|
232
|
-
Rails::Feature = FEATURES[:rails]
|
233
|
-
Rails::FeatureConfiguration = FEATURES[:rails].configuration
|
234
23
|
end
|