devise-two-factor 6.2.0 → 6.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 +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/.github/workflows/push.yml +1 -1
- data/CHANGELOG.md +4 -0
- data/README.md +1 -1
- data/devise-two-factor.gemspec +1 -1
- data/lib/devise_two_factor/models/two_factor_backupable.rb +3 -0
- data/lib/devise_two_factor/spec_helpers/two_factor_backupable_shared_examples.rb +50 -22
- data/lib/devise_two_factor/strategies/two_factor_authenticatable.rb +7 -1
- data/lib/devise_two_factor/version.rb +1 -1
- metadata +11 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4513e96354e689136149f21dbd447785cc74113a66725bed6153e44758a1709b
|
|
4
|
+
data.tar.gz: 9e83133ebdc4166577129276188688780aeec065a5fead7861073496210215e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a119f4f3f825409f6cea77f934fe7e35fa741dfb1b242c33a59dd523eb43ef2270b3dda80d1403f4baf7ade03271bbd4b145d21c6c390eeb223e00f0aadb6d29
|
|
7
|
+
data.tar.gz: 0f31866cb9c1523ff94095d2b43cf819d2a06a658a2dad94383d93e4c6c47d9e791092090cf8063f351c7727df6f2146e4bf22bf5a204c0b1f80aaf8a4fec3fb
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
|
27
27
|
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails_${{ matrix.rails }}.gemfile
|
|
28
28
|
steps:
|
|
29
|
-
- uses: actions/checkout@
|
|
29
|
+
- uses: actions/checkout@v6
|
|
30
30
|
- name: Set up Ruby
|
|
31
31
|
uses: ruby/setup-ruby@v1
|
|
32
32
|
with:
|
data/.github/workflows/push.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
data/devise-two-factor.gemspec
CHANGED
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
|
17
17
|
|
|
18
18
|
s.add_runtime_dependency 'railties', '>= 7.0', '< 8.2'
|
|
19
19
|
s.add_runtime_dependency 'activesupport', '>= 7.0', '< 8.2'
|
|
20
|
-
s.add_runtime_dependency 'devise', '
|
|
20
|
+
s.add_runtime_dependency 'devise', '>= 4.0', '< 5.0'
|
|
21
21
|
s.add_runtime_dependency 'rotp', '~> 6.0'
|
|
22
22
|
|
|
23
23
|
s.add_development_dependency 'activemodel'
|
|
@@ -34,6 +34,9 @@ module Devise
|
|
|
34
34
|
def invalidate_otp_backup_code!(code)
|
|
35
35
|
codes = self.otp_backup_codes || []
|
|
36
36
|
|
|
37
|
+
# Should we still have some other kind of non iterable result, terminate.
|
|
38
|
+
raise TypeError.new("`otp_backup_codes` is expected to be an Array, got #{codes.class.name}. Hint: If your database does not support arrays, does your model correctly `serialize :otp_backup_codes, Array`?") unless codes.is_a?(Array)
|
|
39
|
+
|
|
37
40
|
codes.each do |backup_code|
|
|
38
41
|
next unless Devise::Encryptor.compare(self.class, backup_code, code)
|
|
39
42
|
|
|
@@ -49,38 +49,66 @@ RSpec.shared_examples 'two_factor_backupable' do
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
describe '#invalidate_otp_backup_code!' do
|
|
52
|
-
before do
|
|
53
|
-
@plaintext_codes = subject.generate_otp_backup_codes!
|
|
54
|
-
end
|
|
55
52
|
|
|
56
|
-
context 'given an invalid recovery code' do
|
|
57
|
-
it 'returns false' do
|
|
58
|
-
expect(subject.invalidate_otp_backup_code!('password')).to be false
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
53
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
expect(subject.invalidate_otp_backup_code!(
|
|
54
|
+
describe "#invalidate_otp_backup_code!" do
|
|
55
|
+
context "with no backup codes" do
|
|
56
|
+
it "does nothing" do
|
|
57
|
+
expect(subject.invalidate_otp_backup_code!("foo")).to be false
|
|
66
58
|
end
|
|
67
59
|
end
|
|
68
60
|
|
|
69
|
-
|
|
70
|
-
|
|
61
|
+
context "with an array of backup codes, newly generated" do
|
|
62
|
+
before do
|
|
63
|
+
@plaintext_codes = subject.generate_otp_backup_codes!
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context 'given an invalid recovery code' do
|
|
67
|
+
it 'returns false' do
|
|
68
|
+
expect(subject.invalidate_otp_backup_code!('password')).to be false
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context 'given a valid recovery code' do
|
|
73
|
+
it 'returns true' do
|
|
74
|
+
@plaintext_codes.each do |code|
|
|
75
|
+
expect(subject.invalidate_otp_backup_code!(code)).to be true
|
|
76
|
+
end
|
|
77
|
+
end
|
|
71
78
|
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
it 'invalidates that recovery code' do
|
|
80
|
+
code = @plaintext_codes.sample
|
|
81
|
+
|
|
82
|
+
subject.invalidate_otp_backup_code!(code)
|
|
83
|
+
expect(subject.invalidate_otp_backup_code!(code)).to be false
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'does not invalidate the other recovery codes' do
|
|
87
|
+
code = @plaintext_codes.sample
|
|
88
|
+
subject.invalidate_otp_backup_code!(code)
|
|
89
|
+
|
|
90
|
+
@plaintext_codes.delete(code)
|
|
91
|
+
|
|
92
|
+
@plaintext_codes.each do |code|
|
|
93
|
+
expect(subject.invalidate_otp_backup_code!(code)).to be true
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
74
97
|
end
|
|
75
98
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
99
|
+
context "with backup codes as a string" do
|
|
100
|
+
before do
|
|
101
|
+
@plaintext_codes = subject.generate_otp_backup_codes!
|
|
79
102
|
|
|
80
|
-
|
|
103
|
+
# Simulates database adapters that don't understand `t.string :otp_backup_codes, type: array` properly
|
|
104
|
+
# such as SQL Server; and have just returned the serialized string still.
|
|
105
|
+
# and the user not having done:
|
|
106
|
+
# `serialize :otp_backup_codes, Array` in their model
|
|
107
|
+
subject.otp_backup_codes = subject.otp_backup_codes.to_json
|
|
108
|
+
end
|
|
81
109
|
|
|
82
|
-
|
|
83
|
-
expect
|
|
110
|
+
it "raises a meaningful error" do
|
|
111
|
+
expect { subject.invalidate_otp_backup_code!("flork") }.to raise_error(TypeError)
|
|
84
112
|
end
|
|
85
113
|
end
|
|
86
114
|
end
|
|
@@ -4,12 +4,18 @@ module Devise
|
|
|
4
4
|
|
|
5
5
|
def authenticate!
|
|
6
6
|
resource = mapping.to.find_for_database_authentication(authentication_hash)
|
|
7
|
+
|
|
8
|
+
hashed = false
|
|
7
9
|
# We authenticate in two cases:
|
|
8
10
|
# 1. The password and the OTP are correct
|
|
9
11
|
# 2. The password is correct, and OTP is not required for login
|
|
10
12
|
# We check the OTP, then defer to DatabaseAuthenticatable
|
|
11
|
-
if validate(resource) { validate_otp(resource) }
|
|
13
|
+
if validate(resource) { hashed = true; validate_otp(resource) }
|
|
12
14
|
super
|
|
15
|
+
else
|
|
16
|
+
# Paranoid mode: do the expensive hash even when resource is nil,
|
|
17
|
+
# to avoid timing-based user enumeration.
|
|
18
|
+
mapping.to.new.password = password if !hashed && Devise.paranoid
|
|
13
19
|
end
|
|
14
20
|
|
|
15
21
|
fail(Devise.paranoid ? :invalid : :not_found_in_database) unless resource
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: devise-two-factor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.
|
|
4
|
+
version: 6.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Quinn Wilton
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: railties
|
|
@@ -53,16 +53,22 @@ dependencies:
|
|
|
53
53
|
name: devise
|
|
54
54
|
requirement: !ruby/object:Gem::Requirement
|
|
55
55
|
requirements:
|
|
56
|
-
- - "
|
|
56
|
+
- - ">="
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
58
|
version: '4.0'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '5.0'
|
|
59
62
|
type: :runtime
|
|
60
63
|
prerelease: false
|
|
61
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
62
65
|
requirements:
|
|
63
|
-
- - "
|
|
66
|
+
- - ">="
|
|
64
67
|
- !ruby/object:Gem::Version
|
|
65
68
|
version: '4.0'
|
|
69
|
+
- - "<"
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '5.0'
|
|
66
72
|
- !ruby/object:Gem::Dependency
|
|
67
73
|
name: rotp
|
|
68
74
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -221,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
221
227
|
- !ruby/object:Gem::Version
|
|
222
228
|
version: '0'
|
|
223
229
|
requirements: []
|
|
224
|
-
rubygems_version:
|
|
230
|
+
rubygems_version: 4.0.3
|
|
225
231
|
specification_version: 4
|
|
226
232
|
summary: Barebones two-factor authentication with Devise
|
|
227
233
|
test_files:
|