quo_vadis 2.1.5 → 2.1.8

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: d01da21fdfe58d00e4f073036f53df4e0da212a9b202c31bf9fe9ed162e2e2d5
4
- data.tar.gz: f9b7b777065c7b4e1c83ed54330bc08608cc6020f55f1b72d316de5a1e4e06f5
3
+ metadata.gz: d11498bfa66e0397304c2d9a0f8ac504037f97beac4fd039fe6c8d0299696531
4
+ data.tar.gz: 2d1e267c7b55740c72087e297960ff6ececb1caee45a17eb588bf7e44ba64d31
5
5
  SHA512:
6
- metadata.gz: d3daf72be8a7e1a4545bc8dc7acd77553c62933dd5837e78679a7581cf44356822fbecf4036d5cd8cac5648636a5077e1edd5cb8d6e804ea7c9d55c10b36dc6e
7
- data.tar.gz: eee0046f0ae978f537f85946946cb4fe0267fd866216108f226411a3df479cb1b7e9c5c334d120a9107298ce9c30f3b8b6736dcaf6248a9c4a5e23a34962bc2e
6
+ metadata.gz: e4e7c7bb2996556b35b153c56916aef9834dcac2abea08ede8becc14e030d8f4ea1444f9286c1ca9b728c1a13c16d8d9b2e701255d57b769c7dc9abefa84a976
7
+ data.tar.gz: f466404a5ba44bfd506cbcd2fdc7b2f2d142ecab419363e3c368bb5eca67cfc78829afa698b8b0dc1cc76210b531a32a44c3bfdcd1ae709cf9eafe740861f089
data/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@
4
4
  ## HEAD
5
5
 
6
6
 
7
+ ## 2.1.8 (18 June 2022)
8
+
9
+ * Extract convenience method for has authentication account.
10
+ * Only authenticating models react to email change.
11
+
12
+
13
+ ## 2.1.7 (30 May 2022)
14
+
15
+ * Use SHA256 digest for encryption.
16
+ * Use <time> element in logs view.
17
+
18
+
19
+ ## 2.1.6 (30 May 2022)
20
+
21
+ * Fix typo in session scope.
22
+
23
+
7
24
  ## 2.1.5 (27 May 2022)
8
25
 
9
26
  * Order sessions list and display more information.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Quo Vadis
2
2
 
3
- Multifactor authentication for your Rails 6 app.
3
+ Multifactor authentication for your Rails 6 or Rails 7 app.
4
4
 
5
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
 
@@ -537,6 +537,6 @@ If you don't want a specific flash message at all, give the key an empty value i
537
537
 
538
538
  ## Intellectual Property
539
539
 
540
- Copyright 2011-2021 Andrew Stewart (boss@airbladesoftware.com).
540
+ Copyright 2011-2022 Andrew Stewart (boss@airbladesoftware.com).
541
541
 
542
542
  Released under the MIT licence.
@@ -9,7 +9,7 @@ module QuoVadis
9
9
 
10
10
  belongs_to :account
11
11
  validates :ip, presence: true
12
- scope :new_to_old, -> { order create_at: :desc }
12
+ scope :new_to_old, -> { order created_at: :desc }
13
13
 
14
14
  attribute :last_seen_at, :datetime, default: -> { Time.now.utc }
15
15
 
@@ -12,7 +12,7 @@
12
12
  <tbody>
13
13
  <% @logs.each do |log| %>
14
14
  <tr>
15
- <td><%= log.created_at %></td>
15
+ <td><time datetime="<%= log.created_at.to_formatted_s(:iso8601) %>"><%= log.created_at.to_formatted_s('%-d %B %Y') %></time></td>
16
16
  <td><%= QuoVadis.translate "log.action.#{log.action}" %></td>
17
17
  <td><%= log.ip %></td>
18
18
  <td><%= log.metadata.empty? ? '' : log.metadata.map {|k,v| "#{k}: #{v}"}.join(', ') %></td>
@@ -8,7 +8,7 @@ module QuoVadis
8
8
  return '' if value == ''
9
9
 
10
10
  salt = SecureRandom.hex KEY_LENGTH
11
- crypt = encryptor key(salt)
11
+ crypt = encryptor salt
12
12
  ciphertext = crypt.encrypt_and_sign value
13
13
  [salt, ciphertext].join SEPARATOR
14
14
  end
@@ -18,7 +18,7 @@ module QuoVadis
18
18
  return '' if value == ''
19
19
 
20
20
  salt, data = value.split SEPARATOR
21
- crypt = encryptor key(salt)
21
+ crypt = encryptor salt
22
22
  crypt.decrypt_and_verify(data)
23
23
  end
24
24
 
@@ -27,12 +27,18 @@ module QuoVadis
27
27
  KEY_LENGTH = ActiveSupport::MessageEncryptor.key_len
28
28
  SEPARATOR = '$$'
29
29
 
