devise-two-factor 6.0.0 → 6.4.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 +3 -3
- data/.github/workflows/push.yml +28 -0
- data/Appraisals +9 -34
- data/CHANGELOG.md +44 -0
- data/README.md +5 -8
- data/Rakefile +2 -0
- data/UPGRADING.md +1 -1
- data/devise-two-factor.gemspec +4 -8
- data/gemfiles/{rails_7.0.gemfile → rails_7.2.gemfile} +2 -2
- data/gemfiles/{rails_7.1.gemfile → rails_8.0.gemfile} +2 -2
- data/gemfiles/rails_8.1.gemfile +8 -0
- data/lib/devise-two-factor.rb +1 -0
- data/lib/devise_two_factor/models/two_factor_authenticatable.rb +10 -13
- 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 +51 -22
- data/lib/devise_two_factor/strategies/two_factor_authenticatable.rb +7 -1
- data/lib/devise_two_factor/strategies/two_factor_backupable.rb +6 -1
- data/lib/devise_two_factor/version.rb +1 -1
- metadata +50 -100
- checksums.yaml.gz.sig +0 -0
- data/certs/tinfoil-cacert.pem +0 -41
- data/certs/tinfoilsecurity-gems-cert.pem +0 -35
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48a006cc0a0b85e48b88b8c8521231b65691c513d1c7bf0c55fac2b24fe73d07
|
|
4
|
+
data.tar.gz: e3d988b573e1720e5f1532a8fb161e3399cfd601273cf971957b33a6ad82a489
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee0fd9a8b7042adf26790545788508991ad06bab0191e2d75b3f7119f283f10fa922fa5a51353199539f8a220cb966706820538c22252e5f98a9f976077a8137
|
|
7
|
+
data.tar.gz: ad571291a241e5b7080f62c9ad410f91a0b1f140ff3d978370136212e659670cc8177328c1c306d6957ef925b7789dada8449e2aaa9e4f4096a78f7a97d7f777
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -12,14 +12,14 @@ jobs:
|
|
|
12
12
|
fail-fast: false
|
|
13
13
|
matrix:
|
|
14
14
|
# Due to https://github.com/actions/runner/issues/849, we should quote versions
|
|
15
|
-
ruby: ['3.
|
|
16
|
-
rails: ['7.0', '
|
|
15
|
+
ruby: ['3.2', '3.3', '3.4', '4.0', 'truffleruby-head']
|
|
16
|
+
rails: ['7.2', '8.0', '8.1']
|
|
17
17
|
|
|
18
18
|
name: Ruby ${{ matrix.ruby }}, Rails ${{ matrix.rails }}
|
|
19
19
|
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
|
20
20
|
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails_${{ matrix.rails }}.gemfile
|
|
21
21
|
steps:
|
|
22
|
-
- uses: actions/checkout@
|
|
22
|
+
- uses: actions/checkout@v6
|
|
23
23
|
- name: Set up Ruby
|
|
24
24
|
uses: ruby/setup-ruby@v1
|
|
25
25
|
with:
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Push Gem
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- v*
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
deployment:
|
|
10
|
+
name: Push gem to RubyGems.org
|
|
11
|
+
environment: RubyGems
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
|
16
|
+
contents: write # IMPORTANT: this permission is required for `rake release` to push the release tag
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
# Set up
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
|
+
- name: Set up Ruby
|
|
22
|
+
uses: ruby/setup-ruby@v1
|
|
23
|
+
with:
|
|
24
|
+
bundler-cache: true
|
|
25
|
+
ruby-version: ruby
|
|
26
|
+
|
|
27
|
+
# Release
|
|
28
|
+
- uses: rubygems/release-gem@v1
|
data/Appraisals
CHANGED
|
@@ -1,39 +1,14 @@
|
|
|
1
|
-
appraise "rails-
|
|
2
|
-
gem 'railties', '~>
|
|
3
|
-
gem 'activesupport', '~>
|
|
1
|
+
appraise "rails-7.2" do
|
|
2
|
+
gem 'railties', '~> 7.2.0'
|
|
3
|
+
gem 'activesupport', '~> 7.2.0'
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
-
appraise "rails-
|
|
7
|
-
gem 'railties', '~>
|
|
8
|
-
gem 'activesupport', '~>
|
|
6
|
+
appraise "rails-8.0" do
|
|
7
|
+
gem 'railties', '~> 8.0.0'
|
|
8
|
+
gem 'activesupport', '~> 8.0.0'
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
appraise "rails-
|
|
12
|
-
gem 'railties', '
|
|
13
|
-
gem 'activesupport', '
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
appraise "rails-5.1" do
|
|
17
|
-
gem 'railties', '~> 5.1'
|
|
18
|
-
gem 'activesupport', '~> 5.1'
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
appraise "rails-5.2" do
|
|
22
|
-
gem 'railties', '~> 5.2'
|
|
23
|
-
gem 'activesupport', '~> 5.2'
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
appraise "rails-6.0" do
|
|
27
|
-
gem 'railties', '~> 6.0'
|
|
28
|
-
gem 'activesupport', '~> 6.0'
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
appraise "rails-6.1" do
|
|
32
|
-
gem 'railties', '~> 6.1'
|
|
33
|
-
gem 'activesupport', '~> 6.1'
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
appraise "rails-7.0" do
|
|
37
|
-
gem 'railties', '~> 7.0'
|
|
38
|
-
gem 'activesupport', '~> 7.0'
|
|
11
|
+
appraise "rails-8.1" do
|
|
12
|
+
gem 'railties', '8.1.0'
|
|
13
|
+
gem 'activesupport', '8.1.0'
|
|
39
14
|
end
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 6.4.0
|
|
6
|
+
|
|
7
|
+
- Remove upper limit on Devise version (allows v5) from gemspec
|
|
8
|
+
|
|
9
|
+
## 6.3.1
|
|
10
|
+
|
|
11
|
+
- Fix DB-adapter-specific integration issue with backupable shared example
|
|
12
|
+
- Drop support for EOL Rails versions 7.0 and 7.1
|
|
13
|
+
|
|
14
|
+
## 6.3.0
|
|
15
|
+
|
|
16
|
+
- Fixed timing to be consistent when Devise paranoid mode is active.
|
|
17
|
+
|
|
18
|
+
## 6.2.0
|
|
19
|
+
|
|
20
|
+
- Rails 8.1 support
|
|
21
|
+
|
|
22
|
+
## 6.1.0
|
|
23
|
+
|
|
24
|
+
- Rails 8 support
|
|
25
|
+
|
|
26
|
+
## 6.0.0
|
|
27
|
+
|
|
28
|
+
**Breaking Changes**
|
|
29
|
+
- `otp_secret_length` and `otp_backup_code_length` options have changed to be the number of random bytes that are generated. See [UPGRADING.md](UPGRADING.md).
|
|
30
|
+
- `consume_otp!` and `invalidate_otp_backup_code!` now call `save!` instead of `save`. See [UPGRADING.md](UPGRADING.md).
|
|
31
|
+
|
|
5
32
|
## 5.1.0
|
|
6
33
|
|
|
7
34
|
- Remove faker dev dependency
|
|
@@ -15,20 +42,24 @@
|
|
|
15
42
|
- Rails 7 is now required.
|
|
16
43
|
|
|
17
44
|
## 4.1.0 / 4.1.1
|
|
45
|
+
|
|
18
46
|
- Add support for attr_encrypted v4
|
|
19
47
|
|
|
20
48
|
## 4.0.2
|
|
49
|
+
|
|
21
50
|
- Add Rails 7.0 support
|
|
22
51
|
- Renew signing certificate
|
|
23
52
|
- Use `after` option of TOTP#verify for additional timestamp verification
|
|
24
53
|
|
|
25
54
|
## 4.0.1
|
|
55
|
+
|
|
26
56
|
- Convert CI from Travis CI to Github Actions ([#198](https://github.com/tinfoil/devise-two-factor/pull/198))
|
|
27
57
|
- Fix ActiveSupport::Testing::TimeHelpers require in shared examples ([#191](https://github.com/tinfoil/devise-two-factor/pull/191))
|
|
28
58
|
- Accept whitespace in provided codes ([#195](https://github.com/tinfoil/devise-two-factor/pull/195))
|
|
29
59
|
- Add Truffleruby head to CI ([#200](https://github.com/tinfoil/devise-two-factor/pull/200))
|
|
30
60
|
|
|
31
61
|
## 4.0.0
|
|
62
|
+
|
|
32
63
|
- [breaking] Drop support for Ruby <= 2.2
|
|
33
64
|
- Update ROTP
|
|
34
65
|
- Add Rails 6.1 support
|
|
@@ -37,20 +68,25 @@
|
|
|
37
68
|
- Bugfixes & cleanup
|
|
38
69
|
|
|
39
70
|
## 3.1.0
|
|
71
|
+
|
|
40
72
|
- Add Rails 6.0 support
|
|
41
73
|
- New gem signing certificate
|
|
42
74
|
- Fix paranoid-mode being ignored
|
|
43
75
|
|
|
44
76
|
## 3.0.3
|
|
77
|
+
|
|
45
78
|
- Add Rails 5.2 support
|
|
46
79
|
|
|
47
80
|
## 3.0.2
|
|
81
|
+
|
|
48
82
|
- Add Rails 5.1 support
|
|
49
83
|
|
|
50
84
|
## 3.0.1
|
|
85
|
+
|
|
51
86
|
- Qualify call to rspec shared_examples
|
|
52
87
|
|
|
53
88
|
## 3.0.0
|
|
89
|
+
|
|
54
90
|
See `UPGRADING.md` for specific help with breaking changes from 2.x to 3.0.0.
|
|
55
91
|
|
|
56
92
|
- Adds support for Devise 4.
|
|
@@ -58,33 +94,41 @@ See `UPGRADING.md` for specific help with breaking changes from 2.x to 3.0.0.
|
|
|
58
94
|
- Blocks the use of attr_encrypted 2.x. There was a significant vulnerability in the encryption implementation in attr_encrypted 2.x, and that version of the gem should not be used.
|
|
59
95
|
|
|
60
96
|
## 2.2.0
|
|
97
|
+
|
|
61
98
|
- Use 192 bits, not 1024, as a secret key length. RFC 4226 recommends a minimum length of 128 bits and a recommended length of 160 bits. Google Authenticator doesn't accept 160 bit keys.
|
|
62
99
|
|
|
63
100
|
## 2.1.0
|
|
101
|
+
|
|
64
102
|
- Return false if OTP value is nil, instead of an ROTP exception.
|
|
65
103
|
|
|
66
104
|
## 2.0.1
|
|
105
|
+
|
|
67
106
|
No user-facing changes.
|
|
68
107
|
|
|
69
108
|
## 2.0.0
|
|
109
|
+
|
|
70
110
|
See `UPGRADING.md` for specific help with breaking changes from 1.x to 2.0.0.
|
|
71
111
|
|
|
72
112
|
- Replace `valid_otp?` method with `validate_and_consume_otp!`.
|
|
73
113
|
- Disallow subsequent OTPs once validated via timesteps.
|
|
74
114
|
|
|
75
115
|
## 1.1.0
|
|
116
|
+
|
|
76
117
|
- Removes runtimez activemodel dependency.
|
|
77
118
|
- Uses `Devise::Encryptor` instead of `Devise.bcrypt`, which is deprecated.
|
|
78
119
|
- Bump `rotp` dependency to 2.x.
|
|
79
120
|
|
|
80
121
|
## 1.0.2
|
|
122
|
+
|
|
81
123
|
- Makes Railties the only requirement for Rails generators.
|
|
82
124
|
- Explicitly check that the `otp_attempt` param is not nil in order to avoid 'ROTP only verifies strings' exceptions.
|
|
83
125
|
- Adding warning about recoverable devise strategy and automatic `sign_in` after a password reset.
|
|
84
126
|
- Loosen dependency version requirements for rotp, devise, and attr_encrypted.
|
|
85
127
|
|
|
86
128
|
## 1.0.1
|
|
129
|
+
|
|
87
130
|
- Add version requirements for dependencies.
|
|
88
131
|
|
|
89
132
|
## 1.0.0
|
|
133
|
+
|
|
90
134
|
- Initial release.
|
data/README.md
CHANGED
|
@@ -82,7 +82,7 @@ This generator will:
|
|
|
82
82
|
|
|
83
83
|
1. Edit `app/models/MODEL.rb` (where MODEL is your model name):
|
|
84
84
|
* add the `:two_factor_authenticatable` devise module
|
|
85
|
-
* remove the `:database_authenticatable` if present
|
|
85
|
+
* remove the `:database_authenticatable` devise module, if present; having both modules enabled will lead to issues described below.
|
|
86
86
|
1. Add a Warden config block to your Devise initializer, which enables the strategies required for two-factor authentication.
|
|
87
87
|
|
|
88
88
|
Remember to apply the new migration after you run the generator:
|
|
@@ -107,9 +107,9 @@ Next you need to whitelist `:otp_attempt` as a permitted parameter in Devise `:s
|
|
|
107
107
|
end
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
Finally you should verify that `:database_authenticatable` is **not** being loaded by your model. The generator will try to remove it, but if you have a non-standard Devise setup, this step may fail.
|
|
110
|
+
Finally you should verify that `:database_authenticatable` is **not** being loaded by your model. The generator will try to remove it, but if you have a non-standard Devise setup, this step may fail. `:two_factor_authenticatable` includes all of `:database_authenticatable`'s functionality; it will still allow login without two-factor authentication until you enable it on your model's records with `otp_required_for_login`.
|
|
111
111
|
|
|
112
|
-
**Loading both `:database_authenticatable` and `:two_factor_authenticatable` in a model is a security issue
|
|
112
|
+
**Loading both `:database_authenticatable` and `:two_factor_authenticatable` in a model is a security issue.** It will allow users to bypass two-factor authentication regardless of how `otp_required_for_login` is set due to the way Warden handles cascading strategies!
|
|
113
113
|
|
|
114
114
|
## Designing Your Workflow
|
|
115
115
|
|
|
@@ -155,10 +155,7 @@ At Tinfoil Security, we opted to use the excellent [rqrcode-rails3](https://gith
|
|
|
155
155
|
If you decide to do this you'll need to generate a URI to act as the source for the QR code. This can be done using the `User#otp_provisioning_uri` method.
|
|
156
156
|
|
|
157
157
|
```ruby
|
|
158
|
-
issuer
|
|
159
|
-
label = "#{issuer}:#{current_user.email}"
|
|
160
|
-
|
|
161
|
-
current_user.otp_provisioning_uri(label, issuer: issuer)
|
|
158
|
+
current_user.otp_provisioning_uri(current_user.email, issuer: 'Your App')
|
|
162
159
|
|
|
163
160
|
# > "otpauth://totp/Your%20App:user@example.com?secret=[otp_secret]&issuer=Your+App"
|
|
164
161
|
```
|
|
@@ -236,7 +233,7 @@ class AddDeviseTwoFactorBackupableToUsers < ActiveRecord::Migration
|
|
|
236
233
|
end
|
|
237
234
|
```
|
|
238
235
|
|
|
239
|
-
#### MySQL
|
|
236
|
+
#### MySQL, SQL Server, other databases without an array string type
|
|
240
237
|
|
|
241
238
|
```ruby
|
|
242
239
|
# migration
|
data/Rakefile
CHANGED
data/UPGRADING.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
### save!
|
|
6
6
|
|
|
7
|
-
`consume_otp!` and `invalidate_otp_backup_code!` now call `save!` instead of `save` (or nothing at all in the case of `
|
|
7
|
+
`consume_otp!` and `invalidate_otp_backup_code!` now call `save!` instead of `save` (or nothing at all in the case of `invalidate_otp_backup_code!`). If you manually called `save`/`save!` after calling `invalidate_otp_backup_code!` you may be able to remove it.
|
|
8
8
|
|
|
9
9
|
### Secret Lengths
|
|
10
10
|
|
data/devise-two-factor.gemspec
CHANGED
|
@@ -11,18 +11,13 @@ Gem::Specification.new do |s|
|
|
|
11
11
|
s.description = 'Devise-Two-Factor is a minimalist extension to Devise which offers support for two-factor authentication through the TOTP scheme.'
|
|
12
12
|
s.authors = ['Quinn Wilton']
|
|
13
13
|
|
|
14
|
-
s.cert_chain = [
|
|
15
|
-
'certs/tinfoil-cacert.pem',
|
|
16
|
-
'certs/tinfoilsecurity-gems-cert.pem'
|
|
17
|
-
]
|
|
18
|
-
s.signing_key = File.expand_path("~/.ssh/tinfoilsecurity-gems-key.pem") if $0 =~ /gem\z/
|
|
19
14
|
s.files = `git ls-files`.split("\n").delete_if { |x| x.match('demo/*') }
|
|
20
15
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
|
21
16
|
s.require_paths = ['lib']
|
|
22
17
|
|
|
23
|
-
s.add_runtime_dependency 'railties', '
|
|
24
|
-
s.add_runtime_dependency 'activesupport', '
|
|
25
|
-
s.add_runtime_dependency 'devise', '
|
|
18
|
+
s.add_runtime_dependency 'railties', '>= 7.2', '< 8.2'
|
|
19
|
+
s.add_runtime_dependency 'activesupport', '>= 7.2', '< 8.2'
|
|
20
|
+
s.add_runtime_dependency 'devise', '>= 4.0', '< 6.0'
|
|
26
21
|
s.add_runtime_dependency 'rotp', '~> 6.0'
|
|
27
22
|
|
|
28
23
|
s.add_development_dependency 'activemodel'
|
|
@@ -30,4 +25,5 @@ Gem::Specification.new do |s|
|
|
|
30
25
|
s.add_development_dependency 'bundler', '> 1.0'
|
|
31
26
|
s.add_development_dependency 'rspec', '> 3'
|
|
32
27
|
s.add_development_dependency 'simplecov'
|
|
28
|
+
s.add_development_dependency 'rake', '~> 13'
|
|
33
29
|
end
|
data/lib/devise-two-factor.rb
CHANGED
|
@@ -41,12 +41,11 @@ module Devise
|
|
|
41
41
|
|
|
42
42
|
if self.consumed_timestep
|
|
43
43
|
# reconstruct the timestamp of the last consumed timestep
|
|
44
|
-
after_timestamp = self.consumed_timestep *
|
|
44
|
+
after_timestamp = self.consumed_timestep * totp.interval
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
end
|
|
47
|
+
timestamp = totp.verify(code.gsub(/\s+/, ""), drift_behind: self.class.otp_allowed_drift, drift_ahead: self.class.otp_allowed_drift, after: after_timestamp)
|
|
48
|
+
return consume_otp!(totp, timestamp) if timestamp
|
|
50
49
|
|
|
51
50
|
false
|
|
52
51
|
end
|
|
@@ -59,11 +58,6 @@ module Devise
|
|
|
59
58
|
otp.at(Time.now)
|
|
60
59
|
end
|
|
61
60
|
|
|
62
|
-
# ROTP's TOTP#timecode is private, so we duplicate it here
|
|
63
|
-
def current_otp_timestep
|
|
64
|
-
Time.now.utc.to_i / otp.interval
|
|
65
|
-
end
|
|
66
|
-
|
|
67
61
|
def otp_provisioning_uri(account, options = {})
|
|
68
62
|
otp_secret = options[:otp_secret] || self.otp_secret
|
|
69
63
|
ROTP::TOTP.new(otp_secret, options).provisioning_uri(account)
|
|
@@ -78,10 +72,13 @@ module Devise
|
|
|
78
72
|
|
|
79
73
|
# An OTP cannot be used more than once in a given timestep
|
|
80
74
|
# Storing timestep of last valid OTP is sufficient to satisfy this requirement
|
|
81
|
-
def consume_otp!
|
|
82
|
-
|
|
83
|
-
|
|
75
|
+
def consume_otp!(otp, timestamp)
|
|
76
|
+
timestep = timestamp / otp.interval
|
|
77
|
+
|
|
78
|
+
if self.consumed_timestep != timestep
|
|
79
|
+
self.consumed_timestep = timestep
|
|
84
80
|
save!(validate: false)
|
|
81
|
+
|
|
85
82
|
return true
|
|
86
83
|
end
|
|
87
84
|
|
|
@@ -94,7 +91,7 @@ module Devise
|
|
|
94
91
|
:otp_encrypted_attribute_options,
|
|
95
92
|
:otp_secret_encryption_key)
|
|
96
93
|
|
|
97
|
-
#
|
|
94
|
+
# Generates an OTP secret of the specified length, returning it after Base32 encoding.
|
|
98
95
|
def generate_otp_secret(otp_secret_length = self.otp_secret_length)
|
|
99
96
|
ROTP::Base32.random(otp_secret_length)
|
|
100
97
|
end
|
|
@@ -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,67 @@ 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
|
-
|
|
110
|
+
# Do not run when DB adapter handles array assignment correctly
|
|
111
|
+
it "raises a meaningful error", unless: -> { subject.otp_backup_codes.is_a?(Array) } do
|
|
112
|
+
expect { subject.invalidate_otp_backup_code!("flork") }.to raise_error(TypeError)
|
|
84
113
|
end
|
|
85
114
|
end
|
|
86
115
|
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
|
|
@@ -5,7 +5,7 @@ module Devise
|
|
|
5
5
|
def authenticate!
|
|
6
6
|
resource = mapping.to.find_for_database_authentication(authentication_hash)
|
|
7
7
|
|
|
8
|
-
if validate(resource) { resource
|
|
8
|
+
if validate(resource) { validate_backup_code(resource) }
|
|
9
9
|
super
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -15,6 +15,11 @@ module Devise
|
|
|
15
15
|
# but database authenticatable automatically halts on a bad password
|
|
16
16
|
@halted = false if @result == :failure
|
|
17
17
|
end
|
|
18
|
+
|
|
19
|
+
def validate_backup_code(resource)
|
|
20
|
+
return if params[scope].nil? || params[scope]['otp_attempt'].nil?
|
|
21
|
+
resource.invalidate_otp_backup_code!(params[scope]['otp_attempt'])
|
|
22
|
+
end
|
|
18
23
|
end
|
|
19
24
|
end
|
|
20
25
|
end
|
metadata
CHANGED
|
@@ -1,135 +1,74 @@
|
|
|
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.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Quinn Wilton
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
|
-
cert_chain:
|
|
11
|
-
-
|
|
12
|
-
-----BEGIN CERTIFICATE-----
|
|
13
|
-
MIIHSjCCBTKgAwIBAgIJAK2u0LojMCNgMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD
|
|
14
|
-
VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEfMB0GA1UE
|
|
15
|
-
ChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEfMB0GA1UEAxMWVGluZm9pbCBTZWN1
|
|
16
|
-
cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYbc3VwcG9ydEB0aW5mb2lsc2VjdXJp
|
|
17
|
-
dHkuY29tMB4XDTIxMDkwOTE4MjIwMFoXDTI1MDkwOTE4MjIwMFowgZwxCzAJBgNV
|
|
18
|
-
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
|
19
|
-
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
|
20
|
-
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
|
21
|
-
eS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqbHvsSj0H0FB1
|
|
22
|
-
0gLYoDK1BKugkSB2DZeZZHP6B1UdWRahJXJP9oT1lhfQxx8iX4cgEi7JU3NqA6NR
|
|
23
|
-
cIRFQ50eH/qlmgs7909gaf8pDaeC0vR3wd0GeRg6qr1eDEnkzIyr/D1AMiX6H1eP
|
|
24
|
-
Y7J3SfrdaL3gft2iPRKGkgqsXR7oBNLA3n/ShiNgPXqRDl1CCj6aMY0cn5ROFScz
|
|
25
|
-
vT2FUB4DEwPD2l18m1p99OnXqsOLL2J65qA2+cI8FtgFmlwIi5oSf+URvIdNx+cH
|
|
26
|
-
lInlAtVHCvAKYLY0dlQ7czMQBcRpYjp2rwPt9f2ksq9b/voMTBABYHFV+IVn8svv
|
|
27
|
-
GZ5e1+icjtr/R7dCGmCdEdFLXVxafmZhukymG9USv9DKuv1qh7r4q8KaPIE8n7nQ
|
|
28
|
-
m97jENFfsgnwv+nUmIJ3tzuW5ZxO7A0tIIYdwzt0UjrO3ya4R5bTFXr4bnzZ/g/s
|
|
29
|
-
CLknWqg1BCRlPd6LnpVGPT0gNDV1pEO25wE3A3Yy0Ujxudcgay/CgUhnlU11qOAc
|
|
30
|
-
xmar2fhNZsviUhndd/220Ad5QMV2XzcAiopJIeu0juIVGRQM7x2h19Hsp0m6sOEF
|
|
31
|
-
jfhvbdUa4nvmIFeYFY+hr/YkTmG9ZjyBa8YaZXhwjhSmKCQ374J7mn5e0Cryuvi5
|
|
32
|
-
tYhwJn8rdwYZF/h2qqfEu8vaLoD09QIDAQABo4IBizCCAYcwHQYDVR0OBBYEFMmT
|
|
33
|
-
/x412UH+5OHqgleeTjLOv6iHMIHRBgNVHSMEgckwgcaAFMmT/x412UH+5OHqglee
|
|
34
|
-
TjLOv6iHoYGipIGfMIGcMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNV
|
|
35
|
-
BAcTCVBhbG8gQWx0bzEfMB0GA1UEChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEf
|
|
36
|
-
MB0GA1UEAxMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYb
|
|
37
|
-
c3VwcG9ydEB0aW5mb2lsc2VjdXJpdHkuY29tggkAra7QuiMwI2AwDwYDVR0TAQH/
|
|
38
|
-
BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQYwCQYDVR0SBAIwADArBglghkgBhvhC
|
|
39
|
-
AQ0EHhYcVGlueUNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAmBgNVHREEHzAdgRtz
|
|
40
|
-
dXBwb3J0QHRpbmZvaWxzZWN1cml0eS5jb20wDgYDVR0PAQH/BAQDAgEGMA0GCSqG
|
|
41
|
-
SIb3DQEBBQUAA4ICAQBZy4JJSmwLuO0nZbdr4tJeVS2P8bcGi6PzAcdzVfwzjp6n
|
|
42
|
-
5qf8m4O8my4lnJieom0GrWSHQoPY1Yur4hEoZbugKO9DWZL3dTiGcrgw0TbQ6Gtq
|
|
43
|
-
TTPatW3LA21qFJwvohSvLqPdmZuM+H9g49sdl2kNTDVI6iUyMYuNpL14aPKPGBFo
|
|
44
|
-
o7UjciT1h7JtJl9b/fXrbPeRHBwpZXWeipiPGv/OZW5KnOsNlUkTquS7Zj4ETkIC
|
|
45
|
-
6mVtmsLvq+YwFthFyMU37pXwYxcmqRmH6lX+XC6AVW5oO4GBmG+Zr/Z+h5Cih5ca
|
|
46
|
-
/mX88RkO+dGTjw1IdxKmxOqKL62OBATKrTDJ/scsmRptynA4TunYW+7ikOpDbPfL
|
|
47
|
-
l18aleLISlcgWJg/Czf2nmBqAClPLnhV8qxWsvt58MQQ/Jpoggvpl8EG1PylWiBS
|
|
48
|
-
Kc/4Ad/FKQFpTzXUgDg2kV07npVjYbBzA5p4ZSWSlflFu93jb9gg2+qtnRSImVCZ
|
|
49
|
-
nQjZdsv8hebElPAIbtJjSnoH1Kz2ucYLakdF1UMKnpp1PVREtuKPz/foU9KUHs0z
|
|
50
|
-
dWRALx8cWG4uKK9AIEUlVdGKfX0Wj0qFK0KGxl3f3jObud5Agwue2EPKWwUzEGUh
|
|
51
|
-
Iqp60gNw3vBdKHw4dh1bfcbXWnRDL+OQPuOFZeMWgu1QmeHeuggYtYtRg7V5Kg==
|
|
52
|
-
-----END CERTIFICATE-----
|
|
53
|
-
- |
|
|
54
|
-
-----BEGIN CERTIFICATE-----
|
|
55
|
-
MIIGADCCA+igAwIBAgIIHIF9ta6cW3YwDQYJKoZIhvcNAQENBQAwgZwxCzAJBgNV
|
|
56
|
-
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
|
57
|
-
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
|
58
|
-
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
|
59
|
-
eS5jb20wHhcNMjIwMzIyMjI1MzAwWhcNMjUwOTA5MTgyMjAwWjCBiDELMAkGA1UE
|
|
60
|
-
BhMCVVMxCzAJBgNVBAgTAkNBMR8wHQYDVQQKExZUaW5mb2lsIFNlY3VyaXR5LCBJ
|
|
61
|
-
bmMuMR0wGwYDVQQDExR0aW5mb2lsc2VjdXJpdHktZ2VtczEsMCoGCSqGSIb3DQEJ
|
|
62
|
-
ARYdZW5naW5lZXJzQHRpbmZvaWxzZWN1cml0eS5jb20wggIiMA0GCSqGSIb3DQEB
|
|
63
|
-
AQUAA4ICDwAwggIKAoICAQDNJYNH8D+8lACLt3KzjEIPs3XVBCPaMm2eD/Xk9OOT
|
|
64
|
-
uDV/NqgMK0icD9MRxMUtS3SCrC9QcPocXT76f2LQ3yVJuK+rBUasymEES47PIx2c
|
|
65
|
-
zC4n4Hga0xPPuBpioO26oaRFsobyzh9RPOIbnYfpjyqtdrbm+YyM3sPR4XzFirv9
|
|
66
|
-
xomT4E9T4RCLgOQHTcLKL9K9m+EN7PeVdVUXV0Pa7cVs2vJUKedsd7vnr6Lzbn8T
|
|
67
|
-
oPk/7J/4W931PbaeI5yg9ZuaRa9K2IaY1TkPI67NW4qKitBVepRlXw6Sb7TYcUnc
|
|
68
|
-
WEQ/eC5CpnOmqUrG5tfGD8cc5aGZOkitW/VXZgVj81xgCv1hk4HjErrqq4FBNAaC
|
|
69
|
-
SNyBfwR0TUYqg1lN1nbNjOKwfb6YRn06R2ovcFJG0tmGhsQULCr6fW8u2TfSM+U9
|
|
70
|
-
WFSIJx2griureY7EZPwg/MgsUiWUWMFemz3GVYXWJR3dN2pW9Uqr3rkjKZbA0bst
|
|
71
|
-
GWahJO9HuFdDakQxoaTPYPtTQDC+kskkO6lKG1KLIoZ1iLZzB1Ks1vEeyE7lp1im
|
|
72
|
-
WgpUq+q23PFkt1gIBi/4tGvzsLZye25QU2Y+XLzldCNm+DyRFXZ+Q+bK33IveUeU
|
|
73
|
-
WEOv4T1qTXHAOypyzmgodVRG/PrlsSMOBfE515kG1mDMGjRcCpEtlskgxUbf7qM7
|
|
74
|
-
hQIDAQABo1gwVjAJBgNVHRMEAjAAMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHBzOi8v
|
|
75
|
-
d3d3LnRpbmZvaWxzZWN1cml0eS5jb20vc2VjdXJpdHkvcmV2b2NhdGlvbl9saXN0
|
|
76
|
-
MA0GCSqGSIb3DQEBDQUAA4ICAQAiYF/m2ny/mxFvBVxHfdYuzybhCvsEUd+TSnoe
|
|
77
|
-
mqOWntY3sxCOaY0aGOMB4vyg9G+oP/kT4m63sD4uQxeuU7WOjaG2smCSS5q+PSWS
|
|
78
|
-
v63gILqPamjSyP/Om864EA6YlvVQ7nPXhVDEaiBt3iliefJGmb0wWSbbDCmq3aMb
|
|
79
|
-
WTLuax/IeY6MjJi20LutIcuz+VX8OxlA1hSpgAToMz3xrhA8fPt5UkKhkDkPFYBF
|
|
80
|
-
5htKVipyijChWsXyt33YM2qGaavTEXzxza1I99PGNRKxUMvbSMas4YaLqkBpQSc+
|
|
81
|
-
mcrLWYPiXWsePGu+j08AypE2Ubp4AOSZJN9rBBGotC3gofipo+K/sBiOM9xXI76Q
|
|
82
|
-
0HYOxXPa7D7UQQG1R9i0rcxmf9qepIVYCldmqVkKKDizcDo5UI9lRiLFjDyQhn6l
|
|
83
|
-
YFY9bPQ4lKTK5Jr3M6+dV7fHxLhqXyMGs1905IUb7qvB7Bq/f0qJfC0JZuY/qdn2
|
|
84
|
-
lL0SeFKOVsjErtobh3u8p8j2USkc8uJgIANHpXEMEExdp899CV/eVjh3TpAR7E6T
|
|
85
|
-
mg7Q9Hi6Hh8z+Le9iR4I49vPEWDQEvj35IT6VfwU79UfIOlX+DkW8fFkPbaut3Se
|
|
86
|
-
vqIDv6JBG9I16h/HhchntKfM58MI1bNZFBSdZqYOJiL8JIjP8HNIk76Y366ppG29
|
|
87
|
-
EhBYYg==
|
|
88
|
-
-----END CERTIFICATE-----
|
|
89
|
-
date: 2024-09-17 00:00:00.000000000 Z
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
90
11
|
dependencies:
|
|
91
12
|
- !ruby/object:Gem::Dependency
|
|
92
13
|
name: railties
|
|
93
14
|
requirement: !ruby/object:Gem::Requirement
|
|
94
15
|
requirements:
|
|
95
|
-
- - "
|
|
16
|
+
- - ">="
|
|
96
17
|
- !ruby/object:Gem::Version
|
|
97
|
-
version: '7.
|
|
18
|
+
version: '7.2'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '8.2'
|
|
98
22
|
type: :runtime
|
|
99
23
|
prerelease: false
|
|
100
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
101
25
|
requirements:
|
|
102
|
-
- - "
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '7.2'
|
|
29
|
+
- - "<"
|
|
103
30
|
- !ruby/object:Gem::Version
|
|
104
|
-
version: '
|
|
31
|
+
version: '8.2'
|
|
105
32
|
- !ruby/object:Gem::Dependency
|
|
106
33
|
name: activesupport
|
|
107
34
|
requirement: !ruby/object:Gem::Requirement
|
|
108
35
|
requirements:
|
|
109
|
-
- - "
|
|
36
|
+
- - ">="
|
|
110
37
|
- !ruby/object:Gem::Version
|
|
111
|
-
version: '7.
|
|
38
|
+
version: '7.2'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '8.2'
|
|
112
42
|
type: :runtime
|
|
113
43
|
prerelease: false
|
|
114
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
115
45
|
requirements:
|
|
116
|
-
- - "
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '7.2'
|
|
49
|
+
- - "<"
|
|
117
50
|
- !ruby/object:Gem::Version
|
|
118
|
-
version: '
|
|
51
|
+
version: '8.2'
|
|
119
52
|
- !ruby/object:Gem::Dependency
|
|
120
53
|
name: devise
|
|
121
54
|
requirement: !ruby/object:Gem::Requirement
|
|
122
55
|
requirements:
|
|
123
|
-
- - "
|
|
56
|
+
- - ">="
|
|
124
57
|
- !ruby/object:Gem::Version
|
|
125
58
|
version: '4.0'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '6.0'
|
|
126
62
|
type: :runtime
|
|
127
63
|
prerelease: false
|
|
128
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
129
65
|
requirements:
|
|
130
|
-
- - "
|
|
66
|
+
- - ">="
|
|
131
67
|
- !ruby/object:Gem::Version
|
|
132
68
|
version: '4.0'
|
|
69
|
+
- - "<"
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '6.0'
|
|
133
72
|
- !ruby/object:Gem::Dependency
|
|
134
73
|
name: rotp
|
|
135
74
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -214,15 +153,29 @@ dependencies:
|
|
|
214
153
|
- - ">="
|
|
215
154
|
- !ruby/object:Gem::Version
|
|
216
155
|
version: '0'
|
|
156
|
+
- !ruby/object:Gem::Dependency
|
|
157
|
+
name: rake
|
|
158
|
+
requirement: !ruby/object:Gem::Requirement
|
|
159
|
+
requirements:
|
|
160
|
+
- - "~>"
|
|
161
|
+
- !ruby/object:Gem::Version
|
|
162
|
+
version: '13'
|
|
163
|
+
type: :development
|
|
164
|
+
prerelease: false
|
|
165
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
166
|
+
requirements:
|
|
167
|
+
- - "~>"
|
|
168
|
+
- !ruby/object:Gem::Version
|
|
169
|
+
version: '13'
|
|
217
170
|
description: Devise-Two-Factor is a minimalist extension to Devise which offers support
|
|
218
171
|
for two-factor authentication through the TOTP scheme.
|
|
219
|
-
email:
|
|
220
172
|
executables: []
|
|
221
173
|
extensions: []
|
|
222
174
|
extra_rdoc_files: []
|
|
223
175
|
files:
|
|
224
176
|
- ".github/dependabot.yml"
|
|
225
177
|
- ".github/workflows/ci.yml"
|
|
178
|
+
- ".github/workflows/push.yml"
|
|
226
179
|
- ".gitignore"
|
|
227
180
|
- ".markdownlint.json"
|
|
228
181
|
- ".rspec"
|
|
@@ -235,11 +188,10 @@ files:
|
|
|
235
188
|
- Rakefile
|
|
236
189
|
- SECURITY.md
|
|
237
190
|
- UPGRADING.md
|
|
238
|
-
- certs/tinfoil-cacert.pem
|
|
239
|
-
- certs/tinfoilsecurity-gems-cert.pem
|
|
240
191
|
- devise-two-factor.gemspec
|
|
241
|
-
- gemfiles/rails_7.
|
|
242
|
-
- gemfiles/
|
|
192
|
+
- gemfiles/rails_7.2.gemfile
|
|
193
|
+
- gemfiles/rails_8.0.gemfile
|
|
194
|
+
- gemfiles/rails_8.1.gemfile
|
|
243
195
|
- lib/devise-two-factor.rb
|
|
244
196
|
- lib/devise_two_factor/models.rb
|
|
245
197
|
- lib/devise_two_factor/models/two_factor_authenticatable.rb
|
|
@@ -259,7 +211,6 @@ homepage: https://github.com/devise-two-factor/devise-two-factor
|
|
|
259
211
|
licenses:
|
|
260
212
|
- MIT
|
|
261
213
|
metadata: {}
|
|
262
|
-
post_install_message:
|
|
263
214
|
rdoc_options: []
|
|
264
215
|
require_paths:
|
|
265
216
|
- lib
|
|
@@ -274,8 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
274
225
|
- !ruby/object:Gem::Version
|
|
275
226
|
version: '0'
|
|
276
227
|
requirements: []
|
|
277
|
-
rubygems_version:
|
|
278
|
-
signing_key:
|
|
228
|
+
rubygems_version: 4.0.3
|
|
279
229
|
specification_version: 4
|
|
280
230
|
summary: Barebones two-factor authentication with Devise
|
|
281
231
|
test_files:
|
checksums.yaml.gz.sig
DELETED
|
Binary file
|
data/certs/tinfoil-cacert.pem
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
-----BEGIN CERTIFICATE-----
|
|
2
|
-
MIIHSjCCBTKgAwIBAgIJAK2u0LojMCNgMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD
|
|
3
|
-
VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEfMB0GA1UE
|
|
4
|
-
ChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEfMB0GA1UEAxMWVGluZm9pbCBTZWN1
|
|
5
|
-
cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYbc3VwcG9ydEB0aW5mb2lsc2VjdXJp
|
|
6
|
-
dHkuY29tMB4XDTIxMDkwOTE4MjIwMFoXDTI1MDkwOTE4MjIwMFowgZwxCzAJBgNV
|
|
7
|
-
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
|
8
|
-
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
|
9
|
-
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
|
10
|
-
eS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqbHvsSj0H0FB1
|
|
11
|
-
0gLYoDK1BKugkSB2DZeZZHP6B1UdWRahJXJP9oT1lhfQxx8iX4cgEi7JU3NqA6NR
|
|
12
|
-
cIRFQ50eH/qlmgs7909gaf8pDaeC0vR3wd0GeRg6qr1eDEnkzIyr/D1AMiX6H1eP
|
|
13
|
-
Y7J3SfrdaL3gft2iPRKGkgqsXR7oBNLA3n/ShiNgPXqRDl1CCj6aMY0cn5ROFScz
|
|
14
|
-
vT2FUB4DEwPD2l18m1p99OnXqsOLL2J65qA2+cI8FtgFmlwIi5oSf+URvIdNx+cH
|
|
15
|
-
lInlAtVHCvAKYLY0dlQ7czMQBcRpYjp2rwPt9f2ksq9b/voMTBABYHFV+IVn8svv
|
|
16
|
-
GZ5e1+icjtr/R7dCGmCdEdFLXVxafmZhukymG9USv9DKuv1qh7r4q8KaPIE8n7nQ
|
|
17
|
-
m97jENFfsgnwv+nUmIJ3tzuW5ZxO7A0tIIYdwzt0UjrO3ya4R5bTFXr4bnzZ/g/s
|
|
18
|
-
CLknWqg1BCRlPd6LnpVGPT0gNDV1pEO25wE3A3Yy0Ujxudcgay/CgUhnlU11qOAc
|
|
19
|
-
xmar2fhNZsviUhndd/220Ad5QMV2XzcAiopJIeu0juIVGRQM7x2h19Hsp0m6sOEF
|
|
20
|
-
jfhvbdUa4nvmIFeYFY+hr/YkTmG9ZjyBa8YaZXhwjhSmKCQ374J7mn5e0Cryuvi5
|
|
21
|
-
tYhwJn8rdwYZF/h2qqfEu8vaLoD09QIDAQABo4IBizCCAYcwHQYDVR0OBBYEFMmT
|
|
22
|
-
/x412UH+5OHqgleeTjLOv6iHMIHRBgNVHSMEgckwgcaAFMmT/x412UH+5OHqglee
|
|
23
|
-
TjLOv6iHoYGipIGfMIGcMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNV
|
|
24
|
-
BAcTCVBhbG8gQWx0bzEfMB0GA1UEChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEf
|
|
25
|
-
MB0GA1UEAxMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYb
|
|
26
|
-
c3VwcG9ydEB0aW5mb2lsc2VjdXJpdHkuY29tggkAra7QuiMwI2AwDwYDVR0TAQH/
|
|
27
|
-
BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQYwCQYDVR0SBAIwADArBglghkgBhvhC
|
|
28
|
-
AQ0EHhYcVGlueUNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAmBgNVHREEHzAdgRtz
|
|
29
|
-
dXBwb3J0QHRpbmZvaWxzZWN1cml0eS5jb20wDgYDVR0PAQH/BAQDAgEGMA0GCSqG
|
|
30
|
-
SIb3DQEBBQUAA4ICAQBZy4JJSmwLuO0nZbdr4tJeVS2P8bcGi6PzAcdzVfwzjp6n
|
|
31
|
-
5qf8m4O8my4lnJieom0GrWSHQoPY1Yur4hEoZbugKO9DWZL3dTiGcrgw0TbQ6Gtq
|
|
32
|
-
TTPatW3LA21qFJwvohSvLqPdmZuM+H9g49sdl2kNTDVI6iUyMYuNpL14aPKPGBFo
|
|
33
|
-
o7UjciT1h7JtJl9b/fXrbPeRHBwpZXWeipiPGv/OZW5KnOsNlUkTquS7Zj4ETkIC
|
|
34
|
-
6mVtmsLvq+YwFthFyMU37pXwYxcmqRmH6lX+XC6AVW5oO4GBmG+Zr/Z+h5Cih5ca
|
|
35
|
-
/mX88RkO+dGTjw1IdxKmxOqKL62OBATKrTDJ/scsmRptynA4TunYW+7ikOpDbPfL
|
|
36
|
-
l18aleLISlcgWJg/Czf2nmBqAClPLnhV8qxWsvt58MQQ/Jpoggvpl8EG1PylWiBS
|
|
37
|
-
Kc/4Ad/FKQFpTzXUgDg2kV07npVjYbBzA5p4ZSWSlflFu93jb9gg2+qtnRSImVCZ
|
|
38
|
-
nQjZdsv8hebElPAIbtJjSnoH1Kz2ucYLakdF1UMKnpp1PVREtuKPz/foU9KUHs0z
|
|
39
|
-
dWRALx8cWG4uKK9AIEUlVdGKfX0Wj0qFK0KGxl3f3jObud5Agwue2EPKWwUzEGUh
|
|
40
|
-
Iqp60gNw3vBdKHw4dh1bfcbXWnRDL+OQPuOFZeMWgu1QmeHeuggYtYtRg7V5Kg==
|
|
41
|
-
-----END CERTIFICATE-----
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
-----BEGIN CERTIFICATE-----
|
|
2
|
-
MIIGADCCA+igAwIBAgIIHIF9ta6cW3YwDQYJKoZIhvcNAQENBQAwgZwxCzAJBgNV
|
|
3
|
-
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
|
4
|
-
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
|
5
|
-
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
|
6
|
-
eS5jb20wHhcNMjIwMzIyMjI1MzAwWhcNMjUwOTA5MTgyMjAwWjCBiDELMAkGA1UE
|
|
7
|
-
BhMCVVMxCzAJBgNVBAgTAkNBMR8wHQYDVQQKExZUaW5mb2lsIFNlY3VyaXR5LCBJ
|
|
8
|
-
bmMuMR0wGwYDVQQDExR0aW5mb2lsc2VjdXJpdHktZ2VtczEsMCoGCSqGSIb3DQEJ
|
|
9
|
-
ARYdZW5naW5lZXJzQHRpbmZvaWxzZWN1cml0eS5jb20wggIiMA0GCSqGSIb3DQEB
|
|
10
|
-
AQUAA4ICDwAwggIKAoICAQDNJYNH8D+8lACLt3KzjEIPs3XVBCPaMm2eD/Xk9OOT
|
|
11
|
-
uDV/NqgMK0icD9MRxMUtS3SCrC9QcPocXT76f2LQ3yVJuK+rBUasymEES47PIx2c
|
|
12
|
-
zC4n4Hga0xPPuBpioO26oaRFsobyzh9RPOIbnYfpjyqtdrbm+YyM3sPR4XzFirv9
|
|
13
|
-
xomT4E9T4RCLgOQHTcLKL9K9m+EN7PeVdVUXV0Pa7cVs2vJUKedsd7vnr6Lzbn8T
|
|
14
|
-
oPk/7J/4W931PbaeI5yg9ZuaRa9K2IaY1TkPI67NW4qKitBVepRlXw6Sb7TYcUnc
|
|
15
|
-
WEQ/eC5CpnOmqUrG5tfGD8cc5aGZOkitW/VXZgVj81xgCv1hk4HjErrqq4FBNAaC
|
|
16
|
-
SNyBfwR0TUYqg1lN1nbNjOKwfb6YRn06R2ovcFJG0tmGhsQULCr6fW8u2TfSM+U9
|
|
17
|
-
WFSIJx2griureY7EZPwg/MgsUiWUWMFemz3GVYXWJR3dN2pW9Uqr3rkjKZbA0bst
|
|
18
|
-
GWahJO9HuFdDakQxoaTPYPtTQDC+kskkO6lKG1KLIoZ1iLZzB1Ks1vEeyE7lp1im
|
|
19
|
-
WgpUq+q23PFkt1gIBi/4tGvzsLZye25QU2Y+XLzldCNm+DyRFXZ+Q+bK33IveUeU
|
|
20
|
-
WEOv4T1qTXHAOypyzmgodVRG/PrlsSMOBfE515kG1mDMGjRcCpEtlskgxUbf7qM7
|
|
21
|
-
hQIDAQABo1gwVjAJBgNVHRMEAjAAMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHBzOi8v
|
|
22
|
-
d3d3LnRpbmZvaWxzZWN1cml0eS5jb20vc2VjdXJpdHkvcmV2b2NhdGlvbl9saXN0
|
|
23
|
-
MA0GCSqGSIb3DQEBDQUAA4ICAQAiYF/m2ny/mxFvBVxHfdYuzybhCvsEUd+TSnoe
|
|
24
|
-
mqOWntY3sxCOaY0aGOMB4vyg9G+oP/kT4m63sD4uQxeuU7WOjaG2smCSS5q+PSWS
|
|
25
|
-
v63gILqPamjSyP/Om864EA6YlvVQ7nPXhVDEaiBt3iliefJGmb0wWSbbDCmq3aMb
|
|
26
|
-
WTLuax/IeY6MjJi20LutIcuz+VX8OxlA1hSpgAToMz3xrhA8fPt5UkKhkDkPFYBF
|
|
27
|
-
5htKVipyijChWsXyt33YM2qGaavTEXzxza1I99PGNRKxUMvbSMas4YaLqkBpQSc+
|
|
28
|
-
mcrLWYPiXWsePGu+j08AypE2Ubp4AOSZJN9rBBGotC3gofipo+K/sBiOM9xXI76Q
|
|
29
|
-
0HYOxXPa7D7UQQG1R9i0rcxmf9qepIVYCldmqVkKKDizcDo5UI9lRiLFjDyQhn6l
|
|
30
|
-
YFY9bPQ4lKTK5Jr3M6+dV7fHxLhqXyMGs1905IUb7qvB7Bq/f0qJfC0JZuY/qdn2
|
|
31
|
-
lL0SeFKOVsjErtobh3u8p8j2USkc8uJgIANHpXEMEExdp899CV/eVjh3TpAR7E6T
|
|
32
|
-
mg7Q9Hi6Hh8z+Le9iR4I49vPEWDQEvj35IT6VfwU79UfIOlX+DkW8fFkPbaut3Se
|
|
33
|
-
vqIDv6JBG9I16h/HhchntKfM58MI1bNZFBSdZqYOJiL8JIjP8HNIk76Y366ppG29
|
|
34
|
-
EhBYYg==
|
|
35
|
-
-----END CERTIFICATE-----
|
data.tar.gz.sig
DELETED
|
Binary file
|
metadata.gz.sig
DELETED
|
Binary file
|