rodauth-rails 0.11.0 → 0.12.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 +12 -0
- data/README.md +36 -144
- data/lib/generators/rodauth/templates/app/views/rodauth/_global_logout_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_confirm_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_display.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_new_password_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_otp_auth_code_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_password_confirm_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_password_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_code_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_sms_code_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_sms_phone_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_submit.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_setup.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/remember.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +1 -1
- data/lib/rodauth/rails/feature.rb +17 -230
- data/lib/rodauth/rails/feature/base.rb +62 -0
- data/lib/rodauth/rails/feature/callbacks.rb +61 -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/render.rb +41 -0
- data/lib/rodauth/rails/railtie.rb +0 -5
- data/lib/rodauth/rails/version.rb +1 -1
- metadata +8 -3
- data/lib/rodauth/rails/log_subscriber.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27d48e6bf86cf81b33f6b0282048c2fb6f16ec6602136e18de6ede5120cfd808
|
4
|
+
data.tar.gz: 2f79498ff25a42131a5ead77f3d4adf05152bc85f271c8b985f0f9fa8c04b503
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a0c44b54d304d4dfb2a205d41a5ac360e483209229fa49e767f9eaa595434b291661e283110f3ee39a8fbc17a4ad2d82f90a6e4545ca4112852ee50a35aa8da
|
7
|
+
data.tar.gz: 52bb16489dd97777f7ff2359be9014a2c55c7537b8d4449621eb95ef3b7f0030febcd06caa811d406db1fb24fcc884d22c7460a36a94255133ce261a2bbeb68d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## 0.12.0 (2021-05-15)
|
2
|
+
|
3
|
+
* Include total view render time in logs for Rodauth requests (@janko)
|
4
|
+
|
5
|
+
* Instrument redirects (@janko)
|
6
|
+
|
7
|
+
* Instrument Rodauth requests on `action_controller` namespace (@janko)
|
8
|
+
|
9
|
+
* Update templates for Boostrap 5 compatibility (@janko)
|
10
|
+
|
11
|
+
* Log request parameters for Rodauth requests (@janko)
|
12
|
+
|
1
13
|
## 0.11.0 (2021-05-06)
|
2
14
|
|
3
15
|
* Add controller-like logging for requests to Rodauth endpoints (@janko)
|
data/README.md
CHANGED
@@ -61,7 +61,7 @@ documentation][hmac] for instructions on how to safely transition, or just set
|
|
61
61
|
Add the gem to your Gemfile:
|
62
62
|
|
63
63
|
```rb
|
64
|
-
gem "rodauth-rails", "~> 0.
|
64
|
+
gem "rodauth-rails", "~> 0.12"
|
65
65
|
|
66
66
|
# gem "jwt", require: false # for JWT feature
|
67
67
|
# gem "rotp", require: false # for OTP feature
|
@@ -86,132 +86,22 @@ $ rails generate rodauth:install --jwt # token authentication via the "Authoriza
|
|
86
86
|
$ bundle add jwt
|
87
87
|
```
|
88
88
|
|
89
|
-
|
89
|
+
This generator will create a Rodauth app with common authentication features
|
90
|
+
enabled, a database migration with tables required by those features, a mailer
|
91
|
+
with default templates, and a few other files.
|
90
92
|
|
91
|
-
|
92
|
-
|
93
|
-
* Sequel initializer at `config/initializers/sequel.rb` for ActiveRecord integration
|
94
|
-
* Rodauth app at `app/lib/rodauth_app.rb`
|
95
|
-
* Rodauth controller at `app/controllers/rodauth_controller.rb`
|
96
|
-
* Account model at `app/models/account.rb`
|
97
|
-
* Rodauth mailer at `app/mailers/rodauth_mailer.rb` with views
|
93
|
+
Feel free to remove any features you don't need, along with their corresponding
|
94
|
+
tables. Afterwards, run the migration:
|
98
95
|
|
99
|
-
|
100
|
-
|
101
|
-
The migration file creates tables required by Rodauth. You're encouraged to
|
102
|
-
review the migration, and modify it to only create tables for features you
|
103
|
-
intend to use.
|
104
|
-
|
105
|
-
```rb
|
106
|
-
# db/migrate/*_create_rodauth.rb
|
107
|
-
class CreateRodauth < ActiveRecord::Migration
|
108
|
-
def change
|
109
|
-
create_table :accounts do |t| ... end
|
110
|
-
create_table :account_password_hashes do |t| ... end
|
111
|
-
create_table :account_password_reset_keys do |t| ... end
|
112
|
-
create_table :account_verification_keys do |t| ... end
|
113
|
-
create_table :account_login_change_keys do |t| ... end
|
114
|
-
create_table :account_remember_keys do |t| ... end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
```
|
118
|
-
|
119
|
-
Once you're done, you can run the migration:
|
120
|
-
|
121
|
-
```
|
96
|
+
```sh
|
122
97
|
$ rails db:migrate
|
123
98
|
```
|
124
99
|
|
125
|
-
### Rodauth initializer
|
126
|
-
|
127
|
-
The Rodauth initializer assigns the constant for your Rodauth app, which will
|
128
|
-
be called by the Rack middleware that's added in front of your Rails router.
|
129
|
-
|
130
|
-
```rb
|
131
|
-
# config/initializers/rodauth.rb
|
132
|
-
Rodauth::Rails.configure do |config|
|
133
|
-
config.app = "RodauthApp"
|
134
|
-
end
|
135
|
-
```
|
136
|
-
|
137
|
-
### Sequel initializer
|
138
|
-
|
139
|
-
Rodauth uses [Sequel] for database interaction. If you're using ActiveRecord,
|
140
|
-
an additional initializer will be created which configures Sequel to use the
|
141
|
-
ActiveRecord connection.
|
142
|
-
|
143
|
-
```rb
|
144
|
-
# config/initializers/sequel.rb
|
145
|
-
require "sequel/core"
|
146
|
-
|
147
|
-
# initialize Sequel and have it reuse Active Record's database connection
|
148
|
-
DB = Sequel.connect("postgresql://", extensions: :activerecord_connection)
|
149
|
-
```
|
150
|
-
|
151
|
-
### Rodauth app
|
152
|
-
|
153
|
-
Your Rodauth app is created in the `app/lib/` directory, and comes with a
|
154
|
-
default set of authentication features enabled, as well as extensive examples
|
155
|
-
on ways you can configure authentication behaviour.
|
156
|
-
|
157
|
-
```rb
|
158
|
-
# app/lib/rodauth_app.rb
|
159
|
-
class RodauthApp < Rodauth::Rails::App
|
160
|
-
configure do
|
161
|
-
# authentication configuration
|
162
|
-
end
|
163
|
-
|
164
|
-
route do |r|
|
165
|
-
# request handling
|
166
|
-
end
|
167
|
-
end
|
168
|
-
```
|
169
|
-
|
170
|
-
### Controller
|
171
|
-
|
172
|
-
Your Rodauth app will by default use `RodauthController` for view rendering,
|
173
|
-
CSRF protection, and running controller callbacks and rescue handlers around
|
174
|
-
Rodauth actions.
|
175
|
-
|
176
|
-
```rb
|
177
|
-
# app/controllers/rodauth_controller.rb
|
178
|
-
class RodauthController < ApplicationController
|
179
|
-
end
|
180
|
-
```
|
181
|
-
|
182
|
-
### Account model
|
183
|
-
|
184
|
-
Rodauth stores user accounts in the `accounts` table, so the generator will
|
185
|
-
also create an `Account` model for custom use.
|
186
|
-
|
187
|
-
```rb
|
188
|
-
# app/models/account.rb
|
189
|
-
class Account < ApplicationRecord
|
190
|
-
end
|
191
|
-
```
|
192
|
-
|
193
|
-
### Rodauth mailer
|
194
|
-
|
195
|
-
The default Rodauth app is configured to use `RodauthMailer` mailer
|
196
|
-
for sending authentication emails.
|
197
|
-
|
198
|
-
```rb
|
199
|
-
# app/mailers/rodauth_mailer.rb
|
200
|
-
class RodauthMailer < ApplicationMailer
|
201
|
-
def verify_account(recipient, email_link) ... end
|
202
|
-
def reset_password(recipient, email_link) ... end
|
203
|
-
def verify_login_change(recipient, old_login, new_login, email_link) ... end
|
204
|
-
def password_changed(recipient) ... end
|
205
|
-
# def email_auth(recipient, email_link) ... end
|
206
|
-
# def unlock_account(recipient, email_link) ... end
|
207
|
-
end
|
208
|
-
```
|
209
|
-
|
210
100
|
## Usage
|
211
101
|
|
212
102
|
### Routes
|
213
103
|
|
214
|
-
|
104
|
+
You can see the list of routes our Rodauth middleware handles:
|
215
105
|
|
216
106
|
```sh
|
217
107
|
$ rails rodauth:routes
|
@@ -233,7 +123,7 @@ Routes handled by RodauthApp:
|
|
233
123
|
/close-account rodauth.close_account_path
|
234
124
|
```
|
235
125
|
|
236
|
-
Using this information,
|
126
|
+
Using this information, you can add some basic authentication links to your
|
237
127
|
navigation header:
|
238
128
|
|
239
129
|
```erb
|
@@ -264,7 +154,7 @@ end
|
|
264
154
|
|
265
155
|
### Current account
|
266
156
|
|
267
|
-
To be able to fetch currently authenticated account,
|
157
|
+
To be able to fetch currently authenticated account, you can define a
|
268
158
|
`#current_account` method that fetches the account id from session and
|
269
159
|
retrieves the corresponding account record:
|
270
160
|
|
@@ -281,11 +171,11 @@ class ApplicationController < ActionController::Base
|
|
281
171
|
rodauth.logout
|
282
172
|
rodauth.login_required
|
283
173
|
end
|
284
|
-
helper_method :current_account # skip if inheriting from ActionController
|
174
|
+
helper_method :current_account # skip if inheriting from ActionController::API
|
285
175
|
end
|
286
176
|
```
|
287
177
|
|
288
|
-
This allows
|
178
|
+
This allows you to access the current account in controllers and views:
|
289
179
|
|
290
180
|
```erb
|
291
181
|
<p>Authenticated as: <%= current_account.email %></p>
|
@@ -293,9 +183,9 @@ This allows us to access the current account in controllers and views:
|
|
293
183
|
|
294
184
|
### Requiring authentication
|
295
185
|
|
296
|
-
|
297
|
-
redirecting the user to the login page if they're not logged in.
|
298
|
-
in
|
186
|
+
You'll likely want to require authentication for certain parts of your app,
|
187
|
+
redirecting the user to the login page if they're not logged in. You can do this
|
188
|
+
in your Rodauth app's routing block, which helps keep the authentication logic
|
299
189
|
encapsulated:
|
300
190
|
|
301
191
|
```rb
|
@@ -314,7 +204,7 @@ class RodauthApp < Rodauth::Rails::App
|
|
314
204
|
end
|
315
205
|
```
|
316
206
|
|
317
|
-
|
207
|
+
You can also require authentication at the controller layer:
|
318
208
|
|
319
209
|
```rb
|
320
210
|
# app/controllers/application_controller.rb
|
@@ -341,8 +231,8 @@ end
|
|
341
231
|
|
342
232
|
#### Routing constraints
|
343
233
|
|
344
|
-
|
345
|
-
|
234
|
+
In some cases it makes sense to require authentication at the Rails router
|
235
|
+
level. You can do this via the built-in `authenticated` routing constraint:
|
346
236
|
|
347
237
|
```rb
|
348
238
|
# config/routes.rb
|
@@ -404,7 +294,7 @@ This will generate views for the default set of Rodauth features into the
|
|
404
294
|
`RodauthController`.
|
405
295
|
|
406
296
|
You can pass a list of Rodauth features to the generator to create views for
|
407
|
-
these features (this will not remove any existing views):
|
297
|
+
these features (this will not remove or overwrite any existing views):
|
408
298
|
|
409
299
|
```sh
|
410
300
|
$ rails generate rodauth:views login create_account lockout otp
|
@@ -546,7 +436,7 @@ end
|
|
546
436
|
### Multiple configurations
|
547
437
|
|
548
438
|
If you need to handle multiple types of accounts that require different
|
549
|
-
authentication logic, you can create
|
439
|
+
authentication logic, you can create additional configurations for them:
|
550
440
|
|
551
441
|
```rb
|
552
442
|
# app/lib/rodauth_app.rb
|
@@ -656,8 +546,8 @@ class RodauthAdmin < RodauthBase # inherit common settings
|
|
656
546
|
end
|
657
547
|
```
|
658
548
|
|
659
|
-
Another benefit is that you can define custom methods
|
660
|
-
instead of
|
549
|
+
Another benefit of explicit classes is that you can define custom methods
|
550
|
+
directly at the class level instead of inside an `auth_class_eval`:
|
661
551
|
|
662
552
|
```rb
|
663
553
|
# app/lib/rodauth_admin.rb
|
@@ -722,7 +612,7 @@ rodauth.setup_account_verification
|
|
722
612
|
rodauth.close_account
|
723
613
|
```
|
724
614
|
|
725
|
-
This Rodauth instance will be initialized with basic Rack env that allows
|
615
|
+
This Rodauth instance will be initialized with basic Rack env that allows it
|
726
616
|
to generate URLs, using `config.action_mailer.default_url_options` options.
|
727
617
|
|
728
618
|
## How it works
|
@@ -834,7 +724,7 @@ class RodauthApp < Rodauth::Rails::App
|
|
834
724
|
configure do
|
835
725
|
# ...
|
836
726
|
enable :json
|
837
|
-
only_json? true # accept only JSON requests
|
727
|
+
only_json? true # accept only JSON requests (optional)
|
838
728
|
# ...
|
839
729
|
end
|
840
730
|
end
|
@@ -855,7 +745,7 @@ class RodauthApp < Rodauth::Rails::App
|
|
855
745
|
# ...
|
856
746
|
enable :jwt
|
857
747
|
jwt_secret "<YOUR_SECRET_KEY>" # store the JWT secret in a safe place
|
858
|
-
only_json? true # accept only JSON requests
|
748
|
+
only_json? true # accept only JSON requests (optional)
|
859
749
|
# ...
|
860
750
|
end
|
861
751
|
end
|
@@ -935,7 +825,8 @@ end
|
|
935
825
|
<%= link_to "Login via Facebook", "/auth/facebook" %>
|
936
826
|
```
|
937
827
|
|
938
|
-
|
828
|
+
Finally, let's implement the OmniAuth callback endpoint on our Rodauth
|
829
|
+
controller:
|
939
830
|
|
940
831
|
```rb
|
941
832
|
# config/routes.rb
|
@@ -988,11 +879,8 @@ end
|
|
988
879
|
|
989
880
|
## Configuring
|
990
881
|
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
The `rails` feature rodauth-rails loads is customizable as well, here is the
|
995
|
-
list of its configuration methods:
|
882
|
+
The `rails` feature rodauth-rails loads provides the following configuration
|
883
|
+
methods:
|
996
884
|
|
997
885
|
| Name | Description |
|
998
886
|
| :---- | :---------- |
|
@@ -1019,12 +907,16 @@ Rodauth::Rails.configure do |config|
|
|
1019
907
|
end
|
1020
908
|
```
|
1021
909
|
|
910
|
+
For the list of configuration methods provided by Rodauth, see the [feature
|
911
|
+
documentation].
|
912
|
+
|
1022
913
|
## Custom extensions
|
1023
914
|
|
1024
915
|
When developing custom extensions for Rodauth inside your Rails project, it's
|
1025
|
-
better to use plain modules
|
1026
|
-
feature design doesn't yet
|
1027
|
-
|
916
|
+
probably better to use plain modules, at least in the beginning, as Rodauth
|
917
|
+
feature design doesn't yet work well with Zeitwerk reloading.
|
918
|
+
|
919
|
+
Here is an example of an LDAP authentication extension that uses the
|
1028
920
|
[simple_ldap_authenticator] gem.
|
1029
921
|
|
1030
922
|
```rb
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="form-group">
|
1
|
+
<div class="form-group mb-3">
|
2
2
|
<div class="form-check">
|
3
3
|
<%%= check_box_tag rodauth.global_logout_param, "t", false, id: "global-logout", class: "form-check-input" %>
|
4
4
|
<%%= label_tag "global-logout", "Logout all Logged In Sessons?", class: "form-check-label" %>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "login-confirm", "Confirm Login" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "login-confirm", "Confirm Login", class: "form-label" %>
|
3
3
|
<%%= render "field", name: rodauth.login_confirm_param, id: "login-confirm", type: :email, autocomplete: "email" %>
|
4
4
|
</div>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "login", "Login" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "login", "Login", class: "form-label" %>
|
3
3
|
<%%= email_field_tag rodauth.login_param, params[rodauth.login_param], id: "login", readonly: true, class: "form-control-plaintext" %>
|
4
4
|
</div>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "new-password", "New Password" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "new-password", "New Password", class: "form-label" %>
|
3
3
|
<%%= render "field", name: rodauth.new_password_param, id: "new-password", type: "password", value: "", autocomplete: "new-password" %>
|
4
4
|
</div>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "otp-auth-code", "Authentication Code" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "otp-auth-code", "Authentication Code", class: "form-label" %>
|
3
3
|
<div class="row">
|
4
4
|
<div class="col-sm-3">
|
5
5
|
<%%= render "field", name: rodauth.otp_auth_param, id: "otp-auth-code", value: "", autocomplete: "off", inputmode: "numeric" %>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "password-confirm", "Confirm Password" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "password-confirm", "Confirm Password", class: "form-label" %>
|
3
3
|
<%%= render "field", name: rodauth.password_confirm_param, id: "password-confirm", type: :password, value: "", autocomplete: "new-password" %>
|
4
4
|
</div>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "password", "Password" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "password", "Password", class: "form-label" %>
|
3
3
|
<%%= render "field", name: rodauth.password_param, id: "password", type: :password, value: "", autocomplete: rodauth.password_field_autocomplete_value %>
|
4
4
|
</div>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "recovery_code", "Recovery Code" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "recovery_code", "Recovery Code", class: "form-label" %>
|
3
3
|
<%%= render "field", name: rodauth.recovery_codes_param, id: "recovery_code", value: "", autocomplete: "off" %>
|
4
4
|
</div>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "sms-code", "SMS Code" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "sms-code", "SMS Code", class: "form-label" %>
|
3
3
|
<div class="row">
|
4
4
|
<div class="col-sm-3">
|
5
5
|
<%%= render "field", name: rodauth.sms_code_param, id: "sms-code", value: "", autocomplete: "one-time-code", inputmode: "numeric" %>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<div class="form-group">
|
2
|
-
<%%= label_tag "sms-phone", "Phone Number" %>
|
1
|
+
<div class="form-group mb-3">
|
2
|
+
<%%= label_tag "sms-phone", "Phone Number", class: "form-label" %>
|
3
3
|
<div class="row">
|
4
4
|
<div class="col-sm-3">
|
5
5
|
<%%= render "field", name: rodauth.sms_phone_param, id: "sms-phone", type: :tel, autocomplete: "tel" %>
|
@@ -2,14 +2,14 @@
|
|
2
2
|
<%%= hidden_field_tag rodauth.otp_setup_param, rodauth.otp_user_key, id: "otp-key" %>
|
3
3
|
<%%= hidden_field_tag rodauth.otp_setup_raw_param, rodauth.otp_key, id: "otp-hmac-secret" if rodauth.otp_keys_use_hmac? %>
|
4
4
|
|
5
|
-
<div class="form-group">
|
5
|
+
<div class="form-group mb-3">
|
6
6
|
<p>Secret: <%%= rodauth.otp_user_key %></p>
|
7
7
|
<p>Provisioning URL: <%%= rodauth.otp_provisioning_uri %></p>
|
8
8
|
</div>
|
9
9
|
|
10
10
|
<div class="row">
|
11
11
|
<div class="col-lg-6 col-lg">
|
12
|
-
<div class="form-group">
|
12
|
+
<div class="form-group mb-3">
|
13
13
|
<p><%%= rodauth.otp_qr_code.html_safe %></p>
|
14
14
|
</div>
|
15
15
|
</div>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<%%= form_tag rodauth.remember_path, method: :post do %>
|
2
|
-
<fieldset class="form-group">
|
2
|
+
<fieldset class="form-group mb-3">
|
3
3
|
<div class="form-check">
|
4
4
|
<%%= radio_button_tag rodauth.remember_param, rodauth.remember_remember_param_value, false, id: "remember-remember", class: "form-check-input" %>
|
5
5
|
<%%= label_tag "remember-remember", "Remember Me", class: "form-check-label" %>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<%%= form_tag rodauth.webauthn_remove_path, method: :post, id: "webauthn-remove-form" do %>
|
2
2
|
<%%= render "password_field" if rodauth.two_factor_modifications_require_password? %>
|
3
|
-
<fieldset class="form-group">
|
3
|
+
<fieldset class="form-group mb-3">
|
4
4
|
<%% (usage = rodauth.account_webauthn_usage).each do |id, last_use| %>
|
5
5
|
<div class="form-check">
|
6
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 %>
|
@@ -1,234 +1,21 @@
|
|
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
|
-
rails_render(action: page.tr("-", "_"), layout: true) ||
|
21
|
-
rails_render(html: super.html_safe, layout: true)
|
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
|
+
|
14
|
+
include Rodauth::Rails::Feature::Base
|
15
|
+
include Rodauth::Rails::Feature::Callbacks
|
16
|
+
include Rodauth::Rails::Feature::Csrf
|
17
|
+
include Rodauth::Rails::Feature::Render
|
18
|
+
include Rodauth::Rails::Feature::Email
|
19
|
+
include Rodauth::Rails::Feature::Instrumentation
|
229
20
|
end
|
230
|
-
|
231
|
-
# Assign feature and feature configuration to constants for introspection.
|
232
|
-
Rails::Feature = FEATURES[:rails]
|
233
|
-
Rails::FeatureConfiguration = FEATURES[:rails].configuration
|
234
21
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Rodauth
|
2
|
+
module Rails
|
3
|
+
module Feature
|
4
|
+
module Base
|
5
|
+
def self.included(feature)
|
6
|
+
feature.auth_methods :rails_controller
|
7
|
+
feature.auth_cached_method :rails_controller_instance
|
8
|
+
end
|
9
|
+
|
10
|
+
# Reset Rails session to protect from session fixation attacks.
|
11
|
+
def clear_session
|
12
|
+
rails_controller_instance.reset_session
|
13
|
+
end
|
14
|
+
|
15
|
+
# Default the flash error key to Rails' default :alert.
|
16
|
+
def flash_error_key
|
17
|
+
:alert
|
18
|
+
end
|
19
|
+
|
20
|
+
# Evaluates the block in context of a Rodauth controller instance.
|
21
|
+
def rails_controller_eval(&block)
|
22
|
+
rails_controller_instance.instance_exec(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
delegate :rails_routes, :rails_request, to: :scope
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Instances of the configured controller with current request's env hash.
|
30
|
+
def _rails_controller_instance
|
31
|
+
controller = rails_controller.new
|
32
|
+
prepare_rails_controller(controller, rails_request)
|
33
|
+
controller
|
34
|
+
end
|
35
|
+
|
36
|
+
if ActionPack.version >= Gem::Version.new("5.0")
|
37
|
+
def prepare_rails_controller(controller, rails_request)
|
38
|
+
controller.set_request! rails_request
|
39
|
+
controller.set_response! rails_controller.make_response!(rails_request)
|
40
|
+
end
|
41
|
+
else
|
42
|
+
def prepare_rails_controller(controller, rails_request)
|
43
|
+
controller.send(:set_response!, rails_request)
|
44
|
+
controller.instance_variable_set(:@_request, rails_request)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def rails_api_controller?
|
49
|
+
defined?(ActionController::API) && rails_controller <= ActionController::API
|
50
|
+
end
|
51
|
+
|
52
|
+
def rails_controller
|
53
|
+
if only_json? && Rodauth::Rails.api_only?
|
54
|
+
ActionController::API
|
55
|
+
else
|
56
|
+
ActionController::Base
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Rodauth
|
2
|
+
module Rails
|
3
|
+
module Feature
|
4
|
+
module Callbacks
|
5
|
+
private
|
6
|
+
|
7
|
+
# Runs controller callbacks and rescue handlers around Rodauth actions.
|
8
|
+
def _around_rodauth(&block)
|
9
|
+
result = nil
|
10
|
+
|
11
|
+
rails_controller_rescue do
|
12
|
+
rails_controller_callbacks do
|
13
|
+
result = catch(:halt) { super(&block) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
result = handle_rails_controller_response(result)
|
18
|
+
|
19
|
+
throw :halt, result if result
|
20
|
+
end
|
21
|
+
|
22
|
+
# Runs any #(before|around|after)_action controller callbacks.
|
23
|
+
def rails_controller_callbacks(&block)
|
24
|
+
rails_controller_instance.run_callbacks(:process_action, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Runs any registered #rescue_from controller handlers.
|
28
|
+
def rails_controller_rescue
|
29
|
+
yield
|
30
|
+
rescue Exception => exception
|
31
|
+
rails_controller_instance.rescue_with_handler(exception) || raise
|
32
|
+
|
33
|
+
unless rails_controller_instance.performed?
|
34
|
+
raise Rodauth::Rails::Error, "rescue_from handler didn't write any response"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Handles controller rendering a response or setting response headers.
|
39
|
+
def handle_rails_controller_response(result)
|
40
|
+
if rails_controller_instance.performed?
|
41
|
+
rails_controller_response
|
42
|
+
elsif result
|
43
|
+
result[1].merge!(rails_controller_instance.response.headers)
|
44
|
+
result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns Roda response from controller response if set.
|
49
|
+
def rails_controller_response
|
50
|
+
controller_response = rails_controller_instance.response
|
51
|
+
|
52
|
+
response.status = controller_response.status
|
53
|
+
response.headers.merge! controller_response.headers
|
54
|
+
response.write controller_response.body
|
55
|
+
|
56
|
+
response.finish
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Rodauth
|
2
|
+
module Rails
|
3
|
+
module Feature
|
4
|
+
module Csrf
|
5
|
+
def self.included(feature)
|
6
|
+
feature.auth_methods(
|
7
|
+
:rails_csrf_tag,
|
8
|
+
:rails_csrf_param,
|
9
|
+
:rails_csrf_token,
|
10
|
+
:rails_check_csrf!,
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Render Rails CSRF tags in Rodauth templates.
|
15
|
+
def csrf_tag(*)
|
16
|
+
rails_csrf_tag
|
17
|
+
end
|
18
|
+
|
19
|
+
# Verify Rails' authenticity token.
|
20
|
+
def check_csrf
|
21
|
+
rails_check_csrf!
|
22
|
+
end
|
23
|
+
|
24
|
+
# Have Rodauth call #check_csrf automatically.
|
25
|
+
def check_csrf?
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def rails_controller_callbacks
|
32
|
+
return super if rails_api_controller?
|
33
|
+
|
34
|
+
# don't verify CSRF token as part of callbacks, Rodauth will do that
|
35
|
+
rails_controller_instance.allow_forgery_protection = false
|
36
|
+
super do
|
37
|
+
# turn the setting back to default so that form tags generate CSRF tags
|
38
|
+
rails_controller_instance.allow_forgery_protection = rails_controller.allow_forgery_protection
|
39
|
+
yield
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Calls the controller to verify the authenticity token.
|
44
|
+
def rails_check_csrf!
|
45
|
+
rails_controller_instance.send(:verify_authenticity_token)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Hidden tag with Rails CSRF token inserted into Rodauth templates.
|
49
|
+
def rails_csrf_tag
|
50
|
+
%(<input type="hidden" name="#{rails_csrf_param}" value="#{rails_csrf_token}">)
|
51
|
+
end
|
52
|
+
|
53
|
+
# The request parameter under which to send the Rails CSRF token.
|
54
|
+
def rails_csrf_param
|
55
|
+
rails_controller.request_forgery_protection_token
|
56
|
+
end
|
57
|
+
|
58
|
+
# The Rails CSRF token value inserted into Rodauth templates.
|
59
|
+
def rails_csrf_token
|
60
|
+
rails_controller_instance.send(:form_authenticity_token)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Rodauth
|
2
|
+
module Rails
|
3
|
+
module Feature
|
4
|
+
module Email
|
5
|
+
def self.included(feature)
|
6
|
+
feature.depends :email_base
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Create emails with ActionMailer which uses configured delivery method.
|
12
|
+
def create_email_to(to, subject, body)
|
13
|
+
Mailer.create_email(to: to, from: email_from, subject: "#{email_subject_prefix}#{subject}", body: body)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Delivers the given email.
|
17
|
+
def send_email(email)
|
18
|
+
email.deliver_now
|
19
|
+
end
|
20
|
+
|
21
|
+
# ActionMailer subclass for correct email delivering.
|
22
|
+
class Mailer < ActionMailer::Base
|
23
|
+
def create_email(**options)
|
24
|
+
mail(**options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Rodauth
|
2
|
+
module Rails
|
3
|
+
module Feature
|
4
|
+
module Instrumentation
|
5
|
+
private
|
6
|
+
|
7
|
+
def _around_rodauth
|
8
|
+
rails_instrument_request { super }
|
9
|
+
end
|
10
|
+
|
11
|
+
def redirect(*)
|
12
|
+
rails_instrument_redirection { super }
|
13
|
+
end
|
14
|
+
|
15
|
+
def rails_render(*)
|
16
|
+
render_output = nil
|
17
|
+
rails_controller_instance.view_runtime = rails_controller_instance.send(:cleanup_view_runtime) do
|
18
|
+
Benchmark.ms { render_output = super }
|
19
|
+
end
|
20
|
+
render_output
|
21
|
+
end
|
22
|
+
|
23
|
+
def rails_instrument_request
|
24
|
+
request = rails_request
|
25
|
+
|
26
|
+
raw_payload = {
|
27
|
+
controller: scope.class.superclass.name,
|
28
|
+
action: "call",
|
29
|
+
request: request,
|
30
|
+
params: request.filtered_parameters,
|
31
|
+
headers: request.headers,
|
32
|
+
format: request.format.ref,
|
33
|
+
method: request.request_method,
|
34
|
+
path: request.fullpath
|
35
|
+
}
|
36
|
+
|
37
|
+
ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload)
|
38
|
+
|
39
|
+
ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
|
40
|
+
begin
|
41
|
+
result = catch(:halt) { yield }
|
42
|
+
|
43
|
+
response = ActionDispatch::Response.new *(result || [404, {}, []])
|
44
|
+
payload[:response] = response
|
45
|
+
payload[:status] = response.status
|
46
|
+
|
47
|
+
throw :halt, result if result
|
48
|
+
rescue => error
|
49
|
+
payload[:status] = ActionDispatch::ExceptionWrapper.status_code_for_exception(error.class.name)
|
50
|
+
raise
|
51
|
+
ensure
|
52
|
+
rails_controller_eval { append_info_to_payload(payload) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def rails_instrument_redirection
|
58
|
+
ActiveSupport::Notifications.instrument("redirect_to.action_controller", request: rails_request) do |payload|
|
59
|
+
result = catch(:halt) { yield }
|
60
|
+
|
61
|
+
response = ActionDispatch::Response.new(*result)
|
62
|
+
payload[:status] = response.status
|
63
|
+
payload[:location] = response.filtered_location
|
64
|
+
|
65
|
+
throw :halt, result
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Rodauth
|
2
|
+
module Rails
|
3
|
+
module Feature
|
4
|
+
module Render
|
5
|
+
def self.included(feature)
|
6
|
+
feature.auth_methods :rails_render
|
7
|
+
end
|
8
|
+
|
9
|
+
# Renders templates with layout. First tries to render a user-defined
|
10
|
+
# template, otherwise falls back to Rodauth's template.
|
11
|
+
def view(page, *)
|
12
|
+
rails_render(action: page.tr("-", "_"), layout: true) ||
|
13
|
+
rails_render(html: super.html_safe, layout: true)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Renders templates without layout. First tries to render a user-defined
|
17
|
+
# template or partial, otherwise falls back to Rodauth's template.
|
18
|
+
def render(page)
|
19
|
+
rails_render(partial: page.tr("-", "_"), layout: false) ||
|
20
|
+
rails_render(action: page.tr("-", "_"), layout: false) ||
|
21
|
+
super.html_safe
|
22
|
+
end
|
23
|
+
|
24
|
+
def button(*)
|
25
|
+
super.html_safe
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Calls the Rails renderer, returning nil if a template is missing.
|
31
|
+
def rails_render(*args)
|
32
|
+
return if rails_api_controller?
|
33
|
+
|
34
|
+
rails_controller_instance.render_to_string(*args)
|
35
|
+
rescue ActionView::MissingTemplate
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require "rodauth/rails/middleware"
|
2
2
|
require "rodauth/rails/controller_methods"
|
3
|
-
require "rodauth/rails/log_subscriber"
|
4
3
|
|
5
4
|
require "rails"
|
6
5
|
|
@@ -17,10 +16,6 @@ module Rodauth
|
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
|
-
initializer "rodauth.log_subscriber" do
|
21
|
-
Rodauth::Rails::LogSubscriber.attach_to :rodauth
|
22
|
-
end
|
23
|
-
|
24
19
|
initializer "rodauth.test" do
|
25
20
|
# Rodauth uses RACK_ENV to set the default bcrypt hash cost
|
26
21
|
ENV["RACK_ENV"] = "test" if ::Rails.env.test?
|
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.
|
4
|
+
version: 0.12.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: 2021-05-
|
11
|
+
date: 2021-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -207,7 +207,12 @@ files:
|
|
207
207
|
- lib/rodauth/rails/auth.rb
|
208
208
|
- lib/rodauth/rails/controller_methods.rb
|
209
209
|
- lib/rodauth/rails/feature.rb
|
210
|
-
- lib/rodauth/rails/
|
210
|
+
- lib/rodauth/rails/feature/base.rb
|
211
|
+
- lib/rodauth/rails/feature/callbacks.rb
|
212
|
+
- lib/rodauth/rails/feature/csrf.rb
|
213
|
+
- lib/rodauth/rails/feature/email.rb
|
214
|
+
- lib/rodauth/rails/feature/instrumentation.rb
|
215
|
+
- lib/rodauth/rails/feature/render.rb
|
211
216
|
- lib/rodauth/rails/middleware.rb
|
212
217
|
- lib/rodauth/rails/railtie.rb
|
213
218
|
- lib/rodauth/rails/tasks.rake
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Rodauth
|
2
|
-
module Rails
|
3
|
-
class LogSubscriber < ActiveSupport::LogSubscriber
|
4
|
-
def start_processing(event)
|
5
|
-
rodauth = event.payload[:rodauth]
|
6
|
-
app_class = rodauth.scope.class.superclass
|
7
|
-
format = rodauth.rails_request.format.ref
|
8
|
-
format = format.to_s.upcase if format.is_a?(Symbol)
|
9
|
-
format = "*/*" if format.nil?
|
10
|
-
|
11
|
-
info "Processing by #{app_class} as #{format}"
|
12
|
-
end
|
13
|
-
|
14
|
-
def process_request(event)
|
15
|
-
status = event.payload[:status]
|
16
|
-
|
17
|
-
additions = ActionController::Base.log_process_action(event.payload)
|
18
|
-
if ::Rails.gem_version >= Gem::Version.new("6.0")
|
19
|
-
additions << "Allocations: #{event.allocations}"
|
20
|
-
end
|
21
|
-
|
22
|
-
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
|
23
|
-
message << " (#{additions.join(" | ")})"
|
24
|
-
message << "\n\n" if defined?(::Rails.env) && ::Rails.env.development?
|
25
|
-
|
26
|
-
info message
|
27
|
-
end
|
28
|
-
|
29
|
-
def logger
|
30
|
-
::Rails.logger
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|