quo_vadis 2.1.5 → 2.1.8

Sign up to get free protection for your applications and to get access to all the features.
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