quo_vadis 2.2.5 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d6a07996a9ca5d95f789060694cf9a1be4d2bc7c8e585f7a60c1e3c883eec1e7
4
- data.tar.gz: 350e447a8897c4af8b0bad19971b23bc7d551ca348d4cb1ae0d6ff713f928883
3
+ metadata.gz: 99defadc14bc4d695dccfad2f131ea6817ae931b1af1a65cc2418a5c3dbe1444
4
+ data.tar.gz: 2585f246fe58c479cee88852a155aa66d1ae4ff3f18f9c353216529a096a1f75
5
5
  SHA512:
6
- metadata.gz: 8461e1e31a53a02073b281d99028b0b25839764746d986e7e3325b5c5e8763d4b34cc48b1ae69064405022341fb76101488dc11f3229e8d0d3afcf236beb02fc
7
- data.tar.gz: 508ebf170a8abe591c8217a68390b9e11ec0204b86412e87b86ead2e84b3e0fcab2886aa22897a2d4266d43370cc42c25938a4e92c3073bf042d695278dff761
6
+ metadata.gz: 04a76b0961a32febb4860656ba4a45faaeec652c3174450393583c3667af51950b55f8c9995b123ee135396c442da607512541d8dd01c6cedbfb279f736085aa
7
+ data.tar.gz: e38c400e9a0151691616e522218954d76347fec42cfa479d240166d8bdae95c75cd00d7e56cb4a92c8ec7da7a53b45b6847b1b942df3043f7ddc49bed1ecef56
data/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@
4
4
  ## HEAD
5
5
 
6
6
 
7
+ ## 2.3.0 (18 November 2025)
8
+
9
+ * Upon confirmation redirect to original path.
10
+ * Remove concept of after_signup route.
11
+ * Enable OTP to be given in i18n mailer subject.
12
+
13
+
14
+ ## 2.2.6 (17 November 2025)
15
+
16
+ * Make permitting of password updates explicit.
17
+ * Feature-detect method rather than module for normalisation.
18
+
19
+
7
20
  ## 2.2.5 (14 April 2025)
8
21
 
9
22
  * Normalise identifier value for lookup.
data/README.md CHANGED
@@ -59,6 +59,8 @@ Finally, copy the example views across:
59
59
  rails generate quo_vadis:install
60
60
  ```
61
61
 
62
+ You may find that you need to eager load your code in development so that your model's / models' `#authenticates` call(s) executes straightaway. This method registers your model(s) with QuoVadis, which needs to happen before you can do any authentication-related things such as reset your password.
63
+
62
64
 
63
65
  ## Usage
64
66
 
@@ -195,15 +197,15 @@ Your new user sign-up form ([example](https://github.com/airblade/quo_vadis/blob
195
197
 
196
198
  In your controller, use the [`#login`](#loginmodel-browser_session--true-metadata-) method to log in your new user. The optional second argument specifies for how long the user should be logged in, and any metadata you supply is logged in the audit log.
197
199
 
198
- After logging in the user, redirect them wherever you like. You can use `qv.path_after_signup` which resolves to the first of these routes that exists: `:after_signup`, `:after_login`, the root route.
200
+ After logging in the user, redirect them wherever you like as normal.
199
201
 
200
202
  ```ruby
201
203
  class UsersController < ApplicationController
202
204
  def create
203
205
  @user = User.new user_params
204
206
  if @user.save
205
- login @user
206
- redirect_to qv.path_after_signup
207
+ login @user # <-- add this
208
+ redirect_to dashboard_path
207
209
  else
208
210
  # ...
209
211
  end
@@ -217,21 +219,15 @@ class UsersController < ApplicationController
217
219
  end
218
220
  ```
219
221
 
220
- ```ruby
221
- # config/routes.rb
222
- get '/dashboard', as: 'after_login'
223
- ```
224
-
225
-
226
222
  ### Sign up with account confirmation
227
223
 
228
224
  Follow the steps above for sign-up.
229
225
 
230
- After you have logged in the user and redirected them (to any page which requires being logged in), QuoVadis detects that they need to confirm their account. QuoVadis emails them a 6-digit confirmation code and redirects them to the confirmation page where they can enter that code.
226
+ After you have logged in the user and redirected them, QuoVadis detects that they need to confirm their account. QuoVadis emails them a 6-digit confirmation code and redirects them to the confirmation page where they can enter that code.
231
227
 
232
228
  The confirmation code is valid for `QuoVadis.account_confirmation_otp_lifetime`.
233
229
 
234
- Once the user has confirmed their account, they will be redirected to `qv.path_after_signup` which resolves to the first of these routes that exists: `:after_signup`, `:after_login`, the root route. Add whichever works best for you.
230
+ Once the user has confirmed their account, they will be redirected to the page they requested before they were redirected to the confirmation page.
235
231
 
236
232
  You need to 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 `@otp` variable. See the [Configuration](#configuration) section for how to set QuoVadis's emails' from addresses, headers, etc.
237
233
 
@@ -553,7 +549,7 @@ get '/profile', to: 'profiles#show', as: 'after_password_change'
553
549
 
554
550
  ### I18n
555
551
 
556
- All QuoVadis' flash messages are set via [i18n](https://github.com/airblade/quo_vadis/blob/master/config/locales/quo_vadis.en.yml).
552
+ All QuoVadis' text (flash messages, mail subjects, and log messages) is set via [i18n](https://github.com/airblade/quo_vadis/blob/master/config/locales/quo_vadis.en.yml).
557
553
 
558
554
  You can override any of the messages with your own locale file at `config/locales/quo_vadis.en.yml`.
559
555
 
@@ -7,7 +7,7 @@ module QuoVadis
7
7
  @account = find_pending_account_from_session
8
8
 
9
9
  unless @account
10
- redirect_to qv.path_after_signup, alert: QuoVadis.translate('flash.confirmation.unknown')
10
+ redirect_to qv.path_after_authentication, alert: QuoVadis.translate('flash.confirmation.unknown')
11
11
  end
12
12
  end
13
13
 
@@ -16,7 +16,7 @@ module QuoVadis
16
16
  @account = find_pending_account_from_session
17
17
 
18
18
  unless @account
19
- redirect_to qv.path_after_signup, alert: QuoVadis.translate('flash.confirmation.unknown')
19
+ redirect_to qv.path_after_authentication, alert: QuoVadis.translate('flash.confirmation.unknown')
20
20
  return
21
21
  end
22
22
 
@@ -39,7 +39,7 @@ module QuoVadis
39
39
  session.delete :account_pending_confirmation
40
40
  session.delete :account_confirmation_expires_at
41
41
 
42
- redirect_to qv.path_after_signup, notice: QuoVadis.translate('flash.confirmation.confirmed')
42
+ redirect_to qv.path_after_authentication, notice: QuoVadis.translate('flash.confirmation.confirmed')
43
43
  end
44
44
 
45
45
 
@@ -47,7 +47,7 @@ module QuoVadis
47
47
  @account = find_pending_account_from_session
48
48
 
49
49
  unless @account
50
- redirect_to qv.path_after_signup, alert: QuoVadis.translate('flash.confirmation.unknown')
50
+ redirect_to qv.path_after_authentication, alert: QuoVadis.translate('flash.confirmation.unknown')
51
51
  end
52
52
 
53
53
  qv.request_confirmation @account.model
@@ -5,12 +5,12 @@ module QuoVadis
5
5
 
6
6
  def reset_password
7
7
  @otp = params[:otp]
8
- _mail params[:email], QuoVadis.translate('mailer.password_reset.subject')
8
+ _mail params[:email], QuoVadis.translate('mailer.password_reset.subject', otp: params[:otp])
9
9
  end
10
10
 
11
11
  def account_confirmation
12
12
  @otp = params[:otp]
13
- _mail params[:email], QuoVadis.translate('mailer.confirmation.subject')
13
+ _mail params[:email], QuoVadis.translate('mailer.confirmation.subject', otp: params[:otp])
14
14
  end
15
15
 
16
16
  def email_change_notification
@@ -7,12 +7,14 @@ 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
+ validate :permitted_update, on: :update
11
11
 
12
12
  attr_accessor :new_password
13
13
 
14
14
 
15
15
  def change(current_plaintext, new_plaintext, new_plaintext_confirmation)
16
+ permit_password_update
17
+
16
18
  unless authenticate current_plaintext
17
19
  errors.add :password, :incorrect
18
20
  return false
@@ -38,6 +40,8 @@ module QuoVadis
38
40
 
39
41
 
40
42
  def reset(new_plaintext, new_plaintext_confirmation)
43
+ permit_password_update
44
+
41
45
  # has_secure_password ignores empty passwords ("") on update so reject them here.
42
46
  if new_plaintext.empty?
43
47
  errors.add :password, :blank
@@ -56,18 +60,19 @@ module QuoVadis
56
60
 
57
61
  private
58
62
 
59
- def password_updated_legitimately
60
- return unless password_digest_changed?
63
+ def permit_password_update
64
+ @permit_password_update = true
65
+ end
61
66
 
62
- unless change_or_reset_called?
63
- errors.add :password, 'must be updated via #change or #reset'
64
- end
67
+ def permit_password_update?
68
+ @permit_password_update
65
69
  end
66
70
 
67
- def change_or_reset_called?
68
- caller_locations.any? { |loc|
69
- ['change', 'reset'].include?(loc.label) && Pathname.new(loc.path).basename.to_s == 'password.rb'
70
- }
71
+ def permitted_update
72
+ return unless password_digest_changed?
73
+ return if permit_password_update?
74
+
75
+ errors.add :password, 'must be updated via #change or #reset'
71
76
  end
72
77
  end
73
78
  end
@@ -35,9 +35,9 @@ en:
35
35
  invalidated: You have invalidated your 2FA credentials and recovery codes.
36
36
  mailer:
37
37
  password_reset:
38
- subject: Change your password
38
+ subject: Your password reset code is %{otp}
39
39
  confirmation:
40
- subject: Please confirm your account
40
+ subject: Your account confirmation code is %{otp}
41
41
  notification:
42
42
  email_change: Your email address has been changed
43
43
  identifier_change: Your %{identifier} has been changed
@@ -34,6 +34,7 @@ module QuoVadis
34
34
  if logged_in?
35
35
  if QuoVadis.accounts_require_confirmation && !authenticated_model.qv_account.confirmed?
36
36
  qv.request_confirmation authenticated_model
37
+ session[:qv_bookmark] = request.original_fullpath
37
38
  redirect_to quo_vadis.confirm_path
38
39
  end
39
40
  return
@@ -217,13 +218,6 @@ module QuoVadis
217
218
  Log.create account: account, action: action, ip: request.remote_ip, metadata: metadata
218
219
  end
219
220
 
220
- def path_after_signup
221
- return main_app.after_signup_path if main_app.respond_to?(:after_signup_path)
222
- return main_app.after_login_path if main_app.respond_to?(:after_login_path)
223
- return main_app.root_path if main_app.respond_to?(:root_path)
224
- raise RuntimeError, 'Missing routes: after_signup_path, after_login_path, root_path; define at least one of them.'
225
- end
226
-
227
221
  def path_after_authentication
228
222
  if (bookmark = rails_session[:qv_bookmark])
229
223
  rails_session.delete :qv_bookmark
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QuoVadis
4
- VERSION = '2.2.5'
4
+ VERSION = '2.3.0'
5
5
  end
data/lib/quo_vadis.rb CHANGED
@@ -53,7 +53,7 @@ module QuoVadis
53
53
  identifier = detect_identifier params.keys
54
54
  value = params[identifier]
55
55
 
56
- return value unless defined?(ActiveRecord::Normalization)
56
+ return value unless ApplicationRecord.respond_to? :normalize_value_for
57
57
 
58
58
  klass = model_of(identifier.to_sym).constantize
59
59
  klass.normalize_value_for(identifier.to_sym, value)
@@ -24,11 +24,6 @@ class SignUpsController < ApplicationController
24
24
  @user = User.find params[:id]
25
25
  end
26
26
 
27
- def confirmed
28
- # Here we could send an email.
29
- redirect_to after_login_path
30
- end
31
-
32
27
  private
33
28
 
34
29
  def user_params
@@ -1,6 +1,5 @@
1
1
  Rails.application.routes.draw do
2
2
  resources :users
3
- get '/sign_ups/confirmed', to: 'sign_ups#confirmed', as: 'after_signup'
4
3
  resources :sign_ups
5
4
  resources :articles do
6
5
  collection do
@@ -30,8 +30,6 @@ class AccountConfirmationTest < IntegrationTest
30
30
  post quo_vadis.confirm_path(otp: code)
31
31
 
32
32
  # verify logged in
33
- assert_redirected_to '/sign_ups/confirmed'
34
- follow_redirect!
35
33
  assert_redirected_to '/articles/secret'
36
34
  assert_equal 'Thanks for confirming your account.', flash[:notice]
37
35
  assert QuoVadis::Account.last.confirmed?
@@ -64,7 +62,7 @@ class AccountConfirmationTest < IntegrationTest
64
62
 
65
63
  post quo_vadis.confirm_path(otp: code)
66
64
  assert_equal 'You have already confirmed your account.', flash[:alert]
67
- assert_redirected_to '/sign_ups/confirmed'
65
+ assert_redirected_to '/articles/secret'
68
66
  end
69
67
 
70
68
 
@@ -21,7 +21,7 @@ class MailerTest < ActionMailer::TestCase
21
21
 
22
22
  assert_equal ['foo@example.com'], email.to
23
23
  assert_equal ['bar@example.com'], email.from
24
- assert_equal 'Change your password', email.subject
24
+ assert_equal 'Your password reset code is 314159', email.subject
25
25
  assert_equal read_fixture('reset_password.text').join, email.body.to_s
26
26
  end
27
27
 
@@ -38,7 +38,7 @@ class MailerTest < ActionMailer::TestCase
38
38
 
39
39
  assert_equal ['foo@example.com'], email.to
40
40
  assert_equal ['bar@example.com'], email.from
41
- assert_equal 'Please confirm your account', email.subject
41
+ assert_equal 'Your account confirmation code is 271828', email.subject
42
42
  assert_equal read_fixture('account_confirmation.text').join, email.body.to_s
43
43
  end
44
44
 
@@ -17,7 +17,7 @@ class AccountTest < ActiveSupport::TestCase
17
17
  p = Person.create! username: 'bob', email: 'bob@example.com', password: 'secretsecret'
18
18
  assert_enqueued_email_with QuoVadis::Mailer,
19
19
  :identifier_change_notification,
20
- args: {email: 'bob@example.com', identifier: 'username', ip: nil, timestamp: Time.now} do
20
+ params: {email: 'bob@example.com', identifier: 'username', ip: nil, timestamp: Time.now} do
21
21
  assert_enqueued_emails 1 do
22
22
  p.update username: 'robert@example.com'
23
23
  end
@@ -30,7 +30,7 @@ class AccountTest < ActiveSupport::TestCase
30
30
  u = User.create! name: 'bob', email: 'bob@example.com', password: '123456789abc'
31
31
  assert_enqueued_email_with QuoVadis::Mailer,
32
32
  :email_change_notification,
33
- args: {email: 'bob@example.com', ip: nil, timestamp: Time.now} do
33
+ params: {email: 'bob@example.com', ip: nil, timestamp: Time.now} do
34
34
  assert_enqueued_emails 1 do
35
35
  u.update email: 'robert@example.com'
36
36
  end
@@ -63,7 +63,7 @@ class ModelTest < ActiveSupport::TestCase
63
63
  u = User.create! name: 'bob', email: 'bob@example.com', password: '123456789abc'
64
64
  assert_enqueued_email_with QuoVadis::Mailer,
65
65
  :email_change_notification,
66
- args: {email: 'bob@example.com', ip: nil, timestamp: Time.now} do
66
+ params: {email: 'bob@example.com', ip: nil, timestamp: Time.now} do
67
67
  u.update email: 'robert@example.com'
68
68
  end
69
69
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quo_vadis
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.5
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Stewart
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-04-14 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -66,7 +65,6 @@ dependencies:
66
65
  - - "~>"
67
66
  - !ruby/object:Gem::Version
68
67
  version: '2.0'
69
- description:
70
68
  email:
71
69
  - boss@airbladesoftware.com
72
70
  executables: []
@@ -206,7 +204,6 @@ homepage: https://github.com/airblade/quo_vadis
206
204
  licenses:
207
205
  - MIT
208
206
  metadata: {}
209
- post_install_message:
210
207
  rdoc_options: []
211
208
  require_paths:
212
209
  - lib
@@ -221,8 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
221
218
  - !ruby/object:Gem::Version
222
219
  version: '0'
223
220
  requirements: []
224
- rubygems_version: 3.5.11
225
- signing_key:
221
+ rubygems_version: 3.7.2
226
222
  specification_version: 4
227
223
  summary: Multifactor authentication for Rails.
228
224
  test_files: []