quo_vadis 1.4.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +11 -7
  3. data/CHANGELOG.md +22 -0
  4. data/Gemfile +11 -1
  5. data/LICENSE.txt +21 -0
  6. data/README.md +453 -127
  7. data/Rakefile +15 -9
  8. data/app/controllers/quo_vadis/confirmations_controller.rb +102 -0
  9. data/app/controllers/quo_vadis/logs_controller.rb +20 -0
  10. data/app/controllers/quo_vadis/password_resets_controller.rb +65 -0
  11. data/app/controllers/quo_vadis/passwords_controller.rb +26 -0
  12. data/app/controllers/quo_vadis/recovery_codes_controller.rb +54 -0
  13. data/app/controllers/quo_vadis/sessions_controller.rb +50 -132
  14. data/app/controllers/quo_vadis/totps_controller.rb +72 -0
  15. data/app/controllers/quo_vadis/twofas_controller.rb +26 -0
  16. data/app/mailers/quo_vadis/mailer.rb +73 -0
  17. data/app/models/quo_vadis/account.rb +59 -0
  18. data/app/models/quo_vadis/account_confirmation_token.rb +17 -0
  19. data/app/models/quo_vadis/log.rb +57 -0
  20. data/app/models/quo_vadis/password.rb +52 -0
  21. data/app/models/quo_vadis/password_reset_token.rb +17 -0
  22. data/app/models/quo_vadis/recovery_code.rb +26 -0
  23. data/app/models/quo_vadis/session.rb +55 -0
  24. data/app/models/quo_vadis/token.rb +42 -0
  25. data/app/models/quo_vadis/totp.rb +56 -0
  26. data/bin/console +15 -0
  27. data/bin/rails +21 -0
  28. data/bin/setup +8 -0
  29. data/config/locales/quo_vadis.en.yml +50 -23
  30. data/config/routes.rb +46 -12
  31. data/db/migrate/202102150904_setup.rb +48 -0
  32. data/lib/generators/quo_vadis/install_generator.rb +4 -23
  33. data/lib/quo_vadis.rb +103 -97
  34. data/lib/quo_vadis/controller.rb +228 -0
  35. data/lib/quo_vadis/crypt.rb +43 -0
  36. data/lib/quo_vadis/current_request_details.rb +11 -0
  37. data/lib/quo_vadis/defaults.rb +18 -0
  38. data/lib/quo_vadis/encrypted_type.rb +17 -0
  39. data/lib/quo_vadis/engine.rb +9 -11
  40. data/lib/quo_vadis/hmacable.rb +26 -0
  41. data/lib/quo_vadis/ip_masking.rb +31 -0
  42. data/lib/quo_vadis/model.rb +86 -0
  43. data/lib/quo_vadis/version.rb +3 -1
  44. data/quo_vadis.gemspec +20 -25
  45. data/test/dummy/README.markdown +1 -0
  46. data/test/dummy/Rakefile +2 -6
  47. data/test/dummy/app/controllers/application_controller.rb +0 -1
  48. data/test/dummy/app/controllers/articles_controller.rb +8 -11
  49. data/test/dummy/app/controllers/sign_ups_controller.rb +42 -0
  50. data/test/dummy/app/controllers/users_controller.rb +13 -5
  51. data/test/dummy/app/models/application_record.rb +3 -0
  52. data/test/dummy/app/models/article.rb +2 -1
  53. data/test/dummy/app/models/person.rb +5 -2
  54. data/test/dummy/app/models/user.rb +4 -1
  55. data/test/dummy/app/views/articles/also_secret.html.erb +1 -0
  56. data/test/dummy/app/views/articles/index.html.erb +1 -1
  57. data/test/dummy/app/views/articles/secret.html.erb +1 -0
  58. data/test/dummy/app/views/articles/very_secret.html.erb +2 -0
  59. data/test/dummy/app/views/layouts/application.html.erb +41 -25
  60. data/test/dummy/app/views/quo_vadis/confirmations/edit.html.erb +10 -0
  61. data/test/dummy/app/views/quo_vadis/confirmations/edit_email.html.erb +14 -0
  62. data/test/dummy/app/views/quo_vadis/confirmations/index.html.erb +14 -0
  63. data/test/dummy/app/views/quo_vadis/confirmations/new.html.erb +16 -0
  64. data/test/dummy/app/views/quo_vadis/logs/index.html.erb +28 -0
  65. data/test/dummy/app/views/quo_vadis/mailer/account_confirmation.text.erb +4 -0
  66. data/test/dummy/app/views/quo_vadis/mailer/email_change_notification.text.erb +8 -0
  67. data/test/dummy/app/views/quo_vadis/mailer/identifier_change_notification.text.erb +8 -0
  68. data/test/dummy/app/views/quo_vadis/mailer/password_change_notification.text.erb +8 -0
  69. data/test/dummy/app/views/quo_vadis/mailer/password_reset_notification.text.erb +8 -0
  70. data/test/dummy/app/views/quo_vadis/mailer/recovery_codes_generation_notification.text.erb +8 -0
  71. data/test/dummy/app/views/quo_vadis/mailer/reset_password.text.erb +4 -0
  72. data/test/dummy/app/views/quo_vadis/mailer/totp_reuse_notification.text.erb +6 -0
  73. data/test/dummy/app/views/quo_vadis/mailer/totp_setup_notification.text.erb +8 -0
  74. data/test/dummy/app/views/quo_vadis/mailer/twofa_deactivated_notification.text.erb +8 -0
  75. data/test/dummy/app/views/quo_vadis/password_resets/edit.html.erb +25 -0
  76. data/test/dummy/app/views/quo_vadis/password_resets/index.html.erb +5 -0
  77. data/test/dummy/app/views/quo_vadis/password_resets/new.html.erb +12 -0
  78. data/test/dummy/app/views/quo_vadis/passwords/edit.html.erb +30 -0
  79. data/test/dummy/app/views/quo_vadis/recovery_codes/challenge.html.erb +11 -0
  80. data/test/dummy/app/views/quo_vadis/recovery_codes/index.html.erb +25 -0
  81. data/test/dummy/app/views/quo_vadis/sessions/index.html.erb +26 -0
  82. data/test/dummy/app/views/quo_vadis/sessions/new.html.erb +24 -0
  83. data/test/dummy/app/views/quo_vadis/totps/challenge.html.erb +11 -0
  84. data/test/dummy/app/views/quo_vadis/totps/new.html.erb +17 -0
  85. data/test/dummy/app/views/quo_vadis/twofas/show.html.erb +20 -0
  86. data/test/dummy/app/views/sign_ups/new.html.erb +37 -0
  87. data/test/dummy/app/views/sign_ups/show.html.erb +5 -0
  88. data/test/dummy/app/views/users/new.html.erb +32 -9
  89. data/test/dummy/config.ru +6 -3
  90. data/test/dummy/config/application.rb +18 -9
  91. data/test/dummy/config/boot.rb +3 -9
  92. data/test/dummy/config/database.yml +2 -14
  93. data/test/dummy/config/environment.rb +2 -3
  94. data/test/dummy/config/initializers/quo_vadis.rb +5 -75
  95. data/test/dummy/config/routes.rb +11 -3
  96. data/test/dummy/db/migrate/202102121932_create_users.rb +10 -0
  97. data/test/dummy/db/migrate/202102121935_create_people.rb +10 -0
  98. data/test/dummy/db/schema.rb +80 -21
  99. data/test/fixtures/quo_vadis/mailer/account_confirmation.text +4 -0
  100. data/test/fixtures/quo_vadis/mailer/email_change_notification.text +8 -0
  101. data/test/fixtures/quo_vadis/mailer/identifier_change_notification.text +8 -0
  102. data/test/fixtures/quo_vadis/mailer/password_change_notification.text +8 -0
  103. data/test/fixtures/quo_vadis/mailer/password_reset_notification.text +8 -0
  104. data/test/fixtures/quo_vadis/mailer/recovery_codes_generation_notification.text +8 -0
  105. data/test/fixtures/quo_vadis/mailer/reset_password.text +4 -0
  106. data/test/fixtures/quo_vadis/mailer/totp_reuse_notification.text +6 -0
  107. data/test/fixtures/quo_vadis/mailer/totp_setup_notification.text +8 -0
  108. data/test/fixtures/quo_vadis/mailer/twofa_deactivated_notification.text +8 -0
  109. data/test/integration/account_confirmation_test.rb +145 -0
  110. data/test/integration/controller_test.rb +280 -0
  111. data/test/integration/logging_test.rb +235 -0
  112. data/test/integration/password_change_test.rb +93 -0
  113. data/test/integration/password_login_test.rb +125 -0
  114. data/test/integration/password_reset_test.rb +136 -0
  115. data/test/integration/recovery_codes_test.rb +48 -0
  116. data/test/integration/sessions_test.rb +86 -0
  117. data/test/integration/sign_up_test.rb +26 -12
  118. data/test/integration/totps_test.rb +96 -0
  119. data/test/integration/twofa_test.rb +82 -0
  120. data/test/mailers/mailer_test.rb +200 -0
  121. data/test/models/account_test.rb +34 -0
  122. data/test/models/crypt_test.rb +22 -0
  123. data/test/models/log_test.rb +16 -0
  124. data/test/models/mask_ip_test.rb +27 -0
  125. data/test/models/model_test.rb +66 -0
  126. data/test/models/password_test.rb +163 -0
  127. data/test/models/recovery_code_test.rb +54 -0
  128. data/test/models/session_test.rb +67 -0
  129. data/test/models/token_test.rb +70 -0
  130. data/test/models/totp_test.rb +68 -0
  131. data/test/quo_vadis_test.rb +39 -3
  132. data/test/test_helper.rb +42 -70
  133. metadata +123 -207
  134. data/app/controllers/controller_mixin.rb +0 -109
  135. data/app/mailers/quo_vadis/notifier.rb +0 -30
  136. data/app/models/model_mixin.rb +0 -128
  137. data/lib/generators/quo_vadis/templates/migration.rb.erb +0 -18
  138. data/lib/generators/quo_vadis/templates/quo_vadis.rb.erb +0 -96
  139. data/test/dummy/.gitignore +0 -2
  140. data/test/dummy/app/helpers/application_helper.rb +0 -2
  141. data/test/dummy/app/helpers/articles_helper.rb +0 -2
  142. data/test/dummy/app/views/articles/new.html.erb +0 -11
  143. data/test/dummy/app/views/layouts/sessions.html.erb +0 -3
  144. data/test/dummy/app/views/quo_vadis/notifier/change_password.text.erb +0 -9
  145. data/test/dummy/app/views/quo_vadis/notifier/invite.text.erb +0 -8
  146. data/test/dummy/app/views/sessions/edit.html.erb +0 -11
  147. data/test/dummy/app/views/sessions/forgotten.html.erb +0 -13
  148. data/test/dummy/app/views/sessions/invite.html.erb +0 -31
  149. data/test/dummy/app/views/sessions/new.html.erb +0 -15
  150. data/test/dummy/config/environments/development.rb +0 -26
  151. data/test/dummy/config/environments/production.rb +0 -49
  152. data/test/dummy/config/environments/test.rb +0 -37
  153. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  154. data/test/dummy/config/initializers/inflections.rb +0 -10
  155. data/test/dummy/config/initializers/mime_types.rb +0 -5
  156. data/test/dummy/config/initializers/rack_patch.rb +0 -16
  157. data/test/dummy/config/initializers/secret_token.rb +0 -7
  158. data/test/dummy/config/initializers/session_store.rb +0 -8
  159. data/test/dummy/config/locales/en.yml +0 -5
  160. data/test/dummy/config/locales/quo_vadis.en.yml +0 -21
  161. data/test/dummy/db/migrate/20110124125037_create_users.rb +0 -13
  162. data/test/dummy/db/migrate/20110124131535_create_articles.rb +0 -14
  163. data/test/dummy/db/migrate/20110127094709_add_authentication_to_users.rb +0 -18
  164. data/test/dummy/db/migrate/20111004112209_create_people.rb +0 -13
  165. data/test/dummy/db/migrate/20111004132342_add_authentication_to_people.rb +0 -18
  166. data/test/dummy/public/404.html +0 -26
  167. data/test/dummy/public/422.html +0 -26
  168. data/test/dummy/public/500.html +0 -26
  169. data/test/dummy/public/javascripts/application.js +0 -2
  170. data/test/dummy/public/javascripts/controls.js +0 -965
  171. data/test/dummy/public/javascripts/dragdrop.js +0 -974
  172. data/test/dummy/public/javascripts/effects.js +0 -1123
  173. data/test/dummy/public/javascripts/prototype.js +0 -6001
  174. data/test/dummy/public/javascripts/rails.js +0 -175
  175. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  176. data/test/dummy/script/rails +0 -6
  177. data/test/integration/activation_test.rb +0 -108
  178. data/test/integration/authenticate_test.rb +0 -39
  179. data/test/integration/blocked_test.rb +0 -23
  180. data/test/integration/config_test.rb +0 -118
  181. data/test/integration/cookie_test.rb +0 -67
  182. data/test/integration/csrf_test.rb +0 -41
  183. data/test/integration/forgotten_test.rb +0 -93
  184. data/test/integration/helper_test.rb +0 -18
  185. data/test/integration/locale_test.rb +0 -197
  186. data/test/integration/navigation_test.rb +0 -7
  187. data/test/integration/sign_in_person_test.rb +0 -26
  188. data/test/integration/sign_in_test.rb +0 -24
  189. data/test/integration/sign_out_test.rb +0 -20
  190. data/test/support/integration_case.rb +0 -11
  191. data/test/unit/user_test.rb +0 -75
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9cd2f1cd76d5a11353c01d7644a56b587f4e958c
4
- data.tar.gz: 34586a9d0e1ee196d3a81382e1e5c8cbb4e4052e
2
+ SHA256:
3
+ metadata.gz: aca902d10c618abd2c9c0461aac204236b4ef7565911aafb5bb12dfe1e3b25e1
4
+ data.tar.gz: 3417365d9ca59d5e17a1b28118d3c9ec439b77fb228da9968512786dd3797a12
5
5
  SHA512:
6
- metadata.gz: 24da8db1b59b03a14586e650f88aa0f43f39cf7b7d58f5aa403689a36f9b86a82bfd0bf736364f797c586a94965f40427c371da5d942731bad6e4530d89cb5bc
7
- data.tar.gz: 2b40461150448705b4eaff767c30ab195d322364bc507314a7a73323a98e7e3b64a10116ae317e251b38a5c414c2e04da20337b23ced428c0f9d7c8854fded1f
6
+ metadata.gz: 5ffdeced9bd86b0a64fe21f3491f3ad03cb2098f0687b663ab794c37e278383ad235df856d8a18bf8e73108d602661990992dd033cbc1358849b8824ac25aff6
7
+ data.tar.gz: 59c52478f7a5bc8ee0befe682ee520feec894c6fefe875cc84395e827ae62f9cbf5eb588862cf8eb3888b5b0ba102700b61f5d401156dc9eff893e05307d1787
data/.gitignore CHANGED
@@ -1,8 +1,12 @@
1
- pkg/*
2
- *.gem
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /test/dummy/log/
10
+ /test/dummy/tmp/
11
+ /test/dummy/db/*.sqlite3
3
12
  Gemfile.lock
4
- .bundle
5
- test/dummy/log/*
6
- test/dummy/tmp/*
7
- rdoc/*
8
- NOTES
data/CHANGELOG.md CHANGED
@@ -1,6 +1,28 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## HEAD
5
+
6
+
7
+ ## 2.0.2 (24 May 2021)
8
+
9
+ * Account confirmation: enable updating of email address.
10
+ * Account confirmation: enable direct resending of email.
11
+ * Log unknown identifier in metadata.
12
+
13
+
14
+ ## 2.0.1 (18 May 2021)
15
+
16
+ * Remove Gemfile.lock from repo.
17
+ * Move runtime dependencies into gemspec.
18
+ * Include test files in gem package (so views can be installed).
19
+
20
+
21
+ ## 2.0.0 (14 May 2021)
22
+
23
+ * Total rewrite from scratch.
24
+
25
+
4
26
  ## 1.4.0 (12 October 2016)
5
27
 
6
28
  * Internationalise emails' subject lines.
data/Gemfile CHANGED
@@ -1,3 +1,13 @@
1
- source "http://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in quo_vadis.gemspec
3
6
  gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem 'sqlite3'
11
+ gem 'capybara'
12
+
13
+ # gem "minitest", "~> 5.0"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Andy Stewart
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,211 +1,537 @@
1
- # Quo Vadis?
1
+ # Quo Vadis
2
2
 
3
- Quo Vadis adds simple username/password authentication to Rails 3 applications.
3
+ Multifactor authentication for your Rails 6 app.
4
4
 
5
- Why bother with yet another authentication gem? Well, I find all the others over-engineered. Code should be easy to use and easy to read. As far as I'm concerned, none of the others ticks both boxes.
5
+ Designed in accordance with the [OWASP Application Security Verification Standard](https://owasp.org/www-project-application-security-verification-standard/) and relevant [OWASP Cheatsheets](https://cheatsheetseries.owasp.org).
6
6
 
7
- Features:
7
+ Simple to integrate into your application. The main task is customising the example views' markup to match your look-and-feel.
8
8
 
9
- * Minimal effort to add authentication to your app: get up and running in 5 minutes.
10
- * No surprises: it does what you expect.
11
- * Easy to customise.
12
- * Uses BCrypt to encrypt passwords.
13
- * Sign in, sign out, forgotten password, authenticate actions, remember user between browser sessions, user activation.
14
- * Block accounts.
15
- * Let you choose which model(s) to authenticate (defaults to `User`).
16
9
 
17
- Forthcoming features:
10
+ ## Features
18
11
 
19
- * Generate the views for you (for now, copy the examples given below).
20
- * Let you choose the identification field (currently `username`).
21
- * HTTP basic/digest authentication (probably).
22
- * Generate model plus migration if it doesn't exist.
23
- * Detect presence of `has_secure_password` (see below) and adapt appropriately.
12
+ ### General features
24
13
 
25
- What it doesn't and won't do:
14
+ - Works with any model, e.g. `User` or `Person`.
15
+ - Works with any identifier, e.g. `:username` or `:email`.
16
+ - Minimal footprint in your models and controllers.
17
+ - Does not touch your existing database tables.
18
+ - Secrets (password, TOTP secret, 2FA recovery codes) are encrypted at rest.
26
19
 
27
- * Authorisation.
28
- * Work outside Rails 3.
29
- * OpenID, OAuth, LDAP, CAS, etc.
30
- * Separate identity from authentication services (cf OmniAuth).
31
- * Allow you to have multiple models/scope signed in simultaneously (cf Devise).
32
- * Offer so much flexibility that it takes more than 10 minutes to wrap your head around it (cf Devise, Authlogic).
20
+ ### Authentication features
33
21
 
22
+ - Authentication by password.
23
+ - Two-factor authentication (2FA) by TOTP with recovery codes as a backup factor. Can be optional or mandatory.
24
+ - Change password.
25
+ - Reset password.
26
+ - Account confirmation (optional).
27
+ - Tokens (account confirmation, password reset), TOTPs, and recovery codes are all one-time-only.
28
+ - Sessions expired after lifetime or idle time exceeded.
29
+ - Session replaced after any privilege change.
30
+ - View active sessions, log out of any of them.
31
+ - Email-notifications of updates to authentication details.
32
+ - Audit trail.
34
33
 
35
- ## Quick Start
36
34
 
37
- If this takes you more than 5 minutes, you can have your money back ;)
35
+ ## Installation
38
36
 
39
- Install and run the generator: add `gem 'quo_vadis'` to your Gemfile, run `bundle install`, then `rails generate quo_vadis:install [MODEL_NAME]` (where model name is optional and defaults to `User`).
37
+ Add the gem to your Gemfile:
40
38
 
41
- Edit and run the generated migration to add the authentication columns: `rake db:migrate`. Note the migration (currently) assumes you already have a table for your model.
39
+ ```ruby
40
+ gem 'quo_vadis', '~> 2.0'
41
+ ```
42
42
 
43
- In your `User` (or whichever) model, add `authenticates`:
43
+ Then run `bundle install`.
44
44
 
45
- class User < ActiveRecord::Base
46
- authenticates
47
- end
45
+ Next, add the database tables:
48
46
 
49
- Note Quo Vadis validates the presence and uniqueness of the username, and the presence of the password, but it's up to you to add any other validations you want.
47
+ ```
48
+ rails quo_vadis:install:migrations && rails db:migrate
49
+ ```
50
50
 
51
- Use `:authenticate` in a `before_filter` to protect your controllers' actions. For example:
51
+ All the database tables are prefixed with `qv_`.
52
52
 
53
- class ArticlesController < ActionController::Base
54
- before_filter :authenticate, :except => [:index, :show]
55
- end
53
+ Finally, copy the example views across:
56
54
 
57
- Write the sign-in view. Your sign-in form must:
55
+ ```
56
+ rails generate quo_vadis:install
57
+ ```
58
58
 
59
- * be in `app/views/sessions/new.html.:format`
60
- * POST the parameters `:username` and `:password` to `sign_in_url`
61
59
 
62
- You have to write the view yourself because you'd inevitably want to change whatever markup I generated for you. You can find an example in the [test app](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/sessions/new.html.erb).
60
+ ## Usage
63
61
 
64
- Remember to serve your sign in form over HTTPS -- to avoid [the credentials being stolen](http://blog.jgc.org/2011/01/code-injected-to-steal-passwords-in.html).
65
62
 
66
- In your layout, use `current_user` to retrieve the signed-in user; and `sign_in_path`, `sign_out_path`, and `forgotten_sign_in_path` as appropriate. You can also use `authenticated?`.
63
+ ### Model
67
64
 
65
+ Your model must have an `:email` attribute. All authentication-related emails will be sent to this address.
68
66
 
69
- ## Forgotten Password
67
+ Your model must have an identifier, e.g. `:email` (default) or `:username`, with a uniqueness validation.
70
68
 
71
- Here's the workflow:
69
+ All you need do is add a call to `authenticates`, somewhere after your identifier's uniqueness validation.
72
70
 
73
- 1. [Sign in page] The user clicks the "I've forgotten my password" link.
74
- 2. [Forgotten password page] The user enters their username in the form and submits it.
75
- 3. Quo Vadis emails the user a message with a change-password link. The link is valid for 3 hours.
76
- 4. [The email] The user clicks the link.
77
- 5. [Change password page] The user types in a new password and saves it.
78
- 6. Quo Vadis changes the user's password and signs the user in.
71
+ For example, let's say you have a `User` model and the identifier is `:email`:
79
72
 
80
- It'll take you about 5 minutes to implement this.
73
+ ```ruby
74
+ class User < ApplicationRecord
75
+ validates :email, uniqueness: {case_sensitive: false}
76
+ authenticates
77
+ end
78
+ ```
81
79
 
82
- On your sign-in page, link to the forgotten-password view at `forgotten_sign_in_url`.
80
+ If instead you had a `Person` model with a `:username` identifier:
83
81
 
84
- Write the forgotten-password view ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/sessions/forgotten.html.erb)). The form must:
82
+ ```ruby
83
+ class Person < ApplicationRecord
84
+ validates :username, uniqueness: {case_sensitive: false}
85
+ authenticates identifier: :username
86
+ end
87
+ ```
85
88
 
86
- * be in `app/views/sessions/forgotten.html.:format`
87
- * POST the parameter `:username` to `forgotten_sign_in_url`
89
+ When __creating__ a model instance, include a `:password` attribute and, optionally, `:password_confirmation` attribute.
88
90
 
89
- Now write the mailer view, i.e. the email which will be sent to your forgetful users ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/notifier/change_password.text.erb)). The view must:
91
+ When __updating__ a model instance, do not include a `:password` attribute. To change someone's password, use the Change Password feature (see below).
90
92
 
91
- * be at `app/views/quo_vadis/notifier/change_password.text.erb`
92
- * render `@url` somewhere (this is the link the user clicks to go to the change-password page)
93
+ The minimum password length is configured by `QuoVadis.password_minimum_length` (12 by default).
93
94
 
94
- You can also refer to `@username` in the email view.
95
95
 
96
- Configure the email's from address in `config/initializers/quo_vadis.rb`.
96
+ ### Controllers
97
97
 
98
- Configure the default host so ActionMailer can generate the URL. In `config/environments/<env>.rb`:
98
+ You can use these methods in your controllers.
99
99
 
100
- config.action_mailer.default_url_options = {:host => 'yourdomain.com'}
100
+ __`require_password_authentication`__
101
101
 
102
- Finally, write the change-password page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/sessions/edit.html.erb)). The form must:
102
+ Use this to restrict actions to password-authenticated users. It is aliased to `:require_authentication` for convenience.
103
103
 
104
- * be in `app/views/sessions/edit.html.:format`
105
- * PUT the parameter `:password` to `change_password_url(params[:token])`
104
+ ```ruby
105
+ class FoosController < ApplicationController
106
+ before_action :require_password_authentication
107
+ end
108
+ ```
106
109
 
110
+ __`require_two_factor_authentication`__
107
111
 
108
- ## Sign up (directly, without activation)
112
+ Use this to restrict actions to users authenticated with both a password and a second factor. (You do not need to use `:require_password_authentication` for these actions.)
109
113
 
110
- When you create a user, you need to sign them in. Do this by calling `sign_in(user)` in your controller. For example:
114
+ ```ruby
115
+ class BarsController < ApplicationController
116
+ before_action :require_two_factor_authentication
117
+ end
118
+ ```
111
119
 
112
- # In your app
113
- class UsersController < ApplicationController
114
- def create
115
- @user = User.new params[:user]
116
- if @user.save
117
- sign_in @user # <-- NOTE: sign in your user here
118
- else
119
- render 'new'
120
- end
121
- end
122
- end
120
+ __`login(model, browser_session = true)`__
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).
123
+
124
+ __`request_confirmation(model)`__
125
+
126
+ This is used to sent an account confirmation email to the user. See the Account Confirmation feature below for details.
127
+
128
+ __`authenticated_model`__
129
+
130
+ Call this to get the authenticated user. Feel free to alias this to `:current_user` or set it into an `ActiveSupport::CurrentAttributes` class.
131
+
132
+ Available in controllers and views.
133
+
134
+ __`logged_in?`__
135
+
136
+ Call this to find out whether a user has authenticated with a password.
137
+
138
+ Available in controllers and views.
139
+
140
+
141
+ ### Views
142
+
143
+ You can use `authenticated_model` and `logged_in?` in your views. For example:
123
144
 
124
- The `sign_in(user)` method will redirect the user appropriately (you can configure this in `config/initializers/quo_vadis.rb`), as well as running any sign-in hook you may have defined in the initializer.
145
+ ```erb
146
+ <% if logged_in? %>
147
+ <%= link_to 'My profile', authenticated_model %>
148
+ <% end %>
149
+ ```
125
150
 
151
+ In your own views, you must prefix QuoVadis's routes with `quo_vadis.`. For example:
126
152
 
127
- ## Sign up (with activation)
153
+ ```ruby
154
+ link_to 'Log in', quo_vadis.login_path
155
+ ```
128
156
 
129
- To create a user who must activate their account (via email) before they can sign in, do this:
157
+ When you are customising QuoVadis's views, you must prefix your app's routes with `main_app.`. For example:
130
158
 
131
- # In your app
132
- class UsersController < ApplicationController
133
- def create
134
- @user = User.new_for_activation params[:user] # <-- NOTE: different constructor
135
- if @user.save
136
- QuoVadis::SessionsController.new.invite_to_activate @user # <-- NOTE: email user here
137
- redirect_to root_path, notice: "Emailed sign-in instructions to #{@user.name}" # or whatever
138
- else
139
- render 'new'
140
- end
141
- end
159
+ ```ruby
160
+ link_to 'Home', main_app.root_path
161
+ ```
162
+
163
+
164
+ ## Features
165
+
166
+ The example views show the forms and fields you need. You should only need to adapt the markup to suit your app's appearance.
167
+
168
+ In the snippets below we assume a `User` model whose identifier is `:email`. You can of course use anything you like.
169
+
170
+
171
+ ### Sign up
172
+
173
+ Your new user sign-up form ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/users/new.html.erb)) must include:
174
+
175
+ - a `:password` field;
176
+ - optionally a `:password_confirmation` field;
177
+ - a field for their identifier;
178
+ - an `:email` field if the identifier is not their email.
179
+
180
+ In your controller, use the `#login` method to log in your new user. The optional second argument sets the length of the session (defaults to the browser session) - see the description above in the Controllers section).
181
+
182
+ After logging in the user, redirect them to `qv.path_after_authentication` which resolves to a route named `:after_login`, if you have one, or your root route.
183
+
184
+ ```ruby
185
+ class UsersController < ApplicationController
186
+ def create
187
+ @user = User.new user_params
188
+ if @user.save
189
+ login @user
190
+ redirect_to qv.path_after_authentication
191
+ else
192
+ # ...
142
193
  end
194
+ end
195
+
196
+ private
143
197
 
144
- The user will receive an email with a link which takes them to a page (which you must write) where they can choose a username and password for themselves. When they submit the form their new credentials are stored and they are signed in.
198
+ def user_params
199
+ params.require(:user).permit(:name, :email, :password, :password_confirmation)
200
+ end
201
+ end
202
+ ```
203
+
204
+ ```ruby
205
+ # config/routes.rb
206
+ get '/dashboard', as: 'after_login'
207
+ ```
208
+
209
+
210
+ ### Sign up with account confirmation
145
211
 
146
212
  Here's the workflow:
147
213
 
148
- 1. [New user page, without username/password fields] You or user fills in and submits form.
149
- 2. [Users controller] Create user and invite to activate. See code snippet above.
150
- 3. Quo Vadis emails the user a message with an invitation link. The link is valid for 3 hours.
151
- 4. [The email] The user clicks the link.
152
- 5. [Invitation page] The user fills in their new username and password.
153
- 6. Quo Vadis sets the user's username and password and signs the user in.
214
+ 1. [Sign up page] The user fills in their details.
215
+ 2. [Your controller] Your code tells QuoVadis to email the user a confirmation link. The link is valid for `QuoVadis.account_confirmation_token_lifetime`.
216
+ 3. [The email] The user clicks the link.
217
+ 4. [Account-confirmation confirmation page] The user clicks a button to confirm their account. (This step is to prevent any link prefetching in the user's mail client from confirming them unintentionally.)
218
+ 5. QuoVadis confirms the user's account and logs them in.
219
+
220
+ Your new user sign-up form ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/sign_ups/new.html.erb)) must include:
221
+
222
+ - a `:password` field;
223
+ - optionally a `:password_confirmation` field;
224
+ - a field for their identifier;
225
+ - an `:email` field if the identifier is not their email.
226
+
227
+ In your controller, call `#request_confirmation`:
228
+
229
+ ```ruby
230
+ class UsersController < ApplicationController
231
+ def create
232
+ @user = User.new user_params
233
+ if @user.save
234
+ request_confirmation @user
235
+ redirect_to quo_vadis.confirmations_path # a page where you advise the user to check their email
236
+ else
237
+ # ...
238
+ end
239
+ end
240
+
241
+ private
242
+
243
+ def user_params
244
+ params.require(:user).permit(:name, :email, :password, :password_confirmation)
245
+ end
246
+ end
247
+ ```
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/test/dummy/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
+
251
+ See the Configuration section below for how to set QuoVadis's emails' from addresses, headers, etc.
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/test/dummy/app/views/quo_vadis/confirmations/index.html.erb)). It must be in `app/views/quo_vadis/confirmations/index.html.:format`.
254
+
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
+
257
+ Next, write the page to which the link in the email points ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/confirmations/edit.html.erb)). It must be in `app/views/quo_vadis/confirmations/edit.html.:format`.
258
+
259
+ 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/test/dummy/app/views/quo_vadis/confirmations/new.html.erb)). It must be in `app/views/quo_vadis/confirmations/new.html.:format`.
260
+
261
+ After the user has confirmed their account, they will be logged in and redirected to the first of these that exists:
262
+
263
+ - a route named `:after_login`;
264
+ - your root route.
265
+
266
+ So add whichever works best for you.
267
+
268
+
269
+ ### Login
270
+
271
+ Use `before_action :require_password_authentication` or `before_action :require_authentication` in your controllers.
272
+
273
+ Write the login view ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/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).
274
+
275
+ If you include a `remember` checkbox in your login form:
276
+
277
+ - if the user checks it, they will be logged in for `QuoVadis.session_lifetime`;
278
+ - if the user does not check it, they will be logged in for the browser session.
279
+
280
+ If you do not include a `remember` checkbox, the user will be logged in for `QuoVadis.session_lifetime`.
281
+
282
+ After authenticating the user will be redirected to the first of these that exists:
283
+
284
+ - the page they tried to view before they were redirected to the login page;
285
+ - a route named `after_login`, if any;
286
+ - your root route.
287
+
288
+
289
+ ### Two-factor authentication (2FA) or Two-step verification (2SV)
290
+
291
+ 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.
292
+
293
+ If you do want 2FA, you can choose whether it is optional or mandatory for your users by setting `QuoVadis.two_factor_authentication_mandatory <true|false>` in your configuration.
294
+
295
+ 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.
296
+
297
+ Here's the workflow for a user setting up optional 2FA:
298
+
299
+ 1. User visits their 2FA overview page.
300
+ 2. [2FA overview page] User clicks a link to set up 2FA (TOTP for now).
301
+ 3. [TOTP setup page] User scans the QR code with their authenticator and enters the 6-digit one-time password.
302
+ 4. QuoVadis verifies the one-time password, generates 5 backup recovery codes, and redirects the user to the recovery codes page (or back to step 3 if the OTP is invalid).
303
+ 5. [Recovery code page] User views and hopefully saves their 5 recovery codes.
304
+
305
+ When 2FA is mandatory the workflow starts automatically at step 3 after password authentication.
306
+
307
+ In your views, have a link where users can manage their 2FA:
308
+
309
+ ```ruby
310
+ link_to '2FA', quo_vadis.twofa_path
311
+ ```
312
+
313
+ Write the 2FA overview page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/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.
314
+
315
+ Next, write the TOTP setup page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/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.
154
316
 
155
- It'll take you about 3 minutes to implement this.
317
+ Next, write the recovery codes page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/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.
156
318
 
157
- Update your user controller's `create` action as above.
319
+ Next, write the TOTP challenge page where a user inputs their 6-digit TOTP ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/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.
158
320
 
159
- Write the mailer view, i.e. the email which will be sent to your new users ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/notifier/invite.text.erb)). The view must:
321
+ 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/test/dummy/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.
160
322
 
161
- * be at `app/views/quo_vadis/notifier/invite.text.erb`
162
- * render `@url` somewhere (this is the link the user clicks to go to the invitation page)
163
323
 
164
- You can also refer to `@user` in the email view, as well as any other data you pass to `invite_to_activate`. Note that passing `:from` and/or `:subject` in the hash to `invite_to_activate` overrides the default `QuoVadis.from` and/or `I18n.t('quo_vadis.notifier.invite.subject')` respectively.
324
+ ### Change password
165
325
 
166
- Configure the email's from address in `config/initializers/quo_vadis.rb` (or pass in the data hash to `invite_to_activate`).
326
+ To change their password, the user must provide their current one as well as the new one.
167
327
 
168
- Configure the default host so ActionMailer can generate the URL. In `config/environments/<env>.rb`:
328
+ Write the change-password form ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/passwords/edit.html.erb)). It must be in `app/views/quo_vadis/passwords/edit.html.:format`.
169
329
 
170
- config.action_mailer.default_url_options = {:host => 'yourdomain.com'}
330
+ After the password has been changed, the user is redirected to the first of:
171
331
 
172
- Finally, write the invitation page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/sessions/invite.html.erb)). The form must:
332
+ - your route named `:after_password_change`, if any;
333
+ - your root route.
173
334
 
174
- * be in `app/views/sessions/invite.html.:format`
175
- * POST the parameters `:username` and `:password` to `activation_url(params[:token])`
335
+ A successful password change logs out any other sessions the user has (e.g. on other devices).
176
336
 
177
- If the token expires and you need to generate a new one, re-invite the user with: `invite_to_activate @user`.
178
337
 
338
+ ### Reset password
179
339
 
180
- ## Customisation
340
+ The user can reset their password if they lose it. The flow is:
181
341
 
182
- You can customise the flash messages and mailer from/subject in `config/locales/quo_vadis.en.yml`.
342
+ 1. [Request password-reset page] User enters their identifier (not their email unless the identifier is email).
343
+ 2. QuoVadis emails the user a link. The link is valid for `QuoVadis.password_reset_token_lifetime`.
344
+ 3. [The email] The user clicks the link.
345
+ 4. [Password-reset confirmation page] The user enters their new password and clicks a button.
346
+ 5. QuoVadis sets the user's password and logs them in.
183
347
 
184
- You can customise the sign-in and sign-out redirects in `config/initializers/quo_vadis.rb`; they both default to the root route. You can also hook into the sign-in and sign-out process if you need to run any other code.
348
+ First, write the page where the user requests a password-reset ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/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).
185
349
 
186
- If you want to add other session management type features, go right ahead: create a `SessionsController` as normal and carry on.
350
+ See the Configuration section below for how to set QuoVadis's emails' from addresses, headers, etc.
187
351
 
188
- You can skip the validation of authentication attributes (password etc) by overriding `should_authenticate?` in your model. Perhaps only some of the users should be able to sign in, so you don't want to force them to have a password.
352
+ 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/test/dummy/app/views/quo_vadis/password_resets/index.html.erb)). It must be in `app/views/quo_vadis/password_resets/index.html.:format`.
189
353
 
354
+ 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.
190
355
 
191
- ## See also
356
+ Next, write the page to which the link in the email points ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/password_resets/edit.html.erb)). It must be in `app/views/quo_vadis/password_resets/edit.html.:format`.
357
+
358
+ Finally, write the page where people can put in their identifier (not their email, unless the identifier is email) again to request another password-reset email ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/password_resets/new.html.erb)). It must be in `app/views/quo_vadis/password_resets/new.html.:format`.
359
+
360
+ After the user has reset their password, they will be logged in and redirected to the first of these that exists:
361
+
362
+ - a route named `:after_login`;
363
+ - your root route.
364
+
365
+
366
+ ### Sessions
367
+
368
+ A logged-in session lasts for either the browser session or `QuoVadis.session_lifetime`. As well as having a lifetime, a session will also expire after it has been inactive for `QuoVadis.session_idle_timeout`.
369
+
370
+ A user can view their active sessions and log out of any of them.
371
+
372
+ Write the view showing the sessions ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/sessions/index.html.erb)). It must be in `app/views/quo_vadis/sessions/index.html.:format`.
373
+
374
+
375
+ ### Audit trail
376
+
377
+ 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.
378
+
379
+ Write the view showing the events ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/logs/index.html.erb)). It must be in `app/views/quo_vadis/logs/index.html.:format`.
380
+
381
+
382
+ ### Notifications
383
+
384
+ QuoVadis notifies users by email whenever their authentication details are changed or something suspicious happens.
385
+
386
+ Write the corresponding mailer views:
387
+
388
+ - change of email ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/email_change_notification.text.erb))
389
+ - change of identifier (unless the identifier is email) ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/identifier_change_notification.text.erb))
390
+ - change of password ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/password_change_notification.text.erb))
391
+ - reset of password ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/password_reset_notification.text.erb))
392
+ - TOTP setup ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/totp_setup_notification.text.erb))
393
+ - TOTP code used a second time ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/totp_reuse_notification.text.erb))
394
+ - 2FA deactivated ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/twofa_deactivated_notification.text.erb))
395
+ - recovery codes generated ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/recovery_codes_generation_notification.text.erb))
396
+
397
+ They must be in `app/views/quo_vadis/mailer/NAME.{text,html}.erb`.
398
+
399
+
400
+ ## Configuration
401
+
402
+ This is QuoVadis' [default configuration](https://github.com/airblade/quo_vadis/blob/master/lib/quo_vadis/defaults.rb):
403
+
404
+ ```ruby
405
+ QuoVadis.configure do
406
+ password_minimum_length 12
407
+ mask_ips false
408
+ cookie_name '__Host-qv'
409
+ session_lifetime :session
410
+ session_lifetime_extend_to_end_of_day false
411
+ session_idle_timeout :lifetime
412
+ password_reset_token_lifetime 10.minutes
413
+ accounts_require_confirmation false
414
+ account_confirmation_token_lifetime 10.minutes
415
+ mail_headers ({ from: 'Example App <support@example.com>' })
416
+ enqueue_transactional_emails true
417
+ app_name Rails.app_class.to_s.deconstantize # for the TOTP QR code
418
+ two_factor_authentication_mandatory true
419
+ mount_point '/'
420
+ end
421
+ ```
422
+
423
+ You can override any of it with a similarly structured file in `config/initializers/quo_vadis.rb`.
424
+
425
+ Here are the options in detail:
426
+
427
+ __`password_minimum_length`__ (integer)
428
+
429
+ The minimum number of characters for a password.
430
+
431
+ __`mask_ips`__ (boolean)
432
+
433
+ Whether to mask the IP address in the sessions list and the audit trail.
434
+
435
+ Masking means setting the last octet (IPv4) or the last 80 bits (IPv6) to 0.
436
+
437
+ __`cookie_name`__ (string)
438
+
439
+ The name of the cookie QuoVadis uses to store the session identifier. The `__Host-` prefix is [recommended](https://developer.mozilla.org/en-US/docs/Web/API/document/cookie).
440
+
441
+ __`session_lifetime`__ (`:session` | `ActiveSupport::Duration` | integer)
442
+
443
+ The lifetime of a logged-in session. Use `:session` for the browser session, or a `Duration` or number of seconds.
444
+
445
+ __`session_lifetime_extend_to_end_of_day`__ (boolean)
446
+
447
+ Whether to extend the session's lifetime to the end of the day it will expire on.
448
+
449
+ Set `true` to reduce the chance of a user being logged out while actively using your application.
450
+
451
+ __`session_idle_timeout`__ (`:lifetime` | `ActiveSupport::Duration` | integer)
452
+
453
+ The logged-in session is expired if the user isn't seen for this `Duration` or number of seconds. Use `:lifetime` to set the idle timeout to the session's lifetime (i.e. to turn off the idle timeout).
454
+
455
+ __`password_reset_token_lifetime`__ (`ActiveSupport::Duration` | integer)
456
+
457
+ The `Duration` or number of seconds for which a password-reset token is valid.
458
+
459
+ __`accounts_require_confirmation`__ (boolean)
460
+
461
+ Whether new users must confirm their account before they can log in.
462
+
463
+ __`account_confirmation_token_lifetime`__ (`ActiveSupport::Duration` | integer)
464
+
465
+ The `Duration` or number of seconds for which an account-confirmation token is valid.
466
+
467
+ __`mail_headers`__ (hash)
468
+
469
+ Mail headers which QuoVadis' emails should have.
470
+
471
+ __`enqueue_transactional_emails`__ (boolean)
472
+
473
+ Set `true` if account-confirmation and password-reset emails should be queued for later delivery (`#deliver_later`) or `false` if they should be sent inline (`#deliver_now`).
474
+
475
+ __`app_name`__ (string)
476
+
477
+ Used in the provisioning URI for the TOTP QR code.
478
+
479
+ __`two_factor_authentication_mandatory`__ (boolean)
480
+
481
+ Whether users must set up and use a second authentication factor.
482
+
483
+ __`mount_point`__ (string)
484
+
485
+ The path prefix for QuoVadis's routes.
486
+
487
+ For example, the default login path is at `/login`. If you set `mount_point` to `/auth`, the login path would be `/auth/login`.
488
+
489
+ #### Rails configuration
490
+
491
+ __Mailer URLs__
492
+
493
+ You must also configure the mailer host so URLs are generated correctly in emails:
494
+
495
+ ```ruby
496
+ config.action_mailer.default_url_options: { host: 'example.com' }
497
+ ```
498
+
499
+ __Layouts__
500
+
501
+ You can specify QuoVadis's controllers' layouts in a `#to_prepare` block in your application configuration. For example:
502
+
503
+ ```ruby
504
+ # config/application.rb
505
+ module YourApp
506
+ class Application < Rails::Application
507
+ config.to_prepare do
508
+ QuoVadis::ConfirmationsController.layout 'your_layout'
509
+ end
510
+ end
511
+ end
512
+ ```
192
513
 
193
- * Rails 3 edge's [ActiveModel::SecurePassword](https://github.com/rails/rails/blob/master/activemodel/lib/active_model/secure_password.rb). It's `has_secure_password` class method is similar to Quo Vadis's `authenticates` class method.
194
- * [RailsCast 250: Authentication from Scratch](http://railscasts.com/episodes/250-authentication-from-scratch).
514
+ __Routes__
195
515
 
516
+ You can set up your post-authentication and post-password-change routes. If you don't, you must have a root route. For example:
196
517
 
197
- ## What's up with the name?
518
+ ```ruby
519
+ # config/routes.rb
520
+ get '/dashboard', to: 'dashboards#show', as: 'after_login'
521
+ get '/profile', to: 'profiles#show', as: 'after_password_change'
522
+ ```
198
523
 
199
- Roman sentries used to challenge intruders with, "Halt! Who goes there?"; quo vadis is Latin for "Who goes there?". At least that's what my Latin teacher told us, but I was 8 years old then so I may not be remembering this entirely accurately.
524
+ ### I18n
200
525
 
526
+ All QuoVadis' flash messages are set via [i18n](https://github.com/airblade/quo_vadis/blob/master/config/locales/quo_vadis.en.yml).
201
527
 
202
- ## Questions, Problems, Feedback
528
+ You can override any of the messages with your own locale file at `config/locales/quo_vadis.en.yml`.
203
529
 
204
- Please use the GitHub [issue tracker](https://github.com/airblade/quo_vadis/issues) or email me.
530
+ If you don't want a specific flash message at all, give the key an empty value in your locale file.
205
531
 
206
532
 
207
- ## Intellectual property
533
+ ## Intellectual Property
208
534
 
209
- Copyright 2011 Andy Stewart (boss@airbladesoftware.com).
535
+ Copyright 2011-2021 Andrew Stewart (boss@airbladesoftware.com).
210
536
 
211
537
  Released under the MIT licence.