30
- def self.encryptor(key)
31
- ActiveSupport::MessageEncryptor.new(key)
30
+ def self.encryptor(salt)
31
+ key_sha256 = key salt, OpenSSL::Digest::SHA256
32
+ key_sha1 = key salt, OpenSSL::Digest::SHA1
33
+ ActiveSupport::MessageEncryptor.new(key_sha256).tap { |crypt|
34
+ crypt.rotate key_sha1
35
+ }
32
36
  end
33
37
 
34
- def self.key(salt)
35
- ActiveSupport::KeyGenerator.new(secret).generate_key(salt, KEY_LENGTH)
38
+ def self.key(salt, hash_digest_class)
39
+ ActiveSupport::KeyGenerator
40
+ .new(secret, hash_digest_class: hash_digest_class)
41
+ .generate_key(salt, KEY_LENGTH)
36
42
  end
37
43
 
38
44
  def self.secret
@@ -14,7 +14,7 @@ module QuoVadis
14
14
 
15
15
  has_one :qv_account, as: :model, class_name: 'QuoVadis::Account', dependent: :destroy, autosave: true
16
16
 
17
- before_validation :qv_copy_identifier_to_account, if: Proc.new { |m| m.qv_account }
17
+ before_validation :qv_copy_identifier_to_account, if: :has_authentication_account?
18
18
 
19
19
  validate :qv_copy_password_errors, if: Proc.new { |m| m.qv_account&.password }
20
20
 
@@ -29,8 +29,8 @@ module QuoVadis
29
29
  qv_account.identifier = send identifier
30
30
  end
31
31
 
32
- after_update :qv_log_email_change, if: :saved_change_to_email?
33
- after_update :qv_notify_email_change, if: :saved_change_to_email?
32
+ after_update :qv_log_email_change, if: [:has_authentication_account?, :saved_change_to_email?]
33
+ after_update :qv_notify_email_change, if: [:has_authentication_account?, :saved_change_to_email?]
34
34
 
35
35
  QuoVadis.register_model self.name, identifier
36
36
  end
@@ -57,6 +57,10 @@ module QuoVadis
57
57
  qv_account.revoke
58
58
  end
59
59
 
60
+ def has_authentication_account?
61
+ !!qv_account
62
+ end
63
+
60
64
  private
61
65
 
62
66
  def qv_copy_password_errors
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QuoVadis
4
- VERSION = '2.1.5'
4
+ VERSION = '2.1.8'
5
5
  end
@@ -54,7 +54,7 @@ class SessionsTest < IntegrationTest
54
54
  phone.get quo_vadis.sessions_path
55
55
  phone.assert_response :success
56
56
  phone.assert_select 'td', 'This session'
57
- phone.assert_select 'td input[type=submit][value="Log out"]', 1
57
+ phone.assert_select 'td button[type=submit]', text: 'Log out', count: 1
58
58
 
59
59
  # on phone, log out the desktop session
60
60
  phone.delete quo_vadis.session_path(QuoVadis::Session.first.id)
@@ -4,6 +4,13 @@ class CryptTest < ActiveSupport::TestCase
4
4
 
5
5
  setup do
6
6
  @crypt = QuoVadis::Crypt
7
+
8
+ @crypt_sha1 = Class.new(QuoVadis::Crypt) do
9
+ def self.encryptor(salt)
10
+ key_sha1 = key salt, OpenSSL::Digest::SHA1
11
+ ActiveSupport::MessageEncryptor.new key_sha1
12
+ end
13
+ end
7
14
  end
8
15
 
9
16
  test 'round trip' do
@@ -19,4 +26,16 @@ class CryptTest < ActiveSupport::TestCase
19
26
  refute_equal ciphertext, @crypt.encrypt(plaintext)
20
27
  end
21
28
 
29
+ test 'rotation' do
30
+ # This test only works if our test Rails contains this commit:
31
+ # https://github.com/rails/rails/commit/447e28347eb46e2ad5dc625de616152bd1b69a32
32
+ return unless ActiveSupport::KeyGenerator.respond_to? :hash_digest_class
33
+
34
+ plaintext = 'the quick brown fox'
35
+ # Encrypt with SHA1 digest
36
+ ciphertext_sha1 = @crypt_sha1.encrypt plaintext
37
+ # Ensure code can decrypt it.
38
+ assert_equal plaintext, @crypt.decrypt(ciphertext_sha1)
39
+ end
40
+
22
41
  end
@@ -66,4 +66,14 @@ class ModelTest < ActiveSupport::TestCase
66
66
  u.update email: 'robert@example.com'
67
67
  end
68
68
  end
69
+
70
+
71
+ test 'does not notify or log on email change when no account' do
72
+ u = User.create! name: 'bob', email: 'bob@example.com'
73
+ assert_no_difference 'QuoVadis::Log.count' do
74
+ assert_no_enqueued_emails do
75
+ u.update email: 'robert@example.com'
76
+ end
77
+ end
78
+ end
69
79
  end
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.5
4
+ version: 2.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Stewart
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-27 00:00:00.000000000 Z
11
+ date: 2022-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails