devise-two-factor 3.1.0 → 4.0.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.
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 | 
             
            [](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 |