devise-two-factor 3.1.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of devise-two-factor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +15 -0
- data/LICENSE +1 -1
- data/README.md +19 -7
- data/certs/tinfoilsecurity-gems-cert.pem +14 -14
- data/devise-two-factor.gemspec +3 -7
- data/lib/devise_two_factor/models/two_factor_authenticatable.rb +17 -11
- data/lib/devise_two_factor/spec_helpers/two_factor_authenticatable_shared_examples.rb +13 -11
- data/lib/devise_two_factor/version.rb +1 -1
- data/spec/devise/models/two_factor_authenticatable_spec.rb +20 -0
- data/spec/spec_helper.rb +2 -1
- metadata +29 -44
- 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: 33ab6513476203a5a4135af19c1f3bbddeeed83fb2ed8bf3a74c2afe2e74be9b
|
4
|
+
data.tar.gz: 16068a92b6b20aa06108cb0e3cd294dc5c98c19563311d024dcfc7e0573030ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 258cd2abf3bc9beb80c0f9fc596b33055efa24ca53177847fbab5a38b80a220e322a2739303b30128c356000dabd708bcc77e835dacecee2e3c9fe51b66c2b33
|
7
|
+
data.tar.gz: 940c49c9b2cbea4832ee8f66c39b26c1c6ad45d09dc054cf0c54d0be823219e18ad4ef7ca12dc388e2eec319534be0d880b5f9d3e2eb5fcace86ce6b9008e960
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## 4.0.0
|
6
|
+
- Update ROTP
|
7
|
+
- Add Rails 6.1 support
|
8
|
+
- Remove timecop dependency
|
9
|
+
- Clarify changes in project ownership
|
10
|
+
- Bugfixes & cleanup
|
11
|
+
|
12
|
+
## 3.1.0
|
13
|
+
- Add Rails 6.0 support
|
14
|
+
- New gem signing certificate
|
15
|
+
- Fix paranoid-mode being ignored
|
16
|
+
|
17
|
+
## 3.0.3
|
18
|
+
- Add Rails 5.2 support
|
19
|
+
|
5
20
|
## 3.0.2
|
6
21
|
- Add Rails 5.1 support
|
7
22
|
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Devise-Two-Factor Authentication
|
2
|
-
By [Tinfoil Security](https://www.tinfoilsecurity.com/). Interested in [working with us](https://www.
|
2
|
+
By [Tinfoil Security](https://www.tinfoilsecurity.com/) (acq. [Synopsys](https://www.synopsys.com/) 2020). Interested in [working with us](https://www.synopsys.com/careers.html)? We're hiring!
|
3
3
|
|
4
4
|
[![Build Status](https://travis-ci.org/tinfoil/devise-two-factor.svg?branch=master)](https://travis-ci.org/tinfoil/devise-two-factor)
|
5
5
|
|
6
|
-
Devise-Two-Factor is a minimalist extension to Devise which offers support for two-factor authentication, through the [TOTP](https://en.wikipedia.org/wiki/Time-based_One-
|
6
|
+
Devise-Two-Factor is a minimalist extension to Devise which offers support for two-factor authentication, through the [TOTP](https://en.wikipedia.org/wiki/Time-based_One-Time_Password) scheme. It:
|
7
7
|
|
8
8
|
* Allows you to incorporate two-factor authentication into your existing models
|
9
9
|
* Is opinionated about security, so you don't have to be
|
@@ -53,7 +53,13 @@ This generator will add a few columns to the specified model:
|
|
53
53
|
* consumed_timestep
|
54
54
|
* otp_required_for_login
|
55
55
|
|
56
|
-
|
56
|
+
Remember to apply the new migration.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
bundle exec rake db:migrate
|
60
|
+
```
|
61
|
+
|
62
|
+
It also adds the `:two_factor_authenticatable` directive to your model, and sets up your encryption key. If present, it will remove `:database_authenticatable` from the model, as the two strategies are incompatible. Lastly, the generator will add a Warden config block to your Devise initializer, which enables the strategies required for two-factor authentication.
|
57
63
|
|
58
64
|
If you're running Rails 3, or do not have strong parameters enabled, the generator will also setup the required mass-assignment security options in your model.
|
59
65
|
|
@@ -85,7 +91,7 @@ def configure_permitted_parameters
|
|
85
91
|
end
|
86
92
|
```
|
87
93
|
|
88
|
-
**After running the generator, verify that
|
94
|
+
**After running the generator, 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. Loading both `:database_authenticatable` and `:two_factor_authenticatable` in a model will allow users to bypass two-factor authenticatable due to the way Warden handles cascading strategies.**
|
89
95
|
|
90
96
|
## Designing Your Workflow
|
91
97
|
Devise-Two-Factor only worries about the backend, leaving the details of the integration up to you. This means that you're responsible for building the UI that drives the gem. While there is an example Rails application included in the gem, it is important to remember that this gem is intentionally very open-ended, and you should build a user experience which fits your individual application.
|
@@ -95,7 +101,7 @@ There are two key workflows you'll have to think about:
|
|
95
101
|
1. Logging in with two-factor authentication
|
96
102
|
2. Enabling two-factor authentication for a given user
|
97
103
|
|
98
|
-
We chose to keep things as simple as possible, and our implementation can be found by registering at [Tinfoil Security](https://tinfoilsecurity.com/), and enabling two-factor authentication from the [security settings page](https://www.tinfoilsecurity.com/account/security).
|
104
|
+
We chose to keep things as simple as possible, and our implementation can be found by registering at [Tinfoil Security](https://www.tinfoilsecurity.com/), and enabling two-factor authentication from the [security settings page](https://www.tinfoilsecurity.com/account/security).
|
99
105
|
|
100
106
|
|
101
107
|
### Logging In
|
@@ -108,7 +114,7 @@ Logging in with two-factor authentication works extremely similarly to regular d
|
|
108
114
|
These parameters can be submitted to the standard Devise login route, and the strategy will handle the authentication of the user for you.
|
109
115
|
|
110
116
|
### Disabling Automatic Login After Password Resets
|
111
|
-
If you use the Devise
|
117
|
+
If you use the Devise `recoverable` strategy, the default behavior after a password reset is to automatically authenticate the user and log them in. This is obviously a problem if a user has two-factor authentication enabled, as resetting the password would get around the two-factor requirement.
|
112
118
|
|
113
119
|
Because of this, you need to set `sign_in_after_reset_password` to `false` (either globally in your Devise initializer or via `devise_for`).
|
114
120
|
|
@@ -142,7 +148,13 @@ If you instead to decide to send the one-time password to the user directly, suc
|
|
142
148
|
current_user.current_otp
|
143
149
|
```
|
144
150
|
|
145
|
-
The generated code will be valid for the duration specified by `otp_allowed_drift`.
|
151
|
+
The generated code will be valid for the duration specified by `otp_allowed_drift`. This value can be modified by adding a config in `config/initializers/devise.rb`.
|
152
|
+
```ruby
|
153
|
+
Devise.otp_allowed_drift = 240 # value in seconds
|
154
|
+
Devise.setup do |config|
|
155
|
+
...
|
156
|
+
end
|
157
|
+
```
|
146
158
|
|
147
159
|
However you decide to handle enrollment, there are a few important considerations to be made:
|
148
160
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
MIIGADCCA+
|
2
|
+
MIIGADCCA+igAwIBAgIIP4wV6YA6CO0wDQYJKoZIhvcNAQENBQAwgZwxCzAJBgNV
|
3
3
|
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
4
4
|
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
5
5
|
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
6
|
-
|
6
|
+
eS5jb20wHhcNMjEwNDA4MTUxODAwWhcNMjExMjI0MDUwNzAwWjCBiDELMAkGA1UE
|
7
7
|
BhMCVVMxCzAJBgNVBAgTAkNBMR8wHQYDVQQKExZUaW5mb2lsIFNlY3VyaXR5LCBJ
|
8
8
|
bmMuMR0wGwYDVQQDExR0aW5mb2lsc2VjdXJpdHktZ2VtczEsMCoGCSqGSIb3DQEJ
|
9
9
|
ARYdZW5naW5lZXJzQHRpbmZvaWxzZWN1cml0eS5jb20wggIiMA0GCSqGSIb3DQEB
|
@@ -20,16 +20,16 @@ WgpUq+q23PFkt1gIBi/4tGvzsLZye25QU2Y+XLzldCNm+DyRFXZ+Q+bK33IveUeU
|
|
20
20
|
WEOv4T1qTXHAOypyzmgodVRG/PrlsSMOBfE515kG1mDMGjRcCpEtlskgxUbf7qM7
|
21
21
|
hQIDAQABo1gwVjAJBgNVHRMEAjAAMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHBzOi8v
|
22
22
|
d3d3LnRpbmZvaWxzZWN1cml0eS5jb20vc2VjdXJpdHkvcmV2b2NhdGlvbl9saXN0
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
/
|
34
|
-
|
23
|
+
MA0GCSqGSIb3DQEBDQUAA4ICAQB4p1yL6e/38Dmf5HdZoSJzQ7AcM+jrD0LdMC1V
|
24
|
+
H0Y107JzZWvIB2aWH4tw4+SKGTr52OvyGFLpBv5jsWUUFssuAV971T1x41kWJSYt
|
25
|
+
tnljNguSrH6ah/pDravLxi+JGQXMBRXhkdvQKbFOfutSe9HEuZLiWUYNDYM17XJq
|
26
|
+
WmG+QhNgXliXgu4AQg+8vb1rDbu/G491GEuxbwaLyyKG8X+P5mYTBbMQbTgJkNfX
|
27
|
+
elpmFtqivFaEHs3evVGEEZRQhe8i5V0Ak2c4Or1ap/pZQf3hUIkZbw7HumyZYNWi
|
28
|
+
VJDMpObUyucv6++TNW8bAI5Oip8DGeYKibPsJ0IfYxMmRC3BmY1E3IIvAdsUHTcq
|
29
|
+
WapfQlX732+mfx/gSBpuZhdwEqjWj0xPj6l9DjQrGuhUEijfucKqyY3F280OYM1b
|
30
|
+
2zG6cwVmh5IeR9nVv0i2KNkoc2zC8tcGpjfBBuDdXZCpow54DRJU4qQ6S0lH5ojs
|
31
|
+
aQHEEIQ9/STv9TKuc4KlMUey8W6L0Zw+xFWnkLeygaMps1PhPokSbrABQsB4C10Q
|
32
|
+
QSG/Dvvw438W/2sb9aR+skGh1oNAwJiFhLNaNALfkSXRtU16gLMPBJCi2Xqyco7V
|
33
|
+
Wh4SFQHrAbuglSi0nYgFm2SxYf/r6JRKxhVkwo8wxRiV8rDZj7WmzQoZK4GHj1u6
|
34
|
+
LXXw3g==
|
35
35
|
-----END CERTIFICATE-----
|
data/devise-two-factor.gemspec
CHANGED
@@ -17,18 +17,15 @@ Gem::Specification.new do |s|
|
|
17
17
|
'certs/tinfoilsecurity-gems-cert.pem'
|
18
18
|
]
|
19
19
|
s.signing_key = File.expand_path("~/.ssh/tinfoilsecurity-gems-key.pem") if $0 =~ /gem\z/
|
20
|
-
|
21
|
-
s.rubyforge_project = 'devise-two-factor'
|
22
|
-
|
23
20
|
s.files = `git ls-files`.split("\n").delete_if { |x| x.match('demo/*') }
|
24
21
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
25
22
|
s.require_paths = ['lib']
|
26
23
|
|
27
|
-
s.add_runtime_dependency 'railties', '< 6.
|
28
|
-
s.add_runtime_dependency 'activesupport', '< 6.
|
24
|
+
s.add_runtime_dependency 'railties', '< 6.2'
|
25
|
+
s.add_runtime_dependency 'activesupport', '< 6.2'
|
29
26
|
s.add_runtime_dependency 'attr_encrypted', '>= 1.3', '< 4', '!= 2'
|
30
27
|
s.add_runtime_dependency 'devise', '~> 4.0'
|
31
|
-
s.add_runtime_dependency 'rotp', '~>
|
28
|
+
s.add_runtime_dependency 'rotp', '~> 6.0'
|
32
29
|
|
33
30
|
s.add_development_dependency 'activemodel'
|
34
31
|
s.add_development_dependency 'appraisal'
|
@@ -36,5 +33,4 @@ Gem::Specification.new do |s|
|
|
36
33
|
s.add_development_dependency 'rspec', '> 3'
|
37
34
|
s.add_development_dependency 'simplecov'
|
38
35
|
s.add_development_dependency 'faker'
|
39
|
-
s.add_development_dependency 'timecop'
|
40
36
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'attr_encrypted'
|
2
1
|
require 'rotp'
|
3
2
|
|
4
3
|
module Devise
|
@@ -8,14 +7,18 @@ module Devise
|
|
8
7
|
include Devise::Models::DatabaseAuthenticatable
|
9
8
|
|
10
9
|
included do
|
11
|
-
unless
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
unless %i[otp_secret otp_secret=].all? { |attr| method_defined?(attr) }
|
11
|
+
require 'attr_encrypted'
|
12
|
+
|
13
|
+
unless singleton_class.ancestors.include?(AttrEncrypted)
|
14
|
+
extend AttrEncrypted
|
15
|
+
end
|
16
|
+
|
17
|
+
unless attr_encrypted?(:otp_secret)
|
18
|
+
attr_encrypted :otp_secret,
|
19
|
+
:key => self.otp_secret_encryption_key,
|
20
|
+
:mode => :per_attribute_iv_and_salt unless self.attr_encrypted?(:otp_secret)
|
21
|
+
end
|
19
22
|
end
|
20
23
|
|
21
24
|
attr_accessor :otp_attempt
|
@@ -31,8 +34,10 @@ module Devise
|
|
31
34
|
otp_secret = options[:otp_secret] || self.otp_secret
|
32
35
|
return false unless code.present? && otp_secret.present?
|
33
36
|
|
34
|
-
totp =
|
35
|
-
|
37
|
+
totp = otp(otp_secret)
|
38
|
+
if totp.verify(code, drift_behind: self.class.otp_allowed_drift, drift_ahead: self.class.otp_allowed_drift)
|
39
|
+
return consume_otp!
|
40
|
+
end
|
36
41
|
|
37
42
|
false
|
38
43
|
end
|
@@ -56,6 +61,7 @@ module Devise
|
|
56
61
|
end
|
57
62
|
|
58
63
|
def clean_up_passwords
|
64
|
+
super
|
59
65
|
self.otp_attempt = nil
|
60
66
|
end
|
61
67
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
1
3
|
RSpec.shared_examples 'two_factor_authenticatable' do
|
2
4
|
before :each do
|
3
5
|
subject.otp_secret = subject.class.generate_otp_secret
|
@@ -32,12 +34,12 @@ RSpec.shared_examples 'two_factor_authenticatable' do
|
|
32
34
|
let(:otp_secret) { '2z6hxkdwi3uvrnpn' }
|
33
35
|
|
34
36
|
before :each do
|
35
|
-
|
37
|
+
travel_to(Time.now)
|
36
38
|
subject.otp_secret = otp_secret
|
37
39
|
end
|
38
40
|
|
39
41
|
after :each do
|
40
|
-
|
42
|
+
travel_back
|
41
43
|
end
|
42
44
|
|
43
45
|
context 'with a stored consumed_timestep' do
|
@@ -54,7 +56,7 @@ RSpec.shared_examples 'two_factor_authenticatable' do
|
|
54
56
|
end
|
55
57
|
|
56
58
|
context 'given a previously valid OTP within the allowed drift' do
|
57
|
-
let(:consumed_otp) { ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift
|
59
|
+
let(:consumed_otp) { ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift) }
|
58
60
|
|
59
61
|
before do
|
60
62
|
subject.validate_and_consume_otp!(consumed_otp)
|
@@ -77,17 +79,17 @@ RSpec.shared_examples 'two_factor_authenticatable' do
|
|
77
79
|
end
|
78
80
|
|
79
81
|
it 'validates an OTP within the allowed drift' do
|
80
|
-
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift
|
82
|
+
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift)
|
81
83
|
expect(subject.validate_and_consume_otp!(otp)).to be true
|
82
84
|
end
|
83
85
|
|
84
86
|
it 'does not validate an OTP above the allowed drift' do
|
85
|
-
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift * 2
|
87
|
+
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift * 2)
|
86
88
|
expect(subject.validate_and_consume_otp!(otp)).to be false
|
87
89
|
end
|
88
90
|
|
89
91
|
it 'does not validate an OTP below the allowed drift' do
|
90
|
-
otp = ROTP::TOTP.new(otp_secret).at(Time.now - subject.class.otp_allowed_drift * 2
|
92
|
+
otp = ROTP::TOTP.new(otp_secret).at(Time.now - subject.class.otp_allowed_drift * 2)
|
91
93
|
expect(subject.validate_and_consume_otp!(otp)).to be false
|
92
94
|
end
|
93
95
|
end
|
@@ -95,15 +97,15 @@ RSpec.shared_examples 'two_factor_authenticatable' do
|
|
95
97
|
describe '#otp_provisioning_uri' do
|
96
98
|
let(:otp_secret_length) { subject.class.otp_secret_length }
|
97
99
|
let(:account) { Faker::Internet.email }
|
98
|
-
let(:issuer) {
|
100
|
+
let(:issuer) { 'Tinfoil' }
|
99
101
|
|
100
|
-
it
|
101
|
-
expect(subject.otp_provisioning_uri(account)).to match(%r{otpauth://totp/#{account}\?secret=\w{#{otp_secret_length}}})
|
102
|
+
it 'should return uri with specified account' do
|
103
|
+
expect(subject.otp_provisioning_uri(account)).to match(%r{otpauth://totp/#{CGI.escape(account)}\?secret=\w{#{otp_secret_length}}})
|
102
104
|
end
|
103
105
|
|
104
106
|
it 'should return uri with issuer option' do
|
105
|
-
expect(subject.otp_provisioning_uri(account, issuer: issuer)).to match(%r{otpauth://totp/#{account}\?.*secret=\w{#{otp_secret_length}}(&|$)})
|
106
|
-
expect(subject.otp_provisioning_uri(account, issuer: issuer)).to match(%r{otpauth://totp/#{account}\?.*issuer=#{issuer}(&|$)})
|
107
|
+
expect(subject.otp_provisioning_uri(account, issuer: issuer)).to match(%r{otpauth://totp/#{issuer}:#{CGI.escape(account)}\?.*secret=\w{#{otp_secret_length}}(&|$)})
|
108
|
+
expect(subject.otp_provisioning_uri(account, issuer: issuer)).to match(%r{otpauth://totp/#{issuer}:#{CGI.escape(account)}\?.*issuer=#{issuer}(&|$)})
|
107
109
|
end
|
108
110
|
end
|
109
111
|
end
|
@@ -77,3 +77,23 @@ describe ::Devise::Models::TwoFactorAuthenticatable do
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
80
|
+
|
81
|
+
describe ::Devise::Models::TwoFactorAuthenticatable do
|
82
|
+
context 'When clean_up_passwords is called ' do
|
83
|
+
subject { TwoFactorAuthenticatableDouble.new }
|
84
|
+
before :each do
|
85
|
+
subject.otp_attempt = 'foo'
|
86
|
+
subject.password_confirmation = 'foo'
|
87
|
+
end
|
88
|
+
it 'otp_attempt should be nill' do
|
89
|
+
subject.clean_up_passwords
|
90
|
+
expect(subject.otp_attempt).to be_nil
|
91
|
+
end
|
92
|
+
it 'password_confirmation should be nill' do
|
93
|
+
subject.clean_up_passwords
|
94
|
+
expect(subject.password_confirmation).to be_nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -19,14 +19,15 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
19
19
|
|
20
20
|
require 'rspec'
|
21
21
|
require 'faker'
|
22
|
-
require 'timecop'
|
23
22
|
require 'devise-two-factor'
|
24
23
|
require 'devise_two_factor/spec_helpers'
|
24
|
+
require 'active_support/testing/time_helpers'
|
25
25
|
|
26
26
|
# Requires supporting files with custom matchers and macros, etc,
|
27
27
|
# in ./support/ and its subdirectories.
|
28
28
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
29
29
|
|
30
30
|
RSpec.configure do |config|
|
31
|
+
config.include ActiveSupport::Testing::TimeHelpers
|
31
32
|
config.order = 'random'
|
32
33
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise-two-factor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shane Wilton
|
@@ -52,11 +52,11 @@ cert_chain:
|
|
52
52
|
-----END CERTIFICATE-----
|
53
53
|
- |
|
54
54
|
-----BEGIN CERTIFICATE-----
|
55
|
-
MIIGADCCA+
|
55
|
+
MIIGADCCA+igAwIBAgIIP4wV6YA6CO0wDQYJKoZIhvcNAQENBQAwgZwxCzAJBgNV
|
56
56
|
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
57
57
|
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
58
58
|
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
59
|
-
|
59
|
+
eS5jb20wHhcNMjEwNDA4MTUxODAwWhcNMjExMjI0MDUwNzAwWjCBiDELMAkGA1UE
|
60
60
|
BhMCVVMxCzAJBgNVBAgTAkNBMR8wHQYDVQQKExZUaW5mb2lsIFNlY3VyaXR5LCBJ
|
61
61
|
bmMuMR0wGwYDVQQDExR0aW5mb2lsc2VjdXJpdHktZ2VtczEsMCoGCSqGSIb3DQEJ
|
62
62
|
ARYdZW5naW5lZXJzQHRpbmZvaWxzZWN1cml0eS5jb20wggIiMA0GCSqGSIb3DQEB
|
@@ -73,20 +73,20 @@ cert_chain:
|
|
73
73
|
WEOv4T1qTXHAOypyzmgodVRG/PrlsSMOBfE515kG1mDMGjRcCpEtlskgxUbf7qM7
|
74
74
|
hQIDAQABo1gwVjAJBgNVHRMEAjAAMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHBzOi8v
|
75
75
|
d3d3LnRpbmZvaWxzZWN1cml0eS5jb20vc2VjdXJpdHkvcmV2b2NhdGlvbl9saXN0
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
/
|
87
|
-
|
76
|
+
MA0GCSqGSIb3DQEBDQUAA4ICAQB4p1yL6e/38Dmf5HdZoSJzQ7AcM+jrD0LdMC1V
|
77
|
+
H0Y107JzZWvIB2aWH4tw4+SKGTr52OvyGFLpBv5jsWUUFssuAV971T1x41kWJSYt
|
78
|
+
tnljNguSrH6ah/pDravLxi+JGQXMBRXhkdvQKbFOfutSe9HEuZLiWUYNDYM17XJq
|
79
|
+
WmG+QhNgXliXgu4AQg+8vb1rDbu/G491GEuxbwaLyyKG8X+P5mYTBbMQbTgJkNfX
|
80
|
+
elpmFtqivFaEHs3evVGEEZRQhe8i5V0Ak2c4Or1ap/pZQf3hUIkZbw7HumyZYNWi
|
81
|
+
VJDMpObUyucv6++TNW8bAI5Oip8DGeYKibPsJ0IfYxMmRC3BmY1E3IIvAdsUHTcq
|
82
|
+
WapfQlX732+mfx/gSBpuZhdwEqjWj0xPj6l9DjQrGuhUEijfucKqyY3F280OYM1b
|
83
|
+
2zG6cwVmh5IeR9nVv0i2KNkoc2zC8tcGpjfBBuDdXZCpow54DRJU4qQ6S0lH5ojs
|
84
|
+
aQHEEIQ9/STv9TKuc4KlMUey8W6L0Zw+xFWnkLeygaMps1PhPokSbrABQsB4C10Q
|
85
|
+
QSG/Dvvw438W/2sb9aR+skGh1oNAwJiFhLNaNALfkSXRtU16gLMPBJCi2Xqyco7V
|
86
|
+
Wh4SFQHrAbuglSi0nYgFm2SxYf/r6JRKxhVkwo8wxRiV8rDZj7WmzQoZK4GHj1u6
|
87
|
+
LXXw3g==
|
88
88
|
-----END CERTIFICATE-----
|
89
|
-
date:
|
89
|
+
date: 2021-04-08 00:00:00.000000000 Z
|
90
90
|
dependencies:
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: railties
|
@@ -94,28 +94,28 @@ dependencies:
|
|
94
94
|
requirements:
|
95
95
|
- - "<"
|
96
96
|
- !ruby/object:Gem::Version
|
97
|
-
version: '6.
|
97
|
+
version: '6.2'
|
98
98
|
type: :runtime
|
99
99
|
prerelease: false
|
100
100
|
version_requirements: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
102
|
- - "<"
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version: '6.
|
104
|
+
version: '6.2'
|
105
105
|
- !ruby/object:Gem::Dependency
|
106
106
|
name: activesupport
|
107
107
|
requirement: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
109
|
- - "<"
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: '6.
|
111
|
+
version: '6.2'
|
112
112
|
type: :runtime
|
113
113
|
prerelease: false
|
114
114
|
version_requirements: !ruby/object:Gem::Requirement
|
115
115
|
requirements:
|
116
116
|
- - "<"
|
117
117
|
- !ruby/object:Gem::Version
|
118
|
-
version: '6.
|
118
|
+
version: '6.2'
|
119
119
|
- !ruby/object:Gem::Dependency
|
120
120
|
name: attr_encrypted
|
121
121
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,12 +123,12 @@ dependencies:
|
|
123
123
|
- - ">="
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '1.3'
|
126
|
-
- - "<"
|
127
|
-
- !ruby/object:Gem::Version
|
128
|
-
version: '4'
|
129
126
|
- - "!="
|
130
127
|
- !ruby/object:Gem::Version
|
131
128
|
version: '2'
|
129
|
+
- - "<"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '4'
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -136,12 +136,12 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '1.3'
|
139
|
-
- - "<"
|
140
|
-
- !ruby/object:Gem::Version
|
141
|
-
version: '4'
|
142
139
|
- - "!="
|
143
140
|
- !ruby/object:Gem::Version
|
144
141
|
version: '2'
|
142
|
+
- - "<"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '4'
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
146
|
name: devise
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -162,14 +162,14 @@ dependencies:
|
|
162
162
|
requirements:
|
163
163
|
- - "~>"
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: '
|
165
|
+
version: '6.0'
|
166
166
|
type: :runtime
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
170
|
- - "~>"
|
171
171
|
- !ruby/object:Gem::Version
|
172
|
-
version: '
|
172
|
+
version: '6.0'
|
173
173
|
- !ruby/object:Gem::Dependency
|
174
174
|
name: activemodel
|
175
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,20 +254,6 @@ dependencies:
|
|
254
254
|
- - ">="
|
255
255
|
- !ruby/object:Gem::Version
|
256
256
|
version: '0'
|
257
|
-
- !ruby/object:Gem::Dependency
|
258
|
-
name: timecop
|
259
|
-
requirement: !ruby/object:Gem::Requirement
|
260
|
-
requirements:
|
261
|
-
- - ">="
|
262
|
-
- !ruby/object:Gem::Version
|
263
|
-
version: '0'
|
264
|
-
type: :development
|
265
|
-
prerelease: false
|
266
|
-
version_requirements: !ruby/object:Gem::Requirement
|
267
|
-
requirements:
|
268
|
-
- - ">="
|
269
|
-
- !ruby/object:Gem::Version
|
270
|
-
version: '0'
|
271
257
|
description: Barebones two-factor authentication with Devise
|
272
258
|
email: engineers@tinfoilsecurity.com
|
273
259
|
executables: []
|
@@ -328,8 +314,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
328
314
|
- !ruby/object:Gem::Version
|
329
315
|
version: '0'
|
330
316
|
requirements: []
|
331
|
-
|
332
|
-
rubygems_version: 2.7.6.2
|
317
|
+
rubygems_version: 3.0.3
|
333
318
|
signing_key:
|
334
319
|
specification_version: 4
|
335
320
|
summary: Barebones two-factor authentication with Devise
|
metadata.gz.sig
CHANGED
Binary file
|