quo_vadis 2.1.0 → 2.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +33 -28
- data/app/controllers/quo_vadis/password_resets_controller.rb +1 -1
- data/app/mailers/quo_vadis/mailer.rb +16 -16
- data/app/models/quo_vadis/account.rb +14 -0
- data/app/models/quo_vadis/log.rb +3 -1
- data/app/models/quo_vadis/password.rb +16 -0
- data/{test/dummy/app → app}/views/quo_vadis/confirmations/edit.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/confirmations/edit_email.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/confirmations/index.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/confirmations/new.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/logs/index.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/account_confirmation.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/email_change_notification.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/identifier_change_notification.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/password_change_notification.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/password_reset_notification.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/recovery_codes_generation_notification.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/reset_password.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/totp_reuse_notification.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/totp_setup_notification.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/mailer/twofa_deactivated_notification.text.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/password_resets/edit.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/password_resets/index.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/password_resets/new.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/passwords/edit.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/recovery_codes/challenge.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/recovery_codes/index.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/sessions/index.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/sessions/new.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/totps/challenge.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/totps/new.html.erb +0 -0
- data/{test/dummy/app → app}/views/quo_vadis/twofas/show.html.erb +0 -0
- data/config/locales/quo_vadis.en.yml +1 -0
- data/config/routes.rb +4 -4
- data/lib/generators/quo_vadis/install_generator.rb +1 -1
- data/lib/quo_vadis/controller.rb +3 -3
- data/lib/quo_vadis/model.rb +4 -0
- data/lib/quo_vadis/version.rb +1 -1
- data/lib/quo_vadis.rb +6 -4
- data/test/integration/logging_test.rb +9 -0
- data/test/integration/password_reset_test.rb +1 -1
- data/test/mailers/mailer_test.rb +49 -32
- data/test/models/account_test.rb +24 -2
- data/test/models/model_test.rb +4 -1
- data/test/models/password_test.rb +13 -0
- data/test/models/recovery_code_test.rb +7 -1
- data/test/models/token_test.rb +1 -1
- metadata +29 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0b470ad4482010d9774287306051d802625c95fa5e20675a12bf4537e71d939
|
4
|
+
data.tar.gz: 67574e42473e4c87dc112f7e7ced2104c8df54a8a02e7befcedad6e806d136a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: debe3294db5262b56514b9ece8181464783521f475c4472a43dd4555739cd97fd81bea5fde66e700be8a75ada62ee554d4374aa196bfcb063bc9ecfcd989d1cf
|
7
|
+
data.tar.gz: 00f90c64fd56cec727ba364d784de3928e68e5d34eb5fca1fd56382c77289c0d6c5a4be7396687e1e175d5dc66c4473e00ae77b8b6f52c56def2496e0abeab40
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,30 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## HEAD
|
5
|
+
|
6
|
+
|
7
|
+
## 2.1.3 (30 September 2021)
|
8
|
+
|
9
|
+
* Pass IP and timestamp as paramenters to mailer.
|
10
|
+
|
11
|
+
|
12
|
+
## 2.1.2 (30 September 2021)
|
13
|
+
|
14
|
+
* Delete existing recovery codes when generating new ones.
|
15
|
+
|
16
|
+
|
17
|
+
## 2.1.1 (8 July 2021)
|
18
|
+
|
19
|
+
* Remove unnecessary route names.
|
20
|
+
* Add user revocation.
|
21
|
+
* Ensure password is only updated via #change or #reset.
|
22
|
+
* Move views into gem's app/views/ directory.
|
23
|
+
|
24
|
+
|
4
25
|
## 2.1.0 (25 June 2021)
|
5
26
|
|
27
|
+
* Do not require password on create.
|
6
28
|
* Fix incorrect assignment of built association.
|
7
29
|
* Add i18n translations for log actions.
|
8
30
|
* Use model instance in change-password form.
|
data/README.md
CHANGED
@@ -119,7 +119,7 @@ end
|
|
119
119
|
|
120
120
|
__`login(model, browser_session = true)`__
|
121
121
|
|
122
|
-
To log in a user who has authenticated with a password, call `#login(model, browser_session = true)`. For the `browser_session` argument, pass `true` to log in for the duration of the browser session, or `false` to log in for `QuoVadis.session_lifetime` (which could be the browser session anyway).
|
122
|
+
To log in a user who has authenticated with a password, call `#login(model, browser_session = true, metadata: {})`. For the `browser_session` argument, optionally pass `true` to log in for the duration of the browser session, or `false` to log in for `QuoVadis.session_lifetime` (which could be the browser session anyway). Any metadata are stored in the log entry for the login.
|
123
123
|
|
124
124
|
__`request_confirmation(model)`__
|
125
125
|
|
@@ -246,19 +246,19 @@ class UsersController < ApplicationController
|
|
246
246
|
end
|
247
247
|
```
|
248
248
|
|
249
|
-
QuoVadis will send the user an email with a link. Write the email view ([example](https://github.com/airblade/quo_vadis/blob/master/
|
249
|
+
QuoVadis will send the user an email with a link. Write the email view ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/account_confirmation.text.erb)). It must be in `app/views/quo_vadis/mailer/account_confirmation.{text,html}.erb` and output the `@url` variable.
|
250
250
|
|
251
251
|
See the Configuration section below for how to set QuoVadis's emails' from addresses, headers, etc.
|
252
252
|
|
253
|
-
Now write the page to where the user is redirected while they wait for the email ([example](https://github.com/airblade/quo_vadis/blob/master/
|
253
|
+
Now write the page to where the user is redirected while they wait for the email ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/confirmations/index.html.erb)). It must be in `app/views/quo_vadis/confirmations/index.html.:format`.
|
254
254
|
|
255
255
|
On that page you can show the user the address the email was sent to, enable them to update their email address if they make a mistake on the sign-up form, and provide a button to resend another email directly. If the sign-up occurred in a different browser session, you can instead link to `new_confirmation_path` where the user can request another email if need be.
|
256
256
|
|
257
|
-
Next, write the page to which the link in the email points ([example](https://github.com/airblade/quo_vadis/blob/master/
|
257
|
+
Next, write the page to which the link in the email points ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/confirmations/edit.html.erb)). It must be in `app/views/quo_vadis/confirmations/edit.html.:format`.
|
258
258
|
|
259
|
-
Next, write the page where the user can amend their email address if they made a mistake when signing up ([example](https://github.com/airblade/quo_vadis/blob/master/
|
259
|
+
Next, write the page where the user can amend their email address if they made a mistake when signing up ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/confirmations/edit_email.html.erb)). It must be in `app/views/quo_vadis/confirmations/edit_email.html.:format`.
|
260
260
|
|
261
|
-
Finally, write the page where people can put in their identifier (not their email, unless the identifier is email) again to request another confirmation email ([example](https://github.com/airblade/quo_vadis/blob/master/
|
261
|
+
Finally, write the page where people can put in their identifier (not their email, unless the identifier is email) again to request another confirmation email ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/confirmations/new.html.erb)). It must be in `app/views/quo_vadis/confirmations/new.html.:format`.
|
262
262
|
|
263
263
|
After the user has confirmed their account, they will be logged in and redirected to the first of these that exists:
|
264
264
|
|
@@ -272,7 +272,7 @@ So add whichever works best for you.
|
|
272
272
|
|
273
273
|
Use `before_action :require_password_authentication` or `before_action :require_authentication` in your controllers.
|
274
274
|
|
275
|
-
Write the login view ([example](https://github.com/airblade/quo_vadis/blob/master/
|
275
|
+
Write the login view ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/sessions/new.html.erb)). Your login form must be in `app/views/quo_vadis/sessions/new.html.:format`. Note it must capture the user's identifier (not email, unless the identifier is email).
|
276
276
|
|
277
277
|
If you include a `remember` checkbox in your login form:
|
278
278
|
|
@@ -292,7 +292,7 @@ After authenticating the user will be redirected to the first of these that exis
|
|
292
292
|
|
293
293
|
If you do not want 2FA at all, set `QuoVadis.two_factor_authentication_mandatory false` in your configuration and skip the rest of this section.
|
294
294
|
|
295
|
-
If you do want 2FA, you can choose whether it is
|
295
|
+
If you do want 2FA, you can choose whether it is mandatory or optional for your users by setting `QuoVadis.two_factor_authentication_mandatory <true|false>` in your configuration.
|
296
296
|
|
297
297
|
Use `before_action :require_two_factor_authentication` in your controllers (which supersedes `:require_password_authentication`). This will require the user, after authenticating with their password, to authenticate with 2FA – when 2FA is mandatory, or when it is optional and the user has set up 2FA.
|
298
298
|
|
@@ -312,22 +312,22 @@ In your views, have a link where users can manage their 2FA:
|
|
312
312
|
link_to '2FA', quo_vadis.twofa_path
|
313
313
|
```
|
314
314
|
|
315
|
-
Write the 2FA overview page ([example](https://github.com/airblade/quo_vadis/blob/master/
|
315
|
+
Write the 2FA overview page ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/twofas/show.html.erb)). It must be in `app/views/quo_vadis/twofas/show.html.:format`. This page allows the user to set up 2FA, deactivate or reset it, and generate new recovery codes.
|
316
316
|
|
317
|
-
Next, write the TOTP setup page ([example](https://github.com/airblade/quo_vadis/blob/master/
|
317
|
+
Next, write the TOTP setup page ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/totps/new.html.erb)). It must be in `app/views/quo_vadis/totps/new.html.:format`. This page shows the user a QR code (and the key as text) which they scan with their authenticator.
|
318
318
|
|
319
|
-
Next, write the recovery codes page ([example](https://github.com/airblade/quo_vadis/blob/master/
|
319
|
+
Next, write the recovery codes page ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/recovery_codes/index.html.erb)). It must be in `app/views/quo_vadis/recovery_codes/index.html.:format`. This shows the recovery codes immediately after TOTP is setup, and immediately after generating fresh recovery codes, but not otherwise.
|
320
320
|
|
321
|
-
Next, write the TOTP challenge page where a user inputs their 6-digit TOTP ([example](https://github.com/airblade/quo_vadis/blob/master/
|
321
|
+
Next, write the TOTP challenge page where a user inputs their 6-digit TOTP ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/totps/challenge.html.erb)). It must be in `app/views/quo_vadis/totps/challenge.html.:format`. It's a good idea to link to the recovery code page (`challenge_recovery_codes_path`) for any user who has lost their authenticator.
|
322
322
|
|
323
|
-
Finally, write the recovery code challenge page where a user inputs one of their recovery codes ([example](https://github.com/airblade/quo_vadis/blob/master/
|
323
|
+
Finally, write the recovery code challenge page where a user inputs one of their recovery codes ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/recovery_codes/challenge.html.erb)). It must be in `app/views/quo_vadis/recovery_codes/challenge.html.:format`. A recovery code can only be used once, and using one deactivates TOTP – so the user will have to set it up again next time.
|
324
324
|
|
325
325
|
|
326
326
|
### Change password
|
327
327
|
|
328
328
|
To change their password, the user must provide their current one as well as the new one.
|
329
329
|
|
330
|
-
Write the change-password form ([example](https://github.com/airblade/quo_vadis/blob/master/
|
330
|
+
Write the change-password form ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/passwords/edit.html.erb)). It must be in `app/views/quo_vadis/passwords/edit.html.:format`.
|
331
331
|
|
332
332
|
After the password has been changed, the user is redirected to the first of:
|
333
333
|
|
@@ -347,17 +347,17 @@ The user can reset their password if they lose it. The flow is:
|
|
347
347
|
4. [Password-reset confirmation page] The user enters their new password and clicks a button.
|
348
348
|
5. QuoVadis sets the user's password and logs them in.
|
349
349
|
|
350
|
-
First, write the page where the user requests a password-reset ([example](https://github.com/airblade/quo_vadis/blob/master/
|
350
|
+
First, write the page where the user requests a password-reset ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/password_resets/new.html.erb)). It must be in `app/views/quo_vadis/password_resets/new.html.:format`. Note it must capture the user's identifier (not email, unless the identifier is email).
|
351
351
|
|
352
352
|
See the Configuration section below for how to set QuoVadis's emails' from addresses, headers, etc.
|
353
353
|
|
354
|
-
Now write the page to where the user is redirected while they wait for the email ([example](https://github.com/airblade/quo_vadis/blob/master/
|
354
|
+
Now write the page to where the user is redirected while they wait for the email ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/password_resets/index.html.erb)). It must be in `app/views/quo_vadis/password_resets/index.html.:format`.
|
355
355
|
|
356
356
|
It's a good idea for that page to link to `new_password_reset_path` where the user can request another email if need be.
|
357
357
|
|
358
|
-
Now write the email view ([example](https://github.com/airblade/quo_vadis/blob/master/
|
358
|
+
Now write the email view ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/reset_password.text.erb)). It must be in `app/views/quo_vadis/mailer/reset_password.{text,html}.erb` and output the `@url` variable.
|
359
359
|
|
360
|
-
Next, write the page to which the link in the email points ([example](https://github.com/airblade/quo_vadis/blob/master/
|
360
|
+
Next, write the page to which the link in the email points ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/password_resets/edit.html.erb)). It must be in `app/views/quo_vadis/password_resets/edit.html.:format`.
|
361
361
|
|
362
362
|
After the user has reset their password, they will be logged in and redirected to the first of these that exists:
|
363
363
|
|
@@ -371,14 +371,14 @@ A logged-in session lasts for either the browser session or `QuoVadis.session_li
|
|
371
371
|
|
372
372
|
A user can view their active sessions and log out of any of them.
|
373
373
|
|
374
|
-
Write the view showing the sessions ([example](https://github.com/airblade/quo_vadis/blob/master/
|
374
|
+
Write the view showing the sessions ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/sessions/index.html.erb)). It must be in `app/views/quo_vadis/sessions/index.html.:format`.
|
375
375
|
|
376
376
|
|
377
377
|
### Audit trail
|
378
378
|
|
379
379
|
An audit trail is kept of authentication events. You can see the full list in the [`Log`](https://github.com/airblade/quo_vadis/blob/master/app/models/quo_vadis/log.rb) class.
|
380
380
|
|
381
|
-
Write the view showing the events ([example](https://github.com/airblade/quo_vadis/blob/master/
|
381
|
+
Write the view showing the events ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/logs/index.html.erb)). It must be in `app/views/quo_vadis/logs/index.html.:format`.
|
382
382
|
|
383
383
|
|
384
384
|
### Notifications
|
@@ -387,18 +387,23 @@ QuoVadis notifies users by email whenever their authentication details are chang
|
|
387
387
|
|
388
388
|
Write the corresponding mailer views:
|
389
389
|
|
390
|
-
- change of email ([example](https://github.com/airblade/quo_vadis/blob/master/
|
391
|
-
- change of identifier (unless the identifier is email) ([example](https://github.com/airblade/quo_vadis/blob/master/
|
392
|
-
- change of password ([example](https://github.com/airblade/quo_vadis/blob/master/
|
393
|
-
- reset of password ([example](https://github.com/airblade/quo_vadis/blob/master/
|
394
|
-
- TOTP setup ([example](https://github.com/airblade/quo_vadis/blob/master/
|
395
|
-
- TOTP code used a second time ([example](https://github.com/airblade/quo_vadis/blob/master/
|
396
|
-
- 2FA deactivated ([example](https://github.com/airblade/quo_vadis/blob/master/
|
397
|
-
- recovery codes generated ([example](https://github.com/airblade/quo_vadis/blob/master/
|
390
|
+
- change of email ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/email_change_notification.text.erb))
|
391
|
+
- change of identifier (unless the identifier is email) ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/identifier_change_notification.text.erb))
|
392
|
+
- change of password ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/password_change_notification.text.erb))
|
393
|
+
- reset of password ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/password_reset_notification.text.erb))
|
394
|
+
- TOTP setup ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/totp_setup_notification.text.erb))
|
395
|
+
- TOTP code used a second time ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/totp_reuse_notification.text.erb))
|
396
|
+
- 2FA deactivated ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/twofa_deactivated_notification.text.erb))
|
397
|
+
- recovery codes generated ([example](https://github.com/airblade/quo_vadis/blob/master/app/views/quo_vadis/mailer/recovery_codes_generation_notification.text.erb))
|
398
398
|
|
399
399
|
They must be in `app/views/quo_vadis/mailer/NAME.{text,html}.erb`.
|
400
400
|
|
401
401
|
|
402
|
+
### Revocation
|
403
|
+
|
404
|
+
You can revoke a user's access by calling `#revoke_authentication_credentials` on the model instance. This deletes the user's password, TOTP credential, recovery codes, and active sessions. Their authentication logs, or audit trail, are preserved.
|
405
|
+
|
406
|
+
|
402
407
|
## Configuration
|
403
408
|
|
404
409
|
This is QuoVadis' [default configuration](https://github.com/airblade/quo_vadis/blob/master/lib/quo_vadis/defaults.rb):
|
@@ -17,7 +17,7 @@ module QuoVadis
|
|
17
17
|
|
18
18
|
if account
|
19
19
|
token = QuoVadis::PasswordResetToken.generate account
|
20
|
-
QuoVadis.deliver :reset_password, email: account.model.email, url: quo_vadis.
|
20
|
+
QuoVadis.deliver :reset_password, {email: account.model.email, url: quo_vadis.password_reset_url(token)}
|
21
21
|
end
|
22
22
|
|
23
23
|
redirect_to password_resets_path, notice: QuoVadis.translate('flash.password_reset.create')
|
@@ -14,52 +14,52 @@ module QuoVadis
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def email_change_notification
|
17
|
-
@timestamp =
|
18
|
-
@ip =
|
17
|
+
@timestamp = params[:timestamp]
|
18
|
+
@ip = params[:ip]
|
19
19
|
_mail params[:email], QuoVadis.translate('mailer.notification.email_change')
|
20
20
|
end
|
21
21
|
|
22
22
|
def identifier_change_notification
|
23
|
-
@timestamp =
|
23
|
+
@timestamp = params[:timestamp]
|
24
24
|
@identifier = params[:identifier]
|
25
|
-
@ip =
|
25
|
+
@ip = params[:ip]
|
26
26
|
_mail params[:email], QuoVadis.translate('mailer.notification.identifier_change',
|
27
27
|
identifier: params[:identifier])
|
28
28
|
end
|
29
29
|
|
30
30
|
def password_change_notification
|
31
|
-
@timestamp =
|
32
|
-
@ip =
|
31
|
+
@timestamp = params[:timestamp]
|
32
|
+
@ip = params[:ip]
|
33
33
|
_mail params[:email], QuoVadis.translate('mailer.notification.password_change')
|
34
34
|
end
|
35
35
|
|
36
36
|
def password_reset_notification
|
37
|
-
@timestamp =
|
38
|
-
@ip =
|
37
|
+
@timestamp = params[:timestamp]
|
38
|
+
@ip = params[:ip]
|
39
39
|
_mail params[:email], QuoVadis.translate('mailer.notification.password_reset')
|
40
40
|
end
|
41
41
|
|
42
42
|
def totp_setup_notification
|
43
|
-
@timestamp =
|
44
|
-
@ip =
|
43
|
+
@timestamp = params[:timestamp]
|
44
|
+
@ip = params[:ip]
|
45
45
|
_mail params[:email], QuoVadis.translate('mailer.notification.totp_setup')
|
46
46
|
end
|
47
47
|
|
48
48
|
def totp_reuse_notification
|
49
|
-
@timestamp =
|
50
|
-
@ip =
|
49
|
+
@timestamp = params[:timestamp]
|
50
|
+
@ip = params[:ip]
|
51
51
|
_mail params[:email], QuoVadis.translate('mailer.notification.totp_reuse')
|
52
52
|
end
|
53
53
|
|
54
54
|
def twofa_deactivated_notification
|
55
|
-
@timestamp =
|
56
|
-
@ip =
|
55
|
+
@timestamp = params[:timestamp]
|
56
|
+
@ip = params[:ip]
|
57
57
|
_mail params[:email], QuoVadis.translate('mailer.notification.twofa_deactivated')
|
58
58
|
end
|
59
59
|
|
60
60
|
def recovery_codes_generation_notification
|
61
|
-
@timestamp =
|
62
|
-
@ip =
|
61
|
+
@timestamp = params[:timestamp]
|
62
|
+
@ip = params[:ip]
|
63
63
|
_mail params[:email], QuoVadis.translate('mailer.notification.recovery_codes_generation')
|
64
64
|
end
|
65
65
|
|
@@ -32,9 +32,23 @@ module QuoVadis
|
|
32
32
|
|
33
33
|
# Returns an array of the recovery codes' codes.
|
34
34
|
def generate_recovery_codes
|
35
|
+
recovery_codes.delete_all
|
35
36
|
Array.new(MAX_NUMBER_OF_RECOVERY_CODES) { recovery_codes.create }.map &:code
|
36
37
|
end
|
37
38
|
|
39
|
+
def revoke
|
40
|
+
password&.destroy
|
41
|
+
totp&.destroy
|
42
|
+
recovery_codes.destroy_all
|
43
|
+
sessions.destroy_all
|
44
|
+
|
45
|
+
Log.create(
|
46
|
+
account: self,
|
47
|
+
action: Log::REVOKE,
|
48
|
+
ip: (CurrentRequestDetails.ip || '')
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
38
52
|
private
|
39
53
|
|
40
54
|
def log_identifier_change
|
data/app/models/quo_vadis/log.rb
CHANGED
@@ -22,6 +22,7 @@ module QuoVadis
|
|
22
22
|
ACCOUNT_CONFIRMATION = 'account.confirmation'
|
23
23
|
LOGOUT_OTHER = 'logout.other'
|
24
24
|
LOGOUT = 'logout.self'
|
25
|
+
REVOKE = 'revoke'
|
25
26
|
|
26
27
|
ACTIONS = [
|
27
28
|
LOGIN_SUCCESS,
|
@@ -41,7 +42,8 @@ module QuoVadis
|
|
41
42
|
PASSWORD_RESET,
|
42
43
|
ACCOUNT_CONFIRMATION,
|
43
44
|
LOGOUT_OTHER,
|
44
|
-
LOGOUT
|
45
|
+
LOGOUT,
|
46
|
+
REVOKE
|
45
47
|
]
|
46
48
|
|
47
49
|
belongs_to :account, optional: true # optional only for LOGIN_UNKNOWN
|
@@ -7,6 +7,7 @@ module QuoVadis
|
|
7
7
|
has_secure_password
|
8
8
|
|
9
9
|
validates_length_of :password, minimum: QuoVadis.password_minimum_length, allow_blank: true
|
10
|
+
validate :password_updated_legitimately, on: :update
|
10
11
|
|
11
12
|
attr_accessor :new_password
|
12
13
|
|
@@ -48,5 +49,20 @@ module QuoVadis
|
|
48
49
|
save
|
49
50
|
end
|
50
51
|
|
52
|
+
private
|
53
|
+
|
54
|
+
def password_updated_legitimately
|
55
|
+
return unless password_digest_changed?
|
56
|
+
|
57
|
+
unless change_or_reset_called?
|
58
|
+
errors.add :password, 'must be updated via #change or #reset'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def change_or_reset_called?
|
63
|
+
caller_locations.any? { |loc|
|
64
|
+
['change', 'reset'].include?(loc.label) && Pathname.new(loc.path).basename.to_s == 'password.rb'
|
65
|
+
}
|
66
|
+
end
|
51
67
|
end
|
52
68
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/{test/dummy/app → app}/views/quo_vadis/mailer/recovery_codes_generation_notification.text.erb
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/config/routes.rb
CHANGED
@@ -12,8 +12,8 @@ QuoVadis::Engine.routes.draw do
|
|
12
12
|
resource :password, only: [:edit, :update]
|
13
13
|
|
14
14
|
resources :password_resets, only: [:new, :create, :index]
|
15
|
-
get '/pwd-reset/:token', to: 'password_resets#edit',
|
16
|
-
put '/pwd-reset/:token', to: 'password_resets#update'
|
15
|
+
get '/pwd-reset/:token', to: 'password_resets#edit', as: 'password_reset'
|
16
|
+
put '/pwd-reset/:token', to: 'password_resets#update'
|
17
17
|
|
18
18
|
resources :confirmations, only: [:new, :create, :index] do
|
19
19
|
collection do
|
@@ -22,8 +22,8 @@ QuoVadis::Engine.routes.draw do
|
|
22
22
|
post :resend
|
23
23
|
end
|
24
24
|
end
|
25
|
-
get '/confirm/:token', to: 'confirmations#edit',
|
26
|
-
put '/confirm/:token', to: 'confirmations#update'
|
25
|
+
get '/confirm/:token', to: 'confirmations#edit', as: 'confirmation'
|
26
|
+
put '/confirm/:token', to: 'confirmations#update'
|
27
27
|
|
28
28
|
resources :totps, only: [:new, :create] do
|
29
29
|
collection do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module QuoVadis
|
2
2
|
class InstallGenerator < Rails::Generators::Base
|
3
|
-
source_root Pathname.new(__dir__) / '..' / '..' / '..' / '
|
3
|
+
source_root Pathname.new(__dir__) / '..' / '..' / '..' / 'app' / 'views' / 'quo_vadis'
|
4
4
|
|
5
5
|
desc "Copy QuoVadis' views into your app."
|
6
6
|
def copy_views
|
data/lib/quo_vadis/controller.rb
CHANGED
@@ -36,8 +36,8 @@ module QuoVadis
|
|
36
36
|
#
|
37
37
|
# browser_session - true: login only for duration of browser session
|
38
38
|
# false: login for QuoVadis.session_lifetime (which may be browser session anyway)
|
39
|
-
def login(model, browser_session = true)
|
40
|
-
qv.log model.qv_account, Log::LOGIN_SUCCESS
|
39
|
+
def login(model, browser_session = true, metadata: {})
|
40
|
+
qv.log model.qv_account, Log::LOGIN_SUCCESS, metadata
|
41
41
|
|
42
42
|
qv.prevent_rails_session_fixation
|
43
43
|
|
@@ -87,7 +87,7 @@ module QuoVadis
|
|
87
87
|
|
88
88
|
def request_confirmation(model)
|
89
89
|
token = QuoVadis::AccountConfirmationToken.generate model.qv_account
|
90
|
-
QuoVadis.deliver :account_confirmation, email: model.email, url: quo_vadis.
|
90
|
+
QuoVadis.deliver :account_confirmation, {email: model.email, url: quo_vadis.confirmation_url(token)}
|
91
91
|
session[:account_pending_confirmation] = model.qv_account.id
|
92
92
|
|
93
93
|
flash[:notice] = QuoVadis.translate 'flash.confirmation.create'
|
data/lib/quo_vadis/model.rb
CHANGED
data/lib/quo_vadis/version.rb
CHANGED
data/lib/quo_vadis.rb
CHANGED
@@ -73,12 +73,14 @@ module QuoVadis
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def notify(action, params)
|
76
|
-
|
76
|
+
deliver(action, params, later: true)
|
77
77
|
end
|
78
78
|
|
79
|
-
def deliver(action, params)
|
80
|
-
mail = QuoVadis::Mailer
|
81
|
-
|
79
|
+
def deliver(action, params, later: QuoVadis.enqueue_transactional_emails)
|
80
|
+
mail = QuoVadis::Mailer
|
81
|
+
.with(params.merge(ip: QuoVadis::CurrentRequestDetails.ip, timestamp: Time.now))
|
82
|
+
.send(action)
|
83
|
+
later ?
|
82
84
|
mail.deliver_later :
|
83
85
|
mail.deliver_now
|
84
86
|
end
|
@@ -201,6 +201,15 @@ class LoggingTest < IntegrationTest
|
|
201
201
|
end
|
202
202
|
|
203
203
|
|
204
|
+
test 'revoke' do
|
205
|
+
login_new_session
|
206
|
+
assert_log QuoVadis::Log::REVOKE do
|
207
|
+
QuoVadis::CurrentRequestDetails.ip = '127.0.0.1' # fake out the IP assertion
|
208
|
+
@account.revoke
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
|
204
213
|
private
|
205
214
|
|
206
215
|
def assert_log(action, metadata = {}, account = @account, &block)
|
@@ -56,7 +56,7 @@ class PasswordResetTest < IntegrationTest
|
|
56
56
|
put quo_vadis.password_reset_path(extract_token_from_email, password: {password: 'xxxxxxxxxxxx', password_confirmation: 'xxxxxxxxxxxx'})
|
57
57
|
assert controller.logged_in?
|
58
58
|
|
59
|
-
get quo_vadis.
|
59
|
+
get quo_vadis.password_reset_url(extract_token_from_email)
|
60
60
|
assert_redirected_to quo_vadis.new_password_reset_path
|
61
61
|
assert_equal 'Either the link has expired or you have already reset your password.', flash[:alert]
|
62
62
|
end
|
data/test/mailers/mailer_test.rb
CHANGED
@@ -44,14 +44,16 @@ class MailerTest < ActionMailer::TestCase
|
|
44
44
|
|
45
45
|
|
46
46
|
test 'email change notification' do
|
47
|
-
email = QuoVadis::Mailer.with(
|
47
|
+
email = QuoVadis::Mailer.with(
|
48
|
+
email: 'Foo <foo@example.com>',
|
49
|
+
ip: '1.2.3.4',
|
50
|
+
timestamp: Time.now
|
51
|
+
).email_change_notification
|
48
52
|
|
49
53
|
# freeze_time
|
50
54
|
|
51
55
|
assert_emails 1 do
|
52
|
-
|
53
|
-
email.deliver_now
|
54
|
-
end
|
56
|
+
email.deliver_now
|
55
57
|
end
|
56
58
|
|
57
59
|
assert_equal ['foo@example.com'], email.to
|
@@ -62,14 +64,17 @@ class MailerTest < ActionMailer::TestCase
|
|
62
64
|
|
63
65
|
|
64
66
|
test 'identifier change notification' do
|
65
|
-
email = QuoVadis::Mailer.with(
|
67
|
+
email = QuoVadis::Mailer.with(
|
68
|
+
email: 'Foo <foo@example.com>',
|
69
|
+
identifier: 'email',
|
70
|
+
ip: '1.2.3.4',
|
71
|
+
timestamp: Time.now
|
72
|
+
).identifier_change_notification
|
66
73
|
|
67
74
|
# freeze_time
|
68
75
|
|
69
76
|
assert_emails 1 do
|
70
|
-
|
71
|
-
email.deliver_now
|
72
|
-
end
|
77
|
+
email.deliver_now
|
73
78
|
end
|
74
79
|
|
75
80
|
assert_equal ['foo@example.com'], email.to
|
@@ -80,14 +85,16 @@ class MailerTest < ActionMailer::TestCase
|
|
80
85
|
|
81
86
|
|
82
87
|
test 'password change notification' do
|
83
|
-
email = QuoVadis::Mailer.with(
|
88
|
+
email = QuoVadis::Mailer.with(
|
89
|
+
email: 'Foo <foo@example.com>',
|
90
|
+
ip: '1.2.3.4',
|
91
|
+
timestamp: Time.now
|
92
|
+
).password_change_notification
|
84
93
|
|
85
94
|
# freeze_time
|
86
95
|
|
87
96
|
assert_emails 1 do
|
88
|
-
|
89
|
-
email.deliver_now
|
90
|
-
end
|
97
|
+
email.deliver_now
|
91
98
|
end
|
92
99
|
|
93
100
|
assert_equal ['foo@example.com'], email.to
|
@@ -98,14 +105,16 @@ class MailerTest < ActionMailer::TestCase
|
|
98
105
|
|
99
106
|
|
100
107
|
test 'password reset notification' do
|
101
|
-
email = QuoVadis::Mailer.with(
|
108
|
+
email = QuoVadis::Mailer.with(
|
109
|
+
email: 'Foo <foo@example.com>',
|
110
|
+
ip: '1.2.3.4',
|
111
|
+
timestamp: Time.now
|
112
|
+
).password_reset_notification
|
102
113
|
|
103
114
|
# freeze_time
|
104
115
|
|
105
116
|
assert_emails 1 do
|
106
|
-
|
107
|
-
email.deliver_now
|
108
|
-
end
|
117
|
+
email.deliver_now
|
109
118
|
end
|
110
119
|
|
111
120
|
assert_equal ['foo@example.com'], email.to
|
@@ -116,14 +125,16 @@ class MailerTest < ActionMailer::TestCase
|
|
116
125
|
|
117
126
|
|
118
127
|
test 'totp setup notification' do
|
119
|
-
email = QuoVadis::Mailer.with(
|
128
|
+
email = QuoVadis::Mailer.with(
|
129
|
+
email: 'Foo <foo@example.com>',
|
130
|
+
ip: '1.2.3.4',
|
131
|
+
timestamp: Time.now
|
132
|
+
).totp_setup_notification
|
120
133
|
|
121
134
|
# freeze_time
|
122
135
|
|
123
136
|
assert_emails 1 do
|
124
|
-
|
125
|
-
email.deliver_now
|
126
|
-
end
|
137
|
+
email.deliver_now
|
127
138
|
end
|
128
139
|
|
129
140
|
assert_equal ['foo@example.com'], email.to
|
@@ -134,14 +145,16 @@ class MailerTest < ActionMailer::TestCase
|
|
134
145
|
|
135
146
|
|
136
147
|
test 'totp reuse notification' do
|
137
|
-
email = QuoVadis::Mailer.with(
|
148
|
+
email = QuoVadis::Mailer.with(
|
149
|
+
email: 'Foo <foo@example.com>',
|
150
|
+
ip: '1.2.3.4',
|
151
|
+
timestamp: Time.now
|
152
|
+
).totp_reuse_notification
|
138
153
|
|
139
154
|
# freeze_time
|
140
155
|
|
141
156
|
assert_emails 1 do
|
142
|
-
|
143
|
-
email.deliver_now
|
144
|
-
end
|
157
|
+
email.deliver_now
|
145
158
|
end
|
146
159
|
|
147
160
|
assert_equal ['foo@example.com'], email.to
|
@@ -152,14 +165,16 @@ class MailerTest < ActionMailer::TestCase
|
|
152
165
|
|
153
166
|
|
154
167
|
test '2fa deactivated notification' do
|
155
|
-
email = QuoVadis::Mailer.with(
|
168
|
+
email = QuoVadis::Mailer.with(
|
169
|
+
email: 'Foo <foo@example.com>',
|
170
|
+
ip: '1.2.3.4',
|
171
|
+
timestamp: Time.now
|
172
|
+
).twofa_deactivated_notification
|
156
173
|
|
157
174
|
# freeze_time
|
158
175
|
|
159
176
|
assert_emails 1 do
|
160
|
-
|
161
|
-
email.deliver_now
|
162
|
-
end
|
177
|
+
email.deliver_now
|
163
178
|
end
|
164
179
|
|
165
180
|
assert_equal ['foo@example.com'], email.to
|
@@ -170,14 +185,16 @@ class MailerTest < ActionMailer::TestCase
|
|
170
185
|
|
171
186
|
|
172
187
|
test 'recovery codes generation notification' do
|
173
|
-
email = QuoVadis::Mailer.with(
|
188
|
+
email = QuoVadis::Mailer.with(
|
189
|
+
email: 'Foo <foo@example.com>',
|
190
|
+
ip: '1.2.3.4',
|
191
|
+
timestamp: Time.now
|
192
|
+
).recovery_codes_generation_notification
|
174
193
|
|
175
194
|
# freeze_time
|
176
195
|
|
177
196
|
assert_emails 1 do
|
178
|
-
|
179
|
-
email.deliver_now
|
180
|
-
end
|
197
|
+
email.deliver_now
|
181
198
|
end
|
182
199
|
|
183
200
|
assert_equal ['foo@example.com'], email.to
|
data/test/models/account_test.rb
CHANGED
@@ -13,8 +13,11 @@ class AccountTest < ActiveSupport::TestCase
|
|
13
13
|
|
14
14
|
|
15
15
|
test 'notifies on identifier change when notifier is not email' do
|
16
|
+
freeze_time
|
16
17
|
p = Person.create! username: 'bob', email: 'bob@example.com', password: 'secretsecret'
|
17
|
-
assert_enqueued_email_with QuoVadis::Mailer,
|
18
|
+
assert_enqueued_email_with QuoVadis::Mailer,
|
19
|
+
:identifier_change_notification,
|
20
|
+
args: {email: 'bob@example.com', identifier: 'username', ip: nil, timestamp: Time.now} do
|
18
21
|
assert_enqueued_emails 1 do
|
19
22
|
p.update username: 'robert@example.com'
|
20
23
|
end
|
@@ -23,12 +26,31 @@ class AccountTest < ActiveSupport::TestCase
|
|
23
26
|
|
24
27
|
|
25
28
|
test 'does not notify on identifier change when notifier is email' do
|
29
|
+
freeze_time
|
26
30
|
u = User.create! name: 'bob', email: 'bob@example.com', password: '123456789abc'
|
27
|
-
assert_enqueued_email_with QuoVadis::Mailer,
|
31
|
+
assert_enqueued_email_with QuoVadis::Mailer,
|
32
|
+
:email_change_notification,
|
33
|
+
args: {email: 'bob@example.com', ip: nil, timestamp: Time.now} do
|
28
34
|
assert_enqueued_emails 1 do
|
29
35
|
u.update email: 'robert@example.com'
|
30
36
|
end
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
40
|
+
|
41
|
+
test 'revoke' do
|
42
|
+
u = User.create! name: 'bob', email: 'bob@example.com', password: '123456789abc'
|
43
|
+
account = u.qv_account
|
44
|
+
account.create_totp last_used_at: 1.minute.ago
|
45
|
+
account.generate_recovery_codes
|
46
|
+
|
47
|
+
u.revoke_authentication_credentials
|
48
|
+
account.reload
|
49
|
+
|
50
|
+
assert_nil account.password
|
51
|
+
assert_nil account.totp
|
52
|
+
assert_empty account.recovery_codes
|
53
|
+
assert_empty account.sessions
|
54
|
+
end
|
55
|
+
|
34
56
|
end
|
data/test/models/model_test.rb
CHANGED
@@ -58,8 +58,11 @@ class ModelTest < ActiveSupport::TestCase
|
|
58
58
|
|
59
59
|
|
60
60
|
test 'notifies on email change' do
|
61
|
+
freeze_time
|
61
62
|
u = User.create! name: 'bob', email: 'bob@example.com', password: '123456789abc'
|
62
|
-
assert_enqueued_email_with QuoVadis::Mailer,
|
63
|
+
assert_enqueued_email_with QuoVadis::Mailer,
|
64
|
+
:email_change_notification,
|
65
|
+
args: {email: 'bob@example.com', ip: nil, timestamp: Time.now} do
|
63
66
|
u.update email: 'robert@example.com'
|
64
67
|
end
|
65
68
|
end
|
@@ -120,6 +120,19 @@ class PasswordTest < ActiveSupport::TestCase
|
|
120
120
|
end
|
121
121
|
|
122
122
|
|
123
|
+
test 'passwords can only be updated via #change and #reset' do
|
124
|
+
user = User.create! name: 'bob', email: 'bob@example.com', password: VALID_PASSWORD
|
125
|
+
pw = user.qv_account.password
|
126
|
+
|
127
|
+
refute pw.update password: 'secretsecret'
|
128
|
+
assert_equal ["must be updated via #change or #reset"], pw.errors[:password]
|
129
|
+
|
130
|
+
pw.password = VALID_PASSWORD
|
131
|
+
refute pw.save
|
132
|
+
assert_equal ["must be updated via #change or #reset"], pw.errors[:password]
|
133
|
+
end
|
134
|
+
|
135
|
+
|
123
136
|
test 'cascade destroy' do
|
124
137
|
user = User.create! name: 'bob', email: 'bob@example.com', password: VALID_PASSWORD
|
125
138
|
assert user.qv_account.persisted?
|
@@ -42,13 +42,19 @@ class RecoveryCodeTest < ActiveSupport::TestCase
|
|
42
42
|
test 'generate a fresh set of codes' do
|
43
43
|
account = @user.qv_account
|
44
44
|
codes = []
|
45
|
-
assert_difference 'QuoVadis::RecoveryCode.count', 5 do
|
45
|
+
assert_difference 'QuoVadis::RecoveryCode.count', (-1 + 5) do
|
46
46
|
codes = account.generate_recovery_codes
|
47
47
|
end
|
48
48
|
assert_equal 5, codes.length
|
49
|
+
assert_equal 5, account.recovery_codes.count
|
49
50
|
codes.each do |code|
|
50
51
|
assert_instance_of String, code
|
51
52
|
end
|
53
|
+
|
54
|
+
new_codes = account.generate_recovery_codes
|
55
|
+
assert_equal 5, new_codes.length
|
56
|
+
assert_equal 5, account.recovery_codes.count
|
57
|
+
refute_equal new_codes, codes
|
52
58
|
end
|
53
59
|
|
54
60
|
end
|
data/test/models/token_test.rb
CHANGED
@@ -52,7 +52,7 @@ class TokenTest < ActiveSupport::TestCase
|
|
52
52
|
|
53
53
|
test 'password reset already done' do
|
54
54
|
token = QuoVadis::PasswordResetToken.generate @account
|
55
|
-
@account.password.
|
55
|
+
@account.password.reset 'secretsecret', 'secretsecret'
|
56
56
|
assert_nil QuoVadis::PasswordResetToken.find_account(token)
|
57
57
|
end
|
58
58
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quo_vadis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Stewart
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -97,6 +97,32 @@ files:
|
|
97
97
|
- app/models/quo_vadis/session.rb
|
98
98
|
- app/models/quo_vadis/token.rb
|
99
99
|
- app/models/quo_vadis/totp.rb
|
100
|
+
- app/views/quo_vadis/confirmations/edit.html.erb
|
101
|
+
- app/views/quo_vadis/confirmations/edit_email.html.erb
|
102
|
+
- app/views/quo_vadis/confirmations/index.html.erb
|
103
|
+
- app/views/quo_vadis/confirmations/new.html.erb
|
104
|
+
- app/views/quo_vadis/logs/index.html.erb
|
105
|
+
- app/views/quo_vadis/mailer/account_confirmation.text.erb
|
106
|
+
- app/views/quo_vadis/mailer/email_change_notification.text.erb
|
107
|
+
- app/views/quo_vadis/mailer/identifier_change_notification.text.erb
|
108
|
+
- app/views/quo_vadis/mailer/password_change_notification.text.erb
|
109
|
+
- app/views/quo_vadis/mailer/password_reset_notification.text.erb
|
110
|
+
- app/views/quo_vadis/mailer/recovery_codes_generation_notification.text.erb
|
111
|
+
- app/views/quo_vadis/mailer/reset_password.text.erb
|
112
|
+
- app/views/quo_vadis/mailer/totp_reuse_notification.text.erb
|
113
|
+
- app/views/quo_vadis/mailer/totp_setup_notification.text.erb
|
114
|
+
- app/views/quo_vadis/mailer/twofa_deactivated_notification.text.erb
|
115
|
+
- app/views/quo_vadis/password_resets/edit.html.erb
|
116
|
+
- app/views/quo_vadis/password_resets/index.html.erb
|
117
|
+
- app/views/quo_vadis/password_resets/new.html.erb
|
118
|
+
- app/views/quo_vadis/passwords/edit.html.erb
|
119
|
+
- app/views/quo_vadis/recovery_codes/challenge.html.erb
|
120
|
+
- app/views/quo_vadis/recovery_codes/index.html.erb
|
121
|
+
- app/views/quo_vadis/sessions/index.html.erb
|
122
|
+
- app/views/quo_vadis/sessions/new.html.erb
|
123
|
+
- app/views/quo_vadis/totps/challenge.html.erb
|
124
|
+
- app/views/quo_vadis/totps/new.html.erb
|
125
|
+
- app/views/quo_vadis/twofas/show.html.erb
|
100
126
|
- bin/console
|
101
127
|
- bin/rails
|
102
128
|
- bin/setup
|
@@ -131,32 +157,6 @@ files:
|
|
131
157
|
- test/dummy/app/views/articles/secret.html.erb
|
132
158
|
- test/dummy/app/views/articles/very_secret.html.erb
|
133
159
|
- test/dummy/app/views/layouts/application.html.erb
|
134
|
-
- test/dummy/app/views/quo_vadis/confirmations/edit.html.erb
|
135
|
-
- test/dummy/app/views/quo_vadis/confirmations/edit_email.html.erb
|
136
|
-
- test/dummy/app/views/quo_vadis/confirmations/index.html.erb
|
137
|
-
- test/dummy/app/views/quo_vadis/confirmations/new.html.erb
|
138
|
-
- test/dummy/app/views/quo_vadis/logs/index.html.erb
|
139
|
-
- test/dummy/app/views/quo_vadis/mailer/account_confirmation.text.erb
|
140
|
-
- test/dummy/app/views/quo_vadis/mailer/email_change_notification.text.erb
|
141
|
-
- test/dummy/app/views/quo_vadis/mailer/identifier_change_notification.text.erb
|
142
|
-
- test/dummy/app/views/quo_vadis/mailer/password_change_notification.text.erb
|
143
|
-
- test/dummy/app/views/quo_vadis/mailer/password_reset_notification.text.erb
|
144
|
-
- test/dummy/app/views/quo_vadis/mailer/recovery_codes_generation_notification.text.erb
|
145
|
-
- test/dummy/app/views/quo_vadis/mailer/reset_password.text.erb
|
146
|
-
- test/dummy/app/views/quo_vadis/mailer/totp_reuse_notification.text.erb
|
147
|
-
- test/dummy/app/views/quo_vadis/mailer/totp_setup_notification.text.erb
|
148
|
-
- test/dummy/app/views/quo_vadis/mailer/twofa_deactivated_notification.text.erb
|
149
|
-
- test/dummy/app/views/quo_vadis/password_resets/edit.html.erb
|
150
|
-
- test/dummy/app/views/quo_vadis/password_resets/index.html.erb
|
151
|
-
- test/dummy/app/views/quo_vadis/password_resets/new.html.erb
|
152
|
-
- test/dummy/app/views/quo_vadis/passwords/edit.html.erb
|
153
|
-
- test/dummy/app/views/quo_vadis/recovery_codes/challenge.html.erb
|
154
|
-
- test/dummy/app/views/quo_vadis/recovery_codes/index.html.erb
|
155
|
-
- test/dummy/app/views/quo_vadis/sessions/index.html.erb
|
156
|
-
- test/dummy/app/views/quo_vadis/sessions/new.html.erb
|
157
|
-
- test/dummy/app/views/quo_vadis/totps/challenge.html.erb
|
158
|
-
- test/dummy/app/views/quo_vadis/totps/new.html.erb
|
159
|
-
- test/dummy/app/views/quo_vadis/twofas/show.html.erb
|
160
160
|
- test/dummy/app/views/sign_ups/new.html.erb
|
161
161
|
- test/dummy/app/views/sign_ups/show.html.erb
|
162
162
|
- test/dummy/app/views/users/new.html.erb
|
@@ -224,7 +224,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
224
|
- !ruby/object:Gem::Version
|
225
225
|
version: '0'
|
226
226
|
requirements: []
|
227
|
-
rubygems_version: 3.1.
|
227
|
+
rubygems_version: 3.1.2
|
228
228
|
signing_key:
|
229
229
|
specification_version: 4
|
230
230
|
summary: Multifactor authentication for Rails 6.
|