devise-two-factor 3.1.0 → 4.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ci.yml +51 -0
- data/Appraisals +16 -6
- data/CHANGELOG.md +22 -0
- data/LICENSE +1 -1
- data/README.md +37 -8
- data/certs/tinfoil-cacert.pem +12 -12
- data/certs/tinfoilsecurity-gems-cert.pem +14 -14
- data/devise-two-factor.gemspec +3 -7
- data/gemfiles/{rails_4_1.gemfile → rails_4.1.gemfile} +0 -0
- data/gemfiles/{rails_4_2.gemfile → rails_4.2.gemfile} +0 -0
- data/gemfiles/{rails_5_0.gemfile → rails_5.0.gemfile} +0 -0
- data/gemfiles/{rails_5_1.gemfile → rails_5.1.gemfile} +0 -0
- data/gemfiles/{rails_5_2.gemfile → rails_5.2.gemfile} +0 -0
- data/gemfiles/rails_6.0.gemfile +8 -0
- data/gemfiles/rails_6.1.gemfile +8 -0
- data/gemfiles/rails_7.0.gemfile +8 -0
- data/lib/devise_two_factor/models/two_factor_authenticatable.rb +23 -11
- data/lib/devise_two_factor/spec_helpers/two_factor_authenticatable_shared_examples.rb +54 -11
- data/lib/devise_two_factor/spec_helpers.rb +6 -0
- 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 +0 -1
- data.tar.gz.sig +0 -0
- metadata +47 -60
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -46
- data/gemfiles/rails_6_0.gemfile +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 976317c79975d3526dea8a30d6b7ded62de0d218bc89add6db0cac627b75e057
|
4
|
+
data.tar.gz: 758d0b728bdda8132be4c2f3459cce4bd61a42e548b36b34c5ee07fc8c38f4d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 510c99d55da2f9c66533c968c4d7c4681a14bb81a3ba4624fb3c5f61c542ff5bf68683e5234d618a12aeb5398a2016144b8b5222b01a812e8ab6e48332b75264
|
7
|
+
data.tar.gz: 7e68943b8d191f0b0b27f05f51a55b1a47ae85d487b44db22e4d74810eab29faffac01f6b9f6a8afa9c158eede9286611d2e8eafcf138f0ce0292a3cb2d4895a
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -0,0 +1,51 @@
|
|
1
|
+
name: CI
|
2
|
+
on:
|
3
|
+
push:
|
4
|
+
branches:
|
5
|
+
- main
|
6
|
+
pull_request:
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
tests:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
strategy:
|
12
|
+
fail-fast: false
|
13
|
+
matrix:
|
14
|
+
# Due to https://github.com/actions/runner/issues/849, we should quote versions
|
15
|
+
ruby: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', 'truffleruby-head']
|
16
|
+
rails: ['4.1', '4.2', '5.0', '5.1', '5.2', '6.0', '6.1', '7.0']
|
17
|
+
exclude:
|
18
|
+
- { ruby: '2.3', rails: '7.0' }
|
19
|
+
- { ruby: '2.4', rails: '7.0' }
|
20
|
+
- { ruby: '2.5', rails: '7.0' }
|
21
|
+
- { ruby: '2.6', rails: '7.0' }
|
22
|
+
- { ruby: '2.3', rails: '6.0' }
|
23
|
+
- { ruby: '2.3', rails: '6.1' }
|
24
|
+
- { ruby: '2.4', rails: '6.0' }
|
25
|
+
- { ruby: '2.4', rails: '6.1' }
|
26
|
+
- { ruby: '2.7', rails: '4.1' }
|
27
|
+
- { ruby: '2.7', rails: '4.2' }
|
28
|
+
- { ruby: '3.0', rails: '4.1' }
|
29
|
+
- { ruby: '3.0', rails: '4.2' }
|
30
|
+
- { ruby: 'truffleruby-head', rails: '4.1' }
|
31
|
+
- { ruby: 'truffleruby-head', rails: '4.2' }
|
32
|
+
|
33
|
+
name: Ruby ${{ matrix.ruby }}, Rails ${{ matrix.rails }}
|
34
|
+
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
35
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails_${{ matrix.rails }}.gemfile
|
36
|
+
steps:
|
37
|
+
- uses: actions/checkout@v2
|
38
|
+
- name: Set up Ruby
|
39
|
+
uses: ruby/setup-ruby@v1
|
40
|
+
with:
|
41
|
+
ruby-version: ${{ matrix.ruby }}
|
42
|
+
bundler-cache: true
|
43
|
+
- name: Print versions
|
44
|
+
continue-on-error: true
|
45
|
+
run: |
|
46
|
+
ruby --version
|
47
|
+
bundle --version
|
48
|
+
echo "RubyGems version `gem --version`"
|
49
|
+
bundle exec rails --version
|
50
|
+
- name: Run tests
|
51
|
+
run: bundle exec rake
|
data/Appraisals
CHANGED
@@ -1,29 +1,39 @@
|
|
1
|
-
appraise "rails-4
|
1
|
+
appraise "rails-4.1" do
|
2
2
|
gem 'railties', '~> 4.1'
|
3
3
|
gem 'activesupport', '~> 4.1'
|
4
4
|
end
|
5
5
|
|
6
|
-
appraise "rails-4
|
6
|
+
appraise "rails-4.2" do
|
7
7
|
gem 'railties', '~> 4.2'
|
8
8
|
gem 'activesupport', '~> 4.2'
|
9
9
|
end
|
10
10
|
|
11
|
-
appraise "rails-5
|
11
|
+
appraise "rails-5.0" do
|
12
12
|
gem 'railties', '~> 5.0'
|
13
13
|
gem 'activesupport', '~> 5.0'
|
14
14
|
end
|
15
15
|
|
16
|
-
appraise "rails-5
|
16
|
+
appraise "rails-5.1" do
|
17
17
|
gem 'railties', '~> 5.1'
|
18
18
|
gem 'activesupport', '~> 5.1'
|
19
19
|
end
|
20
20
|
|
21
|
-
appraise "rails-5
|
21
|
+
appraise "rails-5.2" do
|
22
22
|
gem 'railties', '~> 5.2'
|
23
23
|
gem 'activesupport', '~> 5.2'
|
24
24
|
end
|
25
25
|
|
26
|
-
appraise "rails-6
|
26
|
+
appraise "rails-6.0" do
|
27
27
|
gem 'railties', '~> 6.0'
|
28
28
|
gem 'activesupport', '~> 6.0'
|
29
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'
|
39
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,28 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## 4.0.1
|
6
|
+
- Convert CI from Travis CI to Github Actions ([#198](https://github.com/tinfoil/devise-two-factor/pull/198))
|
7
|
+
- Fix ActiveSupport::Testing::TimeHelpers require in shared examples ([#191](https://github.com/tinfoil/devise-two-factor/pull/191))
|
8
|
+
- Accept whitespace in provided codes ([#195](https://github.com/tinfoil/devise-two-factor/pull/195))
|
9
|
+
- Add Truffleruby head to CI ([#200](https://github.com/tinfoil/devise-two-factor/pull/200))
|
10
|
+
|
11
|
+
## 4.0.0
|
12
|
+
- [breaking] Drop support for Ruby <= 2.2
|
13
|
+
- Update ROTP
|
14
|
+
- Add Rails 6.1 support
|
15
|
+
- Remove timecop dependency
|
16
|
+
- Clarify changes in project ownership
|
17
|
+
- Bugfixes & cleanup
|
18
|
+
|
19
|
+
## 3.1.0
|
20
|
+
- Add Rails 6.0 support
|
21
|
+
- New gem signing certificate
|
22
|
+
- Fix paranoid-mode being ignored
|
23
|
+
|
24
|
+
## 3.0.3
|
25
|
+
- Add Rails 5.2 support
|
26
|
+
|
5
27
|
## 3.0.2
|
6
28
|
- Add Rails 5.1 support
|
7
29
|
|
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://github.com/tinfoil/devise-two-factor/actions/workflows/ci.yml/badge.svg)
|
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
|
|
@@ -227,3 +239,20 @@ require 'devise_two_factor/spec_helpers'
|
|
227
239
|
it_behaves_like "two_factor_authenticatable"
|
228
240
|
it_behaves_like "two_factor_backupable"
|
229
241
|
```
|
242
|
+
|
243
|
+
## Troubleshooting
|
244
|
+
If you are using Rails 4.x and Ruby >= 2.7, you may get an error like
|
245
|
+
|
246
|
+
```
|
247
|
+
An error occurred while loading ./spec/devise/models/two_factor_authenticatable_spec.rb.
|
248
|
+
Failure/Error: require 'devise'
|
249
|
+
|
250
|
+
NoMethodError:
|
251
|
+
undefined method `new' for BigDecimal:Class
|
252
|
+
```
|
253
|
+
see https://github.com/ruby/bigdecimal#which-version-should-you-select and https://github.com/ruby/bigdecimal/issues/127
|
254
|
+
for more details, but you should be able to solve this
|
255
|
+
by explicitly requiring an older version of bigdecimal in your gemfile like
|
256
|
+
```
|
257
|
+
gem "bigdecimal", "~> 1.4"
|
258
|
+
```
|
data/certs/tinfoil-cacert.pem
CHANGED
@@ -3,7 +3,7 @@ MIIHSjCCBTKgAwIBAgIJAK2u0LojMCNgMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD
|
|
3
3
|
VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEfMB0GA1UE
|
4
4
|
ChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEfMB0GA1UEAxMWVGluZm9pbCBTZWN1
|
5
5
|
cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYbc3VwcG9ydEB0aW5mb2lsc2VjdXJp
|
6
|
-
|
6
|
+
dHkuY29tMB4XDTIxMDkwOTE4MjIwMFoXDTI1MDkwOTE4MjIwMFowgZwxCzAJBgNV
|
7
7
|
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
8
8
|
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
9
9
|
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
@@ -27,15 +27,15 @@ c3VwcG9ydEB0aW5mb2lsc2VjdXJpdHkuY29tggkAra7QuiMwI2AwDwYDVR0TAQH/
|
|
27
27
|
BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQYwCQYDVR0SBAIwADArBglghkgBhvhC
|
28
28
|
AQ0EHhYcVGlueUNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAmBgNVHREEHzAdgRtz
|
29
29
|
dXBwb3J0QHRpbmZvaWxzZWN1cml0eS5jb20wDgYDVR0PAQH/BAQDAgEGMA0GCSqG
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
41
|
-----END CERTIFICATE-----
|
@@ -1,9 +1,9 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
MIIGADCCA+
|
2
|
+
MIIGADCCA+igAwIBAgIIHIF9ta6cW3YwDQYJKoZIhvcNAQENBQAwgZwxCzAJBgNV
|
3
3
|
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
4
4
|
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
5
5
|
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
6
|
-
|
6
|
+
eS5jb20wHhcNMjIwMzIyMjI1MzAwWhcNMjUwOTA5MTgyMjAwWjCBiDELMAkGA1UE
|
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
|
+
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
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', '<
|
28
|
-
s.add_runtime_dependency 'activesupport', '<
|
24
|
+
s.add_runtime_dependency 'railties', '< 7.1'
|
25
|
+
s.add_runtime_dependency 'activesupport', '< 7.1'
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -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,16 @@ 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
|
+
|
39
|
+
if self.consumed_timestep
|
40
|
+
# reconstruct the timestamp of the last consumed timestep
|
41
|
+
after_timestamp = self.consumed_timestep * otp.interval
|
42
|
+
end
|
43
|
+
|
44
|
+
if totp.verify(code.gsub(/\s+/, ""), drift_behind: self.class.otp_allowed_drift, drift_ahead: self.class.otp_allowed_drift, after: after_timestamp)
|
45
|
+
return consume_otp!
|
46
|
+
end
|
36
47
|
|
37
48
|
false
|
38
49
|
end
|
@@ -56,6 +67,7 @@ module Devise
|
|
56
67
|
end
|
57
68
|
|
58
69
|
def clean_up_passwords
|
70
|
+
super
|
59
71
|
self.otp_attempt = nil
|
60
72
|
end
|
61
73
|
|
@@ -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)
|
@@ -64,6 +66,42 @@ RSpec.shared_examples 'two_factor_authenticatable' do
|
|
64
66
|
expect(subject.validate_and_consume_otp!(consumed_otp)).to be false
|
65
67
|
end
|
66
68
|
end
|
69
|
+
|
70
|
+
context 'given a valid OTP used multiple times within the allowed drift' do
|
71
|
+
let(:consumed_otp) { ROTP::TOTP.new(otp_secret).at(Time.now) }
|
72
|
+
|
73
|
+
before do
|
74
|
+
subject.validate_and_consume_otp!(consumed_otp)
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'after the otp interval' do
|
78
|
+
before do
|
79
|
+
travel_to(subject.otp.interval.seconds.from_now)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'fails to validate' do
|
83
|
+
expect(subject.validate_and_consume_otp!(consumed_otp)).to be false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'given a valid OTP used multiple times within the allowed drift after a subsequent login' do
|
89
|
+
let(:consumed_otp) { ROTP::TOTP.new(otp_secret).at(Time.now - subject.class.otp_allowed_drift) }
|
90
|
+
|
91
|
+
before do
|
92
|
+
travel_to(subject.class.otp_allowed_drift.seconds.ago)
|
93
|
+
subject.validate_and_consume_otp!(consumed_otp)
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'after the otp interval' do
|
97
|
+
it 'fails to validate' do
|
98
|
+
travel_to(subject.class.otp_allowed_drift.seconds.from_now)
|
99
|
+
next_otp = ROTP::TOTP.new(otp_secret).at(Time.now)
|
100
|
+
expect(subject.validate_and_consume_otp!(next_otp)).to be true
|
101
|
+
expect(subject.validate_and_consume_otp!(consumed_otp)).to be false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
67
105
|
end
|
68
106
|
|
69
107
|
it 'validates a precisely correct OTP' do
|
@@ -71,23 +109,28 @@ RSpec.shared_examples 'two_factor_authenticatable' do
|
|
71
109
|
expect(subject.validate_and_consume_otp!(otp)).to be true
|
72
110
|
end
|
73
111
|
|
112
|
+
it 'validates a precisely correct OTP with whitespace' do
|
113
|
+
otp = ROTP::TOTP.new(otp_secret).at(Time.now)
|
114
|
+
expect(subject.validate_and_consume_otp!(otp.split("").join(" "))).to be true
|
115
|
+
end
|
116
|
+
|
74
117
|
it 'fails a nil OTP value' do
|
75
118
|
otp = nil
|
76
119
|
expect(subject.validate_and_consume_otp!(otp)).to be false
|
77
120
|
end
|
78
121
|
|
79
122
|
it 'validates an OTP within the allowed drift' do
|
80
|
-
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift
|
123
|
+
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift)
|
81
124
|
expect(subject.validate_and_consume_otp!(otp)).to be true
|
82
125
|
end
|
83
126
|
|
84
127
|
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
|
128
|
+
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift * 2)
|
86
129
|
expect(subject.validate_and_consume_otp!(otp)).to be false
|
87
130
|
end
|
88
131
|
|
89
132
|
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
|
133
|
+
otp = ROTP::TOTP.new(otp_secret).at(Time.now - subject.class.otp_allowed_drift * 2)
|
91
134
|
expect(subject.validate_and_consume_otp!(otp)).to be false
|
92
135
|
end
|
93
136
|
end
|
@@ -95,15 +138,15 @@ RSpec.shared_examples 'two_factor_authenticatable' do
|
|
95
138
|
describe '#otp_provisioning_uri' do
|
96
139
|
let(:otp_secret_length) { subject.class.otp_secret_length }
|
97
140
|
let(:account) { Faker::Internet.email }
|
98
|
-
let(:issuer) {
|
141
|
+
let(:issuer) { 'Tinfoil' }
|
99
142
|
|
100
|
-
it
|
101
|
-
expect(subject.otp_provisioning_uri(account)).to match(%r{otpauth://totp/#{account}\?secret=\w{#{otp_secret_length}}})
|
143
|
+
it 'should return uri with specified account' do
|
144
|
+
expect(subject.otp_provisioning_uri(account)).to match(%r{otpauth://totp/#{CGI.escape(account)}\?secret=\w{#{otp_secret_length}}})
|
102
145
|
end
|
103
146
|
|
104
147
|
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}(&|$)})
|
148
|
+
expect(subject.otp_provisioning_uri(account, issuer: issuer)).to match(%r{otpauth://totp/#{issuer}:#{CGI.escape(account)}\?.*secret=\w{#{otp_secret_length}}(&|$)})
|
149
|
+
expect(subject.otp_provisioning_uri(account, issuer: issuer)).to match(%r{otpauth://totp/#{issuer}:#{CGI.escape(account)}\?.*issuer=#{issuer}(&|$)})
|
107
150
|
end
|
108
151
|
end
|
109
152
|
end
|
@@ -1,2 +1,8 @@
|
|
1
|
+
require 'active_support/testing/time_helpers'
|
2
|
+
|
1
3
|
require 'devise_two_factor/spec_helpers/two_factor_authenticatable_shared_examples'
|
2
4
|
require 'devise_two_factor/spec_helpers/two_factor_backupable_shared_examples'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.include ActiveSupport::Testing::TimeHelpers
|
8
|
+
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
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,11 +1,11 @@
|
|
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.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shane Wilton
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain:
|
11
11
|
- |
|
@@ -14,7 +14,7 @@ cert_chain:
|
|
14
14
|
VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEfMB0GA1UE
|
15
15
|
ChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEfMB0GA1UEAxMWVGluZm9pbCBTZWN1
|
16
16
|
cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYbc3VwcG9ydEB0aW5mb2lsc2VjdXJp
|
17
|
-
|
17
|
+
dHkuY29tMB4XDTIxMDkwOTE4MjIwMFoXDTI1MDkwOTE4MjIwMFowgZwxCzAJBgNV
|
18
18
|
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
19
19
|
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
20
20
|
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
@@ -38,25 +38,25 @@ cert_chain:
|
|
38
38
|
BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQYwCQYDVR0SBAIwADArBglghkgBhvhC
|
39
39
|
AQ0EHhYcVGlueUNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAmBgNVHREEHzAdgRtz
|
40
40
|
dXBwb3J0QHRpbmZvaWxzZWN1cml0eS5jb20wDgYDVR0PAQH/BAQDAgEGMA0GCSqG
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
52
|
-----END CERTIFICATE-----
|
53
53
|
- |
|
54
54
|
-----BEGIN CERTIFICATE-----
|
55
|
-
MIIGADCCA+
|
55
|
+
MIIGADCCA+igAwIBAgIIHIF9ta6cW3YwDQYJKoZIhvcNAQENBQAwgZwxCzAJBgNV
|
56
56
|
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
|
57
57
|
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
|
58
58
|
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
|
59
|
-
|
59
|
+
eS5jb20wHhcNMjIwMzIyMjI1MzAwWhcNMjUwOTA5MTgyMjAwWjCBiDELMAkGA1UE
|
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
|
+
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
88
|
-----END CERTIFICATE-----
|
89
|
-
date:
|
89
|
+
date: 2022-03-24 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: '
|
97
|
+
version: '7.1'
|
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: '
|
104
|
+
version: '7.1'
|
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: '
|
111
|
+
version: '7.1'
|
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: '
|
118
|
+
version: '7.1'
|
119
119
|
- !ruby/object:Gem::Dependency
|
120
120
|
name: attr_encrypted
|
121
121
|
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,29 +254,15 @@ 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: []
|
274
260
|
extensions: []
|
275
261
|
extra_rdoc_files: []
|
276
262
|
files:
|
263
|
+
- ".github/workflows/ci.yml"
|
277
264
|
- ".gitignore"
|
278
265
|
- ".rspec"
|
279
|
-
- ".travis.yml"
|
280
266
|
- Appraisals
|
281
267
|
- CHANGELOG.md
|
282
268
|
- CONTRIBUTING.md
|
@@ -288,12 +274,14 @@ files:
|
|
288
274
|
- certs/tinfoil-cacert.pem
|
289
275
|
- certs/tinfoilsecurity-gems-cert.pem
|
290
276
|
- devise-two-factor.gemspec
|
291
|
-
- gemfiles/
|
292
|
-
- gemfiles/
|
293
|
-
- gemfiles/
|
294
|
-
- gemfiles/
|
295
|
-
- gemfiles/
|
296
|
-
- gemfiles/
|
277
|
+
- gemfiles/rails_4.1.gemfile
|
278
|
+
- gemfiles/rails_4.2.gemfile
|
279
|
+
- gemfiles/rails_5.0.gemfile
|
280
|
+
- gemfiles/rails_5.1.gemfile
|
281
|
+
- gemfiles/rails_5.2.gemfile
|
282
|
+
- gemfiles/rails_6.0.gemfile
|
283
|
+
- gemfiles/rails_6.1.gemfile
|
284
|
+
- gemfiles/rails_7.0.gemfile
|
297
285
|
- lib/devise-two-factor.rb
|
298
286
|
- lib/devise_two_factor/models.rb
|
299
287
|
- lib/devise_two_factor/models/two_factor_authenticatable.rb
|
@@ -313,7 +301,7 @@ homepage: https://github.com/tinfoil/devise-two-factor
|
|
313
301
|
licenses:
|
314
302
|
- MIT
|
315
303
|
metadata: {}
|
316
|
-
post_install_message:
|
304
|
+
post_install_message:
|
317
305
|
rdoc_options: []
|
318
306
|
require_paths:
|
319
307
|
- lib
|
@@ -328,9 +316,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
328
316
|
- !ruby/object:Gem::Version
|
329
317
|
version: '0'
|
330
318
|
requirements: []
|
331
|
-
|
332
|
-
|
333
|
-
signing_key:
|
319
|
+
rubygems_version: 3.2.32
|
320
|
+
signing_key:
|
334
321
|
specification_version: 4
|
335
322
|
summary: Barebones two-factor authentication with Devise
|
336
323
|
test_files:
|
metadata.gz.sig
CHANGED
Binary file
|
data/.travis.yml
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
language: ruby
|
3
|
-
cache: bundler
|
4
|
-
before_install:
|
5
|
-
- gem i rubygems-update -v '<3' && update_rubygems
|
6
|
-
- gem update bundler
|
7
|
-
gemfile:
|
8
|
-
- Gemfile
|
9
|
-
- gemfiles/rails_4_1.gemfile
|
10
|
-
- gemfiles/rails_4_2.gemfile
|
11
|
-
- gemfiles/rails_5_0.gemfile
|
12
|
-
- gemfiles/rails_5_1.gemfile
|
13
|
-
- gemfiles/rails_5_2.gemfile
|
14
|
-
- gemfiles/rails_6_0.gemfile
|
15
|
-
rvm:
|
16
|
-
- "2.1"
|
17
|
-
- "2.2"
|
18
|
-
- "2.3.4"
|
19
|
-
- "2.4.0"
|
20
|
-
- "2.4.1"
|
21
|
-
- "2.5"
|
22
|
-
- "2.6"
|
23
|
-
matrix:
|
24
|
-
exclude:
|
25
|
-
- rvm: "2.1"
|
26
|
-
gemfile: gemfiles/rails_5_0.gemfile
|
27
|
-
- rvm: "2.2"
|
28
|
-
gemfile: gemfiles/rails_5_0.gemfile
|
29
|
-
- rvm: "2.1"
|
30
|
-
gemfile: gemfiles/rails_5_1.gemfile
|
31
|
-
- rvm: "2.2"
|
32
|
-
gemfile: gemfiles/rails_5_1.gemfile
|
33
|
-
- rvm: "2.1"
|
34
|
-
gemfile: gemfiles/rails_5_2.gemfile
|
35
|
-
- rvm: "2.2"
|
36
|
-
gemfile: gemfiles/rails_5_2.gemfile
|
37
|
-
- rvm: "2.1"
|
38
|
-
gemfile: gemfiles/rails_6_0.gemfile
|
39
|
-
- rvm: "2.2"
|
40
|
-
gemfile: gemfiles/rails_6_0.gemfile
|
41
|
-
- rvm: "2.3.4"
|
42
|
-
gemfile: gemfiles/rails_6_0.gemfile
|
43
|
-
- rvm: "2.4.0"
|
44
|
-
gemfile: gemfiles/rails_6_0.gemfile
|
45
|
-
- rvm: "2.4.1"
|
46
|
-
gemfile: gemfiles/rails_6_0.gemfile
|