pax_global_header 0000666 0000000 0000000 00000000064 12576132612 0014517 g ustar 00root root 0000000 0000000 52 comment=db3d5d568c4a411d5348fa55f75a31c2a2a5b4c7
devise-two-factor-2.0.0/ 0000775 0000000 0000000 00000000000 12576132612 0015060 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/.gitignore 0000664 0000000 0000000 00000001460 12576132612 0017051 0 ustar 00root root 0000000 0000000 Gemfile.lock
*.gem
# rcov generated
coverage
coverage.data
# yard generated
doc
.yardoc
# bundler
.bundle
# jeweler generated
pkg
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
#
# * Create a file at ~/.gitignore
# * Include files you want ignored
# * Run: git config --global core.excludesfile ~/.gitignore
#
# After doing this, these files will be ignored in all your git projects,
# saving you from having to 'pollute' every project you touch with them
#
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
#
# For MacOS:
#
#.DS_Store
# For TextMate
#*.tmproj
#tmtags
# For emacs:
#*~
#\#*
#.\#*
# For vim:
#*.swp
# For redcar:
#.redcar
# For rubinius:
#*.rbc
devise-two-factor-2.0.0/.rspec 0000664 0000000 0000000 00000000010 12576132612 0016164 0 ustar 00root root 0000000 0000000 --color
devise-two-factor-2.0.0/.travis.yml 0000664 0000000 0000000 00000000164 12576132612 0017172 0 ustar 00root root 0000000 0000000 language: ruby
cache: bundler
rvm:
- "1.9.3"
- "2.0.0"
- "2.1"
- "2.2"
- jruby-19mode # JRuby in 1.9 mode
devise-two-factor-2.0.0/CONTRIBUTING.md 0000664 0000000 0000000 00000002470 12576132612 0017314 0 ustar 00root root 0000000 0000000 We love pull requests. Here's a quick guide:
1. Fork the repo.
2. Run the tests. We only take pull requests with passing tests, and it's great
to know that you have a clean slate: `bundle && rake`
3. Add a test for your change. Only refactoring and documentation changes
require no new tests. If you are adding functionality or fixing a bug, we need
a test!
4. Make the test pass.
5. Push to your fork and submit a pull request.
At this point you're waiting on us. We like to at least comment on, if not
accept, pull requests within three business days (and, typically, one business
day). We may suggest some changes or improvements or alternatives.
Some things that will increase the chance that your pull request is accepted,
taken straight from the Ruby on Rails guide:
* Use Rails idioms and helpers
* Include tests that fail without your code, and pass with it
* Update the documentation, the surrounding one, examples elsewhere, guides,
whatever is affected by your contribution
Syntax:
* Two spaces, no tabs.
* No trailing whitespace. Blank lines should not have any space.
* Prefer &&/|| over and/or.
* MyClass.my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
* a = b and not a=b.
* Follow the conventions you see used in the source already.
And in case we didn't emphasize it enough: we love tests!
devise-two-factor-2.0.0/Gemfile 0000664 0000000 0000000 00000000046 12576132612 0016353 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
gemspec
devise-two-factor-2.0.0/LICENSE 0000664 0000000 0000000 00000002101 12576132612 0016057 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2014 Tinfoil Security, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
devise-two-factor-2.0.0/README.md 0000664 0000000 0000000 00000024431 12576132612 0016343 0 ustar 00root root 0000000 0000000 # Devise-Two-Factor Authentication
By [Tinfoil Security](http://tinfoilsecurity.com/)
[](https://travis-ci.org/tinfoil/devise-two-factor)
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_Algorithm) scheme. It:
* Allows you to incorporate two-factor authentication into your existing models
* Is opinionated about security, so you don't have to be
* Integrates easily with two-factor applications like Google Authenticator and Authy
* Is extensible, and includes two-factor backup codes as an example of how plugins can be structured
## Example App
An example Rails 4 application is provided in demo/. It showcases a minimal example of devise-two-factor in action, and can act as a reference for integrating the gem into your own application.
For the demo app to work, create an encryption key and store it as an environment variable. One way to do this is to create a file named `local_env.yml` in the application root. Set the value of 'ENCRYPTION_KEY' in the YML file. That value will be loaded into the application environment by `application.rb`.
## Getting Started
Devise-two-factor doesn't require much to get started, but there are a few prerequisites before you can start using it in your application.
First, you'll need a Rails application setup with Devise. Visit the Devise [homepage](https://github.com/plataformatec/devise) for instructions.
Next, since devise-two-factor encrypts its secrets before storing them in the database, you'll need to generate an encryption key, and store it in an environment variable of your choice. Set the encryption key in the model that uses devise:
```
devise :two_factor_authenticatable,
:otp_secret_encryption_key => ENV['YOUR_ENCRYPTION_KEY_HERE']
```
Finally, you can automate all of the required setup by simply running:
```ruby
rails generate devise_two_factor MODEL ENVIRONMENT_VARIABLE
```
Where MODEL is the name of the model you wish to add two-factor functionality to, and ENVIRONMENT_VARIABLE is the name of the variable you're storing your encryption key in.
This generator will add a few columns to the specified model:
* encrypted_otp_secret
* encrypted_otp_secret_iv
* encrypted_otp_secret_salt
* otp_required_for_login
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 authenticatation.
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.
If you're running Rails 4, you'll also need to whitelist `:otp_attempt` as a permitted parameter in Devise `:sign_in` controller. You can do this by adding the following to your `application_controller.rb`
```ruby
before_action :configure_permitted_parameters, if: :devise_controller?
...
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) << :otp_attempt
end
```
**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.**
## Designing Your Workflow
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.
There are two key workflows you'll have to think about:
1. Logging in with two-factor authentication
2. Enabling two-factor authentication for a given user
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).
### Logging In
Logging in with two-factor authentication works extremely similarly to regular database authentication in Devise. The TwoFactorAuthenticatable strategy accepts three parameters:
1. email
2. password
3. otp_attempt (Their one-time password for this session)
These parameters can be submitted to the standard Devise login route, and the strategy will handle the authentication of the user for you.
### Disabling Automatic Login After Password Resets
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 2FA requirement.
Because of this, you need to set `sign_in_after_reset_password` to false (either globally in your Devise initializer or via `devise_for`)
### Enabling Two-Factor Authentication
Enabling two-factor authentication for a user is easy. For example, if my user model were named User, I could do the following:
```ruby
current_user.otp_required_for_login = true
current_user.otp_secret = User.generate_otp_secret
current_user.save!
```
Before you can do this however, you need to decide how you're going to transmit two-factor tokens to a user. Common strategies include sending an SMS, or using a mobile application such as Google Authenticator.
At Tinfoil Security, we opted to use the excellent [rqrcode-rails3](https://github.com/samvincent/rqrcode-rails3) gem to generate a QR-code representing the user's secret key, which can then be scanned by any mobile two-factor authentication client.
If you instead to decide to send the one-time password to the user directly, such as via SMS, you'll need a mechanism for generating the one-time password on the server:
```ruby
current_user.current_otp
```
The generated code will be valid for the duration specified by otp_allowed_drift.
However you decide to handle enrollment, there are a few important considerations to be made:
* Whether you'll force the use of two-factor authentication, and if so, how you'll migrate existing users to system, and what your onboarding experience will look like
* If you authenticate using SMS, you'll want to verify the user's ownership of the phone, in much the same way you're probably verifying their email address
* How you'll handle device revocation in the event that a user loses access to their device, or that device is rendered temporarily unavailable (This gem includes TwoFactorBackupable as an example extension meant to solve this problem)
It sounds like a lot of work, but most of these problems have been very elegantly solved by other people. We recommend taking a look at the excellent workflows used by Heroku and Google for inspiration.
## Backup Codes
Devise-two-factor is designed with extensibility in mind. One such extension, TwoFactorBackupable, is included and serves as a good example of how to extend this gem. This plugin allows you to add the ability to generate single-use backup codes for a user, which they may use to bypass two-factor authentication, in the event that they lose access to their device.
To install it, you need to add the :two_factor_backupable directive to your model.
```ruby
devise :two_factor_backupable
```
You'll also be required to enable the :two_factor_backupable strategy, by adding the following line to your Warden config in your Devise initializer, substituting :user for the name of your Devise scope.
```ruby
manager.default_strategies(:scope => :user).unshift :two_factor_backupable
```
The final installation step is dependent on your version of Rails. If you're not running Rails 4, skip to the next section. Otherwise, create the following migration:
```ruby
class AddDeviseTwoFactorBackupableToUsers < ActiveRecord::Migration
def change
add_column :users, :otp_backup_codes, :string, array: true
end
end
```
You can then generate backup codes for a user:
```ruby
codes = current_user.generate_otp_backup_codes!
current_user.save!
# Display codes to the user somehow!
```
The backup codes are stored in the database as bcrypt hashes, so be sure to display them to the user at this point. If all went well, the user should be able to login using each of the generated codes in place of their two-factor token. Each code is single-use, and generating a new set of backup codes for that user will invalidate all of the old ones.
You can customize the length of each code, and the number of codes generated by passing the options into `:two_factor_backupable` in the Devise directive:
```ruby
devise :two_factor_backupable, otp_backup_code_length: 32,
otp_number_of_backup_codes: 10
```
### Help! I'm not using Rails 4.0!
Don't worry! TwoFactorBackupable stores the backup codes as an array of strings in the database. In Rails 4.0 this is supported natively, but in earlier versions you can use a gem to emulate this behaviour: we recommend [activerecord-postgres-array](https://github.com/tlconnor/activerecord-postgres-array).
You'll then simply have to create a migration to add an array named `otp_backup_codes` to your model. If you use the above gem, this migration might look like:
```ruby
class AddTwoFactorBackupCodesToUsers < ActiveRecord::Migration
def change
add_column :users, :otp_backup_codes, :string_array
end
end
```
Now just continue with the setup in the previous section, skipping the generator step.
## Testing
Devise-two-factor includes shared-examples for both TwoFactorAuthenticatable and TwoFactorBackupable. Adding the following two lines to the specs for your two-factor enabled models will allow you to test your models for two-factor functionality:
```ruby
require 'devise_two_factor/spec_helpers'
it_behaves_like "two_factor_authenticatable"
it_behaves_like "two_factor_backupable"
```
devise-two-factor-2.0.0/Rakefile 0000664 0000000 0000000 00000001036 12576132612 0016525 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'rubygems'
require 'bundler'
begin
Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
$stderr.puts e.message
$stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code
end
require 'rake'
require 'rspec/core'
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) do |spec|
spec.pattern = FileList['spec/**/*_spec.rb']
end
desc "Code coverage detail"
task :simplecov do
ENV['COVERAGE'] = "true"
Rake::Task['spec'].execute
end
task :default => :spec
devise-two-factor-2.0.0/UPGRADING.md 0000664 0000000 0000000 00000000543 12576132612 0016724 0 ustar 00root root 0000000 0000000 # Guide to upgrading from 1.x to 2.x
Pull request #43 added a new field to protect against "shoulder-surfing" attacks. If upgrading, you'll need to add the `:consumed_timestep` column to your `Users` model.
```ruby
class AddConsumedTimestepToUsers < ActiveRecord::Migration
def change
add_column :users, :consumed_timestep, :integer
end
end
```
devise-two-factor-2.0.0/certs/ 0000775 0000000 0000000 00000000000 12576132612 0016200 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/certs/tinfoil-cacert.pem 0000664 0000000 0000000 00000005035 12576132612 0021611 0 ustar 00root root 0000000 0000000 -----BEGIN CERTIFICATE-----
MIIHSjCCBTKgAwIBAgIJAK2u0LojMCNgMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEfMB0GA1UE
ChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEfMB0GA1UEAxMWVGluZm9pbCBTZWN1
cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYbc3VwcG9ydEB0aW5mb2lsc2VjdXJp
dHkuY29tMB4XDTExMTIyNzA1MDc0N1oXDTIxMTIyNDA1MDc0N1owgZwxCzAJBgNV
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR8wHQYDVQQDExZUaW5mb2lsIFNlY3Vy
aXR5LCBJbmMuMSowKAYJKoZIhvcNAQkBFhtzdXBwb3J0QHRpbmZvaWxzZWN1cml0
eS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqbHvsSj0H0FB1
0gLYoDK1BKugkSB2DZeZZHP6B1UdWRahJXJP9oT1lhfQxx8iX4cgEi7JU3NqA6NR
cIRFQ50eH/qlmgs7909gaf8pDaeC0vR3wd0GeRg6qr1eDEnkzIyr/D1AMiX6H1eP
Y7J3SfrdaL3gft2iPRKGkgqsXR7oBNLA3n/ShiNgPXqRDl1CCj6aMY0cn5ROFScz
vT2FUB4DEwPD2l18m1p99OnXqsOLL2J65qA2+cI8FtgFmlwIi5oSf+URvIdNx+cH
lInlAtVHCvAKYLY0dlQ7czMQBcRpYjp2rwPt9f2ksq9b/voMTBABYHFV+IVn8svv
GZ5e1+icjtr/R7dCGmCdEdFLXVxafmZhukymG9USv9DKuv1qh7r4q8KaPIE8n7nQ
m97jENFfsgnwv+nUmIJ3tzuW5ZxO7A0tIIYdwzt0UjrO3ya4R5bTFXr4bnzZ/g/s
CLknWqg1BCRlPd6LnpVGPT0gNDV1pEO25wE3A3Yy0Ujxudcgay/CgUhnlU11qOAc
xmar2fhNZsviUhndd/220Ad5QMV2XzcAiopJIeu0juIVGRQM7x2h19Hsp0m6sOEF
jfhvbdUa4nvmIFeYFY+hr/YkTmG9ZjyBa8YaZXhwjhSmKCQ374J7mn5e0Cryuvi5
tYhwJn8rdwYZF/h2qqfEu8vaLoD09QIDAQABo4IBizCCAYcwHQYDVR0OBBYEFMmT
/x412UH+5OHqgleeTjLOv6iHMIHRBgNVHSMEgckwgcaAFMmT/x412UH+5OHqglee
TjLOv6iHoYGipIGfMIGcMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNV
BAcTCVBhbG8gQWx0bzEfMB0GA1UEChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEf
MB0GA1UEAxMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYb
c3VwcG9ydEB0aW5mb2lsc2VjdXJpdHkuY29tggkAra7QuiMwI2AwDwYDVR0TAQH/
BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAQYwCQYDVR0SBAIwADArBglghkgBhvhC
AQ0EHhYcVGlueUNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAmBgNVHREEHzAdgRtz
dXBwb3J0QHRpbmZvaWxzZWN1cml0eS5jb20wDgYDVR0PAQH/BAQDAgEGMA0GCSqG
SIb3DQEBBQUAA4ICAQAD7nsmdg1vStFTi8/P2rgSFxlXxZT0aaVVB1bFBe/m5phb
MjvKQ7VAuiFZxEp3oBNdXTi4FzT1QjhRKdlYMgKZQnU+XDLLIYuoi+atxr5qGD4B
m58eCGO6ZEutVs3Z7s63UOm5rG0zJ+IEWh8VHMvxgSwiX88QyJuhOtqeiKhIeSGZ
2/qGGMWgsScnPg3J/ZVOIKUn/4ljEDlC64Gh5Zz5PZUbGSXPMhdYbSD3EknDvEGA
omYW4jlPMeK3GJgwAZu9yWC8hHGFpiMca/6W0W622cg7MX+CByOd+24dvWFnOHur
NHBqI+kZo/7Sjdm8x7TWEOz9Rfh5RPMeVNRTj4iq0B6GzfaecT3Yn8y7HTRRiWns
IYpP+iHCFYnZhDZsFi4ccKqxKtj6BGmhLf00FuNpgkvrsU3cXrhidkCaYGYj1SME
1CMfy0PPKVDpDKeFb6y0NvLf4d57vi99dZAvSJEO18rrNEHN2VUfCKRPA/mBSMLY
RxKWAby1YVT/8iC9JWix9yvgsEUtTLyOFxLGtgj3PRiQSvbNe/jK4G9WAIFe6R9E
9+HUO2owcmyFXyU3rC/z/lBfDP+2pIRFdUVRGlYCMeUqR08PXpfva5+NQz21fC69
FPRMZvXh70ntnFaWAq+j6NCss+AauC8ckECiQsTgbzJvJd6C3mJXYHkNCQODhg==
-----END CERTIFICATE-----
devise-two-factor-2.0.0/certs/tinfoilsecurity-gems-cert.pem 0000664 0000000 0000000 00000004025 12576132612 0024024 0 ustar 00root root 0000000 0000000 -----BEGIN CERTIFICATE-----
MIIFyjCCA7KgAwIBAgIJAK2u0LojMCNtMA0GCSqGSIb3DQEBDQUAMIGcMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEfMB0GA1UE
ChMWVGluZm9pbCBTZWN1cml0eSwgSW5jLjEfMB0GA1UEAxMWVGluZm9pbCBTZWN1
cml0eSwgSW5jLjEqMCgGCSqGSIb3DQEJARYbc3VwcG9ydEB0aW5mb2lsc2VjdXJp
dHkuY29tMB4XDTE0MDUyMDIxMTAwMFoXDTE2MDUyMDIxMTAwMFowgZwxCzAJBgNV
BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQK
ExZUaW5mb2lsIFNlY3VyaXR5LCBJbmMuMR0wGwYDVQQDExR0aW5mb2lsc2VjdXJp
dHktZ2VtczEsMCoGCSqGSIb3DQEJARYdZW5naW5lZXJzQHRpbmZvaWxzZWN1cml0
eS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDNJYNH8D+8lACL
t3KzjEIPs3XVBCPaMm2eD/Xk9OOTuDV/NqgMK0icD9MRxMUtS3SCrC9QcPocXT76
f2LQ3yVJuK+rBUasymEES47PIx2czC4n4Hga0xPPuBpioO26oaRFsobyzh9RPOIb
nYfpjyqtdrbm+YyM3sPR4XzFirv9xomT4E9T4RCLgOQHTcLKL9K9m+EN7PeVdVUX
V0Pa7cVs2vJUKedsd7vnr6Lzbn8ToPk/7J/4W931PbaeI5yg9ZuaRa9K2IaY1TkP
I67NW4qKitBVepRlXw6Sb7TYcUncWEQ/eC5CpnOmqUrG5tfGD8cc5aGZOkitW/VX
ZgVj81xgCv1hk4HjErrqq4FBNAaCSNyBfwR0TUYqg1lN1nbNjOKwfb6YRn06R2ov
cFJG0tmGhsQULCr6fW8u2TfSM+U9WFSIJx2griureY7EZPwg/MgsUiWUWMFemz3G
VYXWJR3dN2pW9Uqr3rkjKZbA0bstGWahJO9HuFdDakQxoaTPYPtTQDC+kskkO6lK
G1KLIoZ1iLZzB1Ks1vEeyE7lp1imWgpUq+q23PFkt1gIBi/4tGvzsLZye25QU2Y+
XLzldCNm+DyRFXZ+Q+bK33IveUeUWEOv4T1qTXHAOypyzmgodVRG/PrlsSMOBfE5
15kG1mDMGjRcCpEtlskgxUbf7qM7hQIDAQABow0wCzAJBgNVHRMEAjAAMA0GCSqG
SIb3DQEBDQUAA4ICAQCLXzGJOr0isGHscTvm73ReEAOv4g0IOSXjfHfHAOWKhzdM
g+D8nrzhy8wnARqAt2Ob4I+R9scEIfI5MPp/C5HHqWed4m0W0Uygx3V3qyixavkc
nVUJMZ4TPS6W48IHdGGVD45hopx7ycFy+iPm7QUFk4sg044dO53mkScTetm2AvIE
xDTotsFNpn/hrAnzXlH4MQQ7LKXAedPmFi8Jv5nJwv9BnEGJQJhvzQtdx7le4S8J
a78vwAq429N2gVnfSdeU9v9QqdHOF1215lC6qaDI4bk8hVE4RyMxSBZmWKhnPLAm
jFXGc6Wj2yF7HQ2YtEGAAEyjH+tAwF35STv+J3eweUFhyGZPH8Sf+b+UKZc9UF1D
J/VmzQd9D9RaB+pOclDYR3Uiji5EBq1La2FPg48hA0uCd4KJ9dBGwNrxvjDNSBW0
FiM1vjR6AVxIAhOwICeWG6QTvH5Jrnq/UDBnnK/KALCbFw3YbbhOyy+295jta7xf
r32d4cJAvbDF1C6t2JRjNwi0ANgPw0cytl+8yvCyXpXMZpT0YpDk76XICo97SOHI
5C31v4YyRBnNCp0pN66nxYX2avEiQ8riTBP5mlkPPOhsIoYQHHe2Uj75aVpu0LZ3
cdFzuO4GC1dV0Wv+dsDm+MyF7DT5E9pUPXpnMJuPvPrFpCb+wrFlszW9hGjXbQ==
-----END CERTIFICATE-----
devise-two-factor-2.0.0/demo/ 0000775 0000000 0000000 00000000000 12576132612 0016004 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/.gitignore 0000664 0000000 0000000 00000000722 12576132612 0017775 0 ustar 00root root 0000000 0000000 # See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config.
/.bundle
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*.log
/tmp
devise-two-factor-2.0.0/demo/Gemfile 0000664 0000000 0000000 00000002330 12576132612 0017275 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.1.0'
# Use postgresql as the database for Active Record
gem 'pg'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.3'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc
gem 'devise'
gem 'devise-two-factor', :path => '../'
gem 'rqrcode-rails3'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use unicorn as the app server
# gem 'unicorn'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
# Use debugger
# gem 'debugger', group: [:development, :test]
devise-two-factor-2.0.0/demo/README.rdoc 0000664 0000000 0000000 00000000736 12576132612 0017620 0 ustar 00root root 0000000 0000000 == README
This README would normally document whatever steps are necessary to get the
application up and running.
Things you may want to cover:
* Ruby version
* System dependencies
* Configuration
* Database creation
* Database initialization
* How to run the test suite
* Services (job queues, cache servers, search engines, etc.)
* Deployment instructions
* ...
Please feel free to use a different markup language if you do not plan to run
rake doc:app.
devise-two-factor-2.0.0/demo/Rakefile 0000664 0000000 0000000 00000000371 12576132612 0017452 0 ustar 00root root 0000000 0000000 # Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
Rails.application.load_tasks
devise-two-factor-2.0.0/demo/app/ 0000775 0000000 0000000 00000000000 12576132612 0016564 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/assets/ 0000775 0000000 0000000 00000000000 12576132612 0020066 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/assets/images/ 0000775 0000000 0000000 00000000000 12576132612 0021333 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/assets/images/.keep 0000664 0000000 0000000 00000000000 12576132612 0022246 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/assets/javascripts/ 0000775 0000000 0000000 00000000000 12576132612 0022417 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/assets/javascripts/application.js 0000664 0000000 0000000 00000001230 12576132612 0025254 0 ustar 00root root 0000000 0000000 // This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
devise-two-factor-2.0.0/demo/app/assets/javascripts/home.js.coffee 0000664 0000000 0000000 00000000323 12576132612 0025131 0 ustar 00root root 0000000 0000000 # Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
devise-two-factor-2.0.0/demo/app/assets/stylesheets/ 0000775 0000000 0000000 00000000000 12576132612 0022442 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/assets/stylesheets/application.css 0000664 0000000 0000000 00000001253 12576132612 0025460 0 ustar 00root root 0000000 0000000 /*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any styles
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require_tree .
*= require_self
*/
devise-two-factor-2.0.0/demo/app/assets/stylesheets/home.css.scss 0000664 0000000 0000000 00000000257 12576132612 0025062 0 ustar 00root root 0000000 0000000 // Place all the styles related to the home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
devise-two-factor-2.0.0/demo/app/controllers/ 0000775 0000000 0000000 00000000000 12576132612 0021132 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/controllers/application_controller.rb 0000664 0000000 0000000 00000000614 12576132612 0026226 0 ustar 00root root 0000000 0000000 class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) << :otp_attempt
end
end
devise-two-factor-2.0.0/demo/app/controllers/concerns/ 0000775 0000000 0000000 00000000000 12576132612 0022744 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/controllers/concerns/.keep 0000664 0000000 0000000 00000000000 12576132612 0023657 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/controllers/home_controller.rb 0000664 0000000 0000000 00000000103 12576132612 0024644 0 ustar 00root root 0000000 0000000 class HomeController < ApplicationController
def index
end
end
devise-two-factor-2.0.0/demo/app/controllers/users_controller.rb 0000664 0000000 0000000 00000000546 12576132612 0025070 0 ustar 00root root 0000000 0000000 class UsersController < ApplicationController
def disable_otp
current_user.otp_required_for_login = false
current_user.save!
redirect_to home_index_path
end
def enable_otp
current_user.otp_secret = User.generate_otp_secret
current_user.otp_required_for_login = true
current_user.save!
redirect_to home_index_path
end
end
devise-two-factor-2.0.0/demo/app/helpers/ 0000775 0000000 0000000 00000000000 12576132612 0020226 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/helpers/application_helper.rb 0000664 0000000 0000000 00000000035 12576132612 0024413 0 ustar 00root root 0000000 0000000 module ApplicationHelper
end
devise-two-factor-2.0.0/demo/app/helpers/home_helper.rb 0000664 0000000 0000000 00000000026 12576132612 0023040 0 ustar 00root root 0000000 0000000 module HomeHelper
end
devise-two-factor-2.0.0/demo/app/mailers/ 0000775 0000000 0000000 00000000000 12576132612 0020220 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/mailers/.keep 0000664 0000000 0000000 00000000000 12576132612 0021133 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/models/ 0000775 0000000 0000000 00000000000 12576132612 0020047 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/models/.keep 0000664 0000000 0000000 00000000000 12576132612 0020762 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/models/concerns/ 0000775 0000000 0000000 00000000000 12576132612 0021661 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/models/concerns/.keep 0000664 0000000 0000000 00000000000 12576132612 0022574 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/models/user.rb 0000664 0000000 0000000 00000001133 12576132612 0021350 0 ustar 00root root 0000000 0000000 class User < ActiveRecord::Base
devise :two_factor_authenticatable,
:otp_secret_encryption_key => ENV['ENCRYPTION_KEY'] # Set a unique encryption key for your app.
# Store your key as an ENV variable and
# remember to add it to .gitignore
# if you plan to share your code publicly.
devise :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
devise-two-factor-2.0.0/demo/app/views/ 0000775 0000000 0000000 00000000000 12576132612 0017721 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/ 0000775 0000000 0000000 00000000000 12576132612 0021200 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/confirmations/ 0000775 0000000 0000000 00000000000 12576132612 0024053 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/confirmations/new.html.erb 0000664 0000000 0000000 00000000610 12576132612 0026276 0 ustar 00root root 0000000 0000000
Resend confirmation instructions
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
<%= f.submit "Resend confirmation instructions" %>
<% end %>
<%= render "devise/shared/links" %>
devise-two-factor-2.0.0/demo/app/views/devise/mailer/ 0000775 0000000 0000000 00000000000 12576132612 0022451 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/mailer/confirmation_instructions.html.erb 0000664 0000000 0000000 00000000306 12576132612 0031421 0 ustar 00root root 0000000 0000000 Welcome <%= @email %>!
You can confirm your account email through the link below:
<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>
devise-two-factor-2.0.0/demo/app/views/devise/mailer/reset_password_instructions.html.erb 0000664 0000000 0000000 00000000611 12576132612 0031774 0 ustar 00root root 0000000 0000000 Hello <%= @resource.email %>!
Someone has requested a link to change your password. You can do this through the link below.
<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>
If you didn't request this, please ignore this email.
Your password won't change until you access the link above and create a new one.
devise-two-factor-2.0.0/demo/app/views/devise/mailer/unlock_instructions.html.erb 0000664 0000000 0000000 00000000424 12576132612 0030225 0 ustar 00root root 0000000 0000000 Hello <%= @resource.email %>!
Your account has been locked due to an excessive number of unsuccessful sign in attempts.
Click the link below to unlock your account:
<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>
devise-two-factor-2.0.0/demo/app/views/devise/passwords/ 0000775 0000000 0000000 00000000000 12576132612 0023225 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/passwords/edit.html.erb 0000664 0000000 0000000 00000001141 12576132612 0025604 0 ustar 00root root 0000000 0000000 Change your password
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<%= f.hidden_field :reset_password_token %>
<%= f.label :password, "New password" %>
<%= f.password_field :password, autofocus: true, autocomplete: "off" %>
<%= f.label :password_confirmation, "Confirm new password" %>
<%= f.password_field :password_confirmation, autocomplete: "off" %>
<%= f.submit "Change my password" %>
<% end %>
<%= render "devise/shared/links" %>
devise-two-factor-2.0.0/demo/app/views/devise/passwords/new.html.erb 0000664 0000000 0000000 00000000574 12576132612 0025461 0 ustar 00root root 0000000 0000000 Forgot your password?
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
<%= f.submit "Send me reset password instructions" %>
<% end %>
<%= render "devise/shared/links" %>
devise-two-factor-2.0.0/demo/app/views/devise/registrations/ 0000775 0000000 0000000 00000000000 12576132612 0024075 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/registrations/edit.html.erb 0000664 0000000 0000000 00000002230 12576132612 0026454 0 ustar 00root root 0000000 0000000 Edit <%= resource_name.to_s.humanize %>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= devise_error_messages! %>
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
Currently waiting confirmation for: <%= resource.unconfirmed_email %>
<% end %>
<%= f.label :password %> (leave blank if you don't want to change it)
<%= f.password_field :password, autocomplete: "off" %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off" %>
<%= f.label :current_password %> (we need your current password to confirm your changes)
<%= f.password_field :current_password, autocomplete: "off" %>
<%= f.submit "Update" %>
<% end %>
Cancel my account
Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
<%= link_to "Back", :back %>
devise-two-factor-2.0.0/demo/app/views/devise/registrations/new.html.erb 0000664 0000000 0000000 00000001047 12576132612 0026325 0 ustar 00root root 0000000 0000000 Sign up
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
<%= f.label :password %>
<%= f.password_field :password, autocomplete: "off" %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off" %>
<%= f.submit "Sign up" %>
<% end %>
<%= render "devise/shared/links" %>
devise-two-factor-2.0.0/demo/app/views/devise/sessions/ 0000775 0000000 0000000 00000000000 12576132612 0023046 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/sessions/new.html.erb 0000664 0000000 0000000 00000001127 12576132612 0025275 0 ustar 00root root 0000000 0000000 Sign in
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
<%= f.label :password %>
<%= f.password_field :password, autocomplete: "off" %>
<%= f.label :otp_attempt %>
<%= f.text_field :otp_attempt %>
<% if devise_mapping.rememberable? -%>
<%= f.check_box :remember_me %> <%= f.label :remember_me %>
<% end -%>
<%= f.submit "Sign in" %>
<% end %>
<%= render "devise/shared/links" %>
devise-two-factor-2.0.0/demo/app/views/devise/shared/ 0000775 0000000 0000000 00000000000 12576132612 0022446 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/shared/_links.erb 0000664 0000000 0000000 00000002162 12576132612 0024420 0 ustar 00root root 0000000 0000000 <%- if controller_name != 'sessions' %>
<%= link_to "Sign in", new_session_path(resource_name) %>
<% end -%>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to "Sign up", new_registration_path(resource_name) %>
<% end -%>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<%= link_to "Forgot your password?", new_password_path(resource_name) %>
<% end -%>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
<% end -%>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
<% end -%>
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %>
<% end -%>
<% end -%>
devise-two-factor-2.0.0/demo/app/views/devise/unlocks/ 0000775 0000000 0000000 00000000000 12576132612 0022656 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/devise/unlocks/new.html.erb 0000664 0000000 0000000 00000000566 12576132612 0025113 0 ustar 00root root 0000000 0000000 Resend unlock instructions
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<%= f.label :email %>
<%= f.email_field :email, autofocus: true %>
<%= f.submit "Resend unlock instructions" %>
<% end %>
<%= render "devise/shared/links" %>
devise-two-factor-2.0.0/demo/app/views/home/ 0000775 0000000 0000000 00000000000 12576132612 0020651 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/home/index.html.erb 0000664 0000000 0000000 00000001424 12576132612 0023416 0 ustar 00root root 0000000 0000000 <% if !current_user %>
<%= link_to "Sign up", new_user_registration_path %>
<%= link_to "Login", new_user_session_path %>
<% end %>
<% if current_user %>
<% if !current_user.otp_required_for_login %>
<%= button_to "Enable 2FA", users_enable_otp_path, :method => :post %>
<% end %>
<% if current_user.otp_required_for_login %>
<%= button_to "Disable 2FA", users_disable_otp_path, :method => :post %>
<%= raw RQRCode::render_qrcode(current_user.otp_provisioning_uri(current_user.email, issuer: "Devise-Two-Factor-Demo"),
:svg,
:level => :l,
:unit => 2) %>
<% end %>
<%= link_to "Log out", destroy_user_session_path, :method => :delete %>
<% end %>
devise-two-factor-2.0.0/demo/app/views/layouts/ 0000775 0000000 0000000 00000000000 12576132612 0021421 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/app/views/layouts/application.html.erb 0000664 0000000 0000000 00000000465 12576132612 0025366 0 ustar 00root root 0000000 0000000
DeviseTwoFactorDemo
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
<%= yield %>
devise-two-factor-2.0.0/demo/bin/ 0000775 0000000 0000000 00000000000 12576132612 0016554 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/bin/bundle 0000775 0000000 0000000 00000000201 12576132612 0017744 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
load Gem.bin_path('bundler', 'bundle')
devise-two-factor-2.0.0/demo/bin/rails 0000775 0000000 0000000 00000000222 12576132612 0017610 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
require 'rails/commands'
devise-two-factor-2.0.0/demo/bin/rake 0000775 0000000 0000000 00000000132 12576132612 0017420 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
require_relative '../config/boot'
require 'rake'
Rake.application.run
devise-two-factor-2.0.0/demo/config.ru 0000664 0000000 0000000 00000000232 12576132612 0017616 0 ustar 00root root 0000000 0000000 # This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run Rails.application
devise-two-factor-2.0.0/demo/config/ 0000775 0000000 0000000 00000000000 12576132612 0017251 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/config/application.rb 0000664 0000000 0000000 00000002227 12576132612 0022104 0 ustar 00root root 0000000 0000000 require File.expand_path('../boot', __FILE__)
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module DeviseTwoFactorDemo
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
env_file = File.join(Rails.root, 'config', 'local_env.yml')
YAML.load(File.open(env_file)).each do |key, value|
ENV[key.to_s] = value
end if File.exists?(env_file)
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
end
end
devise-two-factor-2.0.0/demo/config/boot.rb 0000664 0000000 0000000 00000000252 12576132612 0020540 0 ustar 00root root 0000000 0000000 # Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
devise-two-factor-2.0.0/demo/config/database.yml 0000664 0000000 0000000 00000005661 12576132612 0021550 0 ustar 00root root 0000000 0000000 # PostgreSQL. Versions 8.2 and up are supported.
#
# Install the pg driver:
# gem install pg
# On OS X with Homebrew:
# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On OS X with MacPorts:
# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem 'pg'
#
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: 5
development:
<<: *default
database: DeviseTwoFactorDemo_development
# The specified database role being used to connect to postgres.
# To create additional roles in postgres see `$ createuser --help`.
# When left blank, postgres will use the default role. This is
# the same name as the operating system user that initialized the database.
#username: DeviseTwoFactorDemo
# The password associated with the postgres role (username).
#password:
# Connect on a TCP socket. Omitted by default since the client uses a
# domain socket that doesn't need configuration. Windows does not have
# domain sockets, so uncomment these lines.
#host: localhost
# The TCP port the server listens on. Defaults to 5432.
# If your server runs on a different port number, change accordingly.
#port: 5432
# Schema search path. The server defaults to $user,public
#schema_search_path: myapp,sharedapp,public
# Minimum log levels, in increasing order:
# debug5, debug4, debug3, debug2, debug1,
# log, notice, warning, error, fatal, and panic
# Defaults to warning.
#min_messages: notice
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: DeviseTwoFactorDemo_test
# As with config/secrets.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%= ENV['DATABASE_URL'] %>
#
production:
<<: *default
database: DeviseTwoFactorDemo_production
username: DeviseTwoFactorDemo
password: <%= ENV['DEVISETWOFACTORDEMO_DATABASE_PASSWORD'] %>
devise-two-factor-2.0.0/demo/config/environment.rb 0000664 0000000 0000000 00000000226 12576132612 0022142 0 ustar 00root root 0000000 0000000 # Load the Rails application.
require File.expand_path('../application', __FILE__)
# Initialize the Rails application.
Rails.application.initialize!
devise-two-factor-2.0.0/demo/config/environments/ 0000775 0000000 0000000 00000000000 12576132612 0022000 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/config/environments/development.rb 0000664 0000000 0000000 00000002616 12576132612 0024654 0 ustar 00root root 0000000 0000000 Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
devise-two-factor-2.0.0/demo/config/environments/production.rb 0000664 0000000 0000000 00000006426 12576132612 0024523 0 ustar 00root root 0000000 0000000 Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid.
# config.action_dispatch.rack_cache = true
# Disable Rails's static asset server (Apache or nginx will already do this).
config.serve_static_assets = false
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Generate digests for assets URLs.
config.assets.digest = true
# Version of your assets, change this if you want to expire all your assets.
config.assets.version = '1.0'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Set to :debug to see everything in the log.
config.log_level = :info
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
# Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = "http://assets.example.com"
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# config.assets.precompile += %w( search.js )
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Disable automatic flushing of the log to improve performance.
# config.autoflush_log = false
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
end
devise-two-factor-2.0.0/demo/config/environments/test.rb 0000664 0000000 0000000 00000003175 12576132612 0023312 0 ustar 00root root 0000000 0000000 Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure static asset server for tests with Cache-Control for performance.
config.serve_static_assets = true
config.static_cache_control = 'public, max-age=3600'
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
devise-two-factor-2.0.0/demo/config/initializers/ 0000775 0000000 0000000 00000000000 12576132612 0021757 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/config/initializers/backtrace_silencers.rb 0000664 0000000 0000000 00000000624 12576132612 0026274 0 ustar 00root root 0000000 0000000 # Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
devise-two-factor-2.0.0/demo/config/initializers/cookies_serializer.rb 0000664 0000000 0000000 00000000200 12576132612 0026161 0 ustar 00root root 0000000 0000000 # Be sure to restart your server when you modify this file.
Rails.application.config.action_dispatch.cookies_serializer = :json devise-two-factor-2.0.0/demo/config/initializers/devise.rb 0000664 0000000 0000000 00000001116 12576132612 0023562 0 ustar 00root root 0000000 0000000 Devise.setup do |config|
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :two_factor_authenticatable
end
config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
require 'devise/orm/active_record'
config.case_insensitive_keys = [ :email ]
config.strip_whitespace_keys = [ :email ]
config.skip_session_storage = [:http_auth]
config.stretches = Rails.env.test? ? 1 : 10
config.reconfirmable = true
config.password_length = 8..128
config.reset_password_within = 6.hours
config.sign_out_via = :delete
end
devise-two-factor-2.0.0/demo/config/initializers/filter_parameter_logging.rb 0000664 0000000 0000000 00000000302 12576132612 0027332 0 ustar 00root root 0000000 0000000 # Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:password]
devise-two-factor-2.0.0/demo/config/initializers/inflections.rb 0000664 0000000 0000000 00000001207 12576132612 0024621 0 ustar 00root root 0000000 0000000 # Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym 'RESTful'
# end
devise-two-factor-2.0.0/demo/config/initializers/mime_types.rb 0000664 0000000 0000000 00000000234 12576132612 0024456 0 ustar 00root root 0000000 0000000 # Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
devise-two-factor-2.0.0/demo/config/initializers/session_store.rb 0000664 0000000 0000000 00000000227 12576132612 0025204 0 ustar 00root root 0000000 0000000 # Be sure to restart your server when you modify this file.
Rails.application.config.session_store :cookie_store, key: '_DeviseTwoFactorDemo_session'
devise-two-factor-2.0.0/demo/config/initializers/wrap_parameters.rb 0000664 0000000 0000000 00000001005 12576132612 0025474 0 ustar 00root root 0000000 0000000 # Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
# end
devise-two-factor-2.0.0/demo/config/locales/ 0000775 0000000 0000000 00000000000 12576132612 0020673 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/config/locales/devise.en.yml 0000664 0000000 0000000 00000007512 12576132612 0023303 0 ustar 00root root 0000000 0000000 # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
en:
devise:
confirmations:
confirmed: "Your account was successfully confirmed."
send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes."
send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes."
failure:
already_authenticated: "You are already signed in."
inactive: "Your account is not activated yet."
invalid: "Invalid email or password."
locked: "Your account is locked."
last_attempt: "You have one more attempt before your account will be locked."
not_found_in_database: "Invalid email or password."
timeout: "Your session expired. Please sign in again to continue."
unauthenticated: "You need to sign in or sign up before continuing."
unconfirmed: "You have to confirm your account before continuing."
mailer:
confirmation_instructions:
subject: "Confirmation instructions"
reset_password_instructions:
subject: "Reset password instructions"
unlock_instructions:
subject: "Unlock Instructions"
omniauth_callbacks:
failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
success: "Successfully authenticated from %{kind} account."
passwords:
no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
updated: "Your password was changed successfully. You are now signed in."
updated_not_active: "Your password was changed successfully."
registrations:
destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon."
signed_up: "Welcome! You have signed up successfully."
signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account."
update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address."
updated: "You updated your account successfully."
sessions:
signed_in: "Signed in successfully."
signed_out: "Signed out successfully."
unlocks:
send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes."
send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes."
unlocked: "Your account has been unlocked successfully. Please sign in to continue."
errors:
messages:
already_confirmed: "was already confirmed, please try signing in"
confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
expired: "has expired, please request a new one"
not_found: "not found"
not_locked: "was not locked"
not_saved:
one: "1 error prohibited this %{resource} from being saved:"
other: "%{count} errors prohibited this %{resource} from being saved:"
devise-two-factor-2.0.0/demo/config/locales/en.yml 0000664 0000000 0000000 00000001172 12576132612 0022021 0 ustar 00root root 0000000 0000000 # Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t 'hello'
#
# In views, this is aliased to just `t`:
#
# <%= t('hello') %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# To learn more, please read the Rails Internationalization guide
# available at http://guides.rubyonrails.org/i18n.html.
en:
hello: "Hello world"
devise-two-factor-2.0.0/demo/config/routes.rb 0000664 0000000 0000000 00000000257 12576132612 0021123 0 ustar 00root root 0000000 0000000 Rails.application.routes.draw do
get 'home/index'
post 'users/enable_otp'
post 'users/disable_otp'
devise_for :users
root to: "home#index", via: [:get, :post]
end
devise-two-factor-2.0.0/demo/config/secrets.yml 0000664 0000000 0000000 00000001704 12576132612 0021446 0 ustar 00root root 0000000 0000000 # Be sure to restart your server when you modify this file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.
# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.
development:
secret_key_base: c8c845b85a69d2b67ec99c1912ddcde63f0fcd05a74052f396daf68a2688d576c203bdc239c9423a0cf88218e201d30616959d5eeceea00eedf915677ecd373b
test:
secret_key_base: df468dd66c4b0f143354d216d96cdb8542ffe215afd78ebf977f7a8bfdb93010db134320cb738d27385bd7884cd73f3f22f90b147d4d176c3c8d0d63d5427fa9
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
devise-two-factor-2.0.0/demo/db/ 0000775 0000000 0000000 00000000000 12576132612 0016371 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/db/migrate/ 0000775 0000000 0000000 00000000000 12576132612 0020021 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/db/migrate/20140515190128_devise_create_users.rb 0000664 0000000 0000000 00000002500 12576132612 0026034 0 ustar 00root root 0000000 0000000 class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
devise-two-factor-2.0.0/demo/db/migrate/20140516191259_add_devise_two_factor_to_users.rb 0000664 0000000 0000000 00000000550 12576132612 0030264 0 ustar 00root root 0000000 0000000 class AddDeviseTwoFactorToUsers < ActiveRecord::Migration
def change
add_column :users, :encrypted_otp_secret, :string
add_column :users, :encrypted_otp_secret_iv, :string
add_column :users, :encrypted_otp_secret_salt, :string
add_column :users, :consumed_timestep, :integer
add_column :users, :otp_required_for_login, :boolean
end
end
devise-two-factor-2.0.0/demo/db/schema.rb 0000664 0000000 0000000 00000003536 12576132612 0020165 0 ustar 00root root 0000000 0000000 # encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20140516191259) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "encrypted_otp_secret"
t.string "encrypted_otp_secret_iv"
t.string "encrypted_otp_secret_salt"
t.integer "consumed_timestep"
t.boolean "otp_required_for_login"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
devise-two-factor-2.0.0/demo/db/seeds.rb 0000664 0000000 0000000 00000000527 12576132612 0020025 0 ustar 00root root 0000000 0000000 # This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
#
# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
# Mayor.create(name: 'Emanuel', city: cities.first)
devise-two-factor-2.0.0/demo/lib/ 0000775 0000000 0000000 00000000000 12576132612 0016552 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/lib/assets/ 0000775 0000000 0000000 00000000000 12576132612 0020054 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/lib/assets/.keep 0000664 0000000 0000000 00000000000 12576132612 0020767 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/lib/tasks/ 0000775 0000000 0000000 00000000000 12576132612 0017677 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/lib/tasks/.keep 0000664 0000000 0000000 00000000000 12576132612 0020612 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/log/ 0000775 0000000 0000000 00000000000 12576132612 0016565 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/log/.keep 0000664 0000000 0000000 00000000000 12576132612 0017500 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/public/ 0000775 0000000 0000000 00000000000 12576132612 0017262 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/public/404.html 0000664 0000000 0000000 00000003034 12576132612 0020457 0 ustar 00root root 0000000 0000000
The page you were looking for doesn't exist (404)
The page you were looking for doesn't exist.
You may have mistyped the address or the page may have moved.
If you are the application owner check the logs for more information.
devise-two-factor-2.0.0/demo/public/422.html 0000664 0000000 0000000 00000003013 12576132612 0020454 0 ustar 00root root 0000000 0000000
The change you wanted was rejected (422)
The change you wanted was rejected.
Maybe you tried to change something you didn't have access to.
If you are the application owner check the logs for more information.
devise-two-factor-2.0.0/demo/public/500.html 0000664 0000000 0000000 00000002705 12576132612 0020460 0 ustar 00root root 0000000 0000000
We're sorry, but something went wrong (500)
We're sorry, but something went wrong.
If you are the application owner check the logs for more information.
devise-two-factor-2.0.0/demo/public/favicon.ico 0000664 0000000 0000000 00000000000 12576132612 0021371 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/public/robots.txt 0000664 0000000 0000000 00000000312 12576132612 0021327 0 ustar 00root root 0000000 0000000 # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
#
# To ban all spiders from the entire site uncomment the next two lines:
# User-agent: *
# Disallow: /
devise-two-factor-2.0.0/demo/test/ 0000775 0000000 0000000 00000000000 12576132612 0016763 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/controllers/ 0000775 0000000 0000000 00000000000 12576132612 0021331 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/controllers/.keep 0000664 0000000 0000000 00000000000 12576132612 0022244 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/controllers/home_controller_test.rb 0000664 0000000 0000000 00000000241 12576132612 0026105 0 ustar 00root root 0000000 0000000 require 'test_helper'
class HomeControllerTest < ActionController::TestCase
test "should get index" do
get :index
assert_response :success
end
end
devise-two-factor-2.0.0/demo/test/fixtures/ 0000775 0000000 0000000 00000000000 12576132612 0020634 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/fixtures/.keep 0000664 0000000 0000000 00000000000 12576132612 0021547 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/fixtures/users.yml 0000664 0000000 0000000 00000000543 12576132612 0022522 0 ustar 00root root 0000000 0000000 # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
# This model initially had no columns defined. If you add columns to the
# model remove the '{}' from the fixture names and add the columns immediately
# below each fixture, per the syntax in the comments below
#
one: {}
# column: value
#
two: {}
# column: value
devise-two-factor-2.0.0/demo/test/helpers/ 0000775 0000000 0000000 00000000000 12576132612 0020425 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/helpers/.keep 0000664 0000000 0000000 00000000000 12576132612 0021340 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/helpers/home_helper_test.rb 0000664 0000000 0000000 00000000107 12576132612 0024276 0 ustar 00root root 0000000 0000000 require 'test_helper'
class HomeHelperTest < ActionView::TestCase
end
devise-two-factor-2.0.0/demo/test/integration/ 0000775 0000000 0000000 00000000000 12576132612 0021306 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/integration/.keep 0000664 0000000 0000000 00000000000 12576132612 0022221 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/mailers/ 0000775 0000000 0000000 00000000000 12576132612 0020417 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/mailers/.keep 0000664 0000000 0000000 00000000000 12576132612 0021332 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/models/ 0000775 0000000 0000000 00000000000 12576132612 0020246 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/models/.keep 0000664 0000000 0000000 00000000000 12576132612 0021161 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/test/models/user_test.rb 0000664 0000000 0000000 00000000166 12576132612 0022613 0 ustar 00root root 0000000 0000000 require 'test_helper'
class UserTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
devise-two-factor-2.0.0/demo/test/test_helper.rb 0000664 0000000 0000000 00000000702 12576132612 0021625 0 ustar 00root root 0000000 0000000 ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# Add more helper methods to be used by all tests here...
end
devise-two-factor-2.0.0/demo/vendor/ 0000775 0000000 0000000 00000000000 12576132612 0017301 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/vendor/assets/ 0000775 0000000 0000000 00000000000 12576132612 0020603 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/vendor/assets/javascripts/ 0000775 0000000 0000000 00000000000 12576132612 0023134 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/vendor/assets/javascripts/.keep 0000664 0000000 0000000 00000000000 12576132612 0024047 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/vendor/assets/stylesheets/ 0000775 0000000 0000000 00000000000 12576132612 0023157 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/demo/vendor/assets/stylesheets/.keep 0000664 0000000 0000000 00000000000 12576132612 0024072 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/devise-two-factor.gemspec 0000664 0000000 0000000 00000002762 12576132612 0021776 0 ustar 00root root 0000000 0000000 $:.push File.expand_path('../lib', __FILE__)
require 'devise_two_factor/version'
Gem::Specification.new do |s|
s.name = 'devise-two-factor'
s.version = DeviseTwoFactor::VERSION.dup
s.platform = Gem::Platform::RUBY
s.licenses = ['MIT']
s.summary = 'Barebones two-factor authentication with Devise'
s.email = 'engineers@tinfoilsecurity.com'
s.homepage = 'https://github.com/tinfoil/devise-two-factor'
s.description = 'Barebones two-factor authentication with Devise'
s.authors = ['Shane Wilton']
s.cert_chain = [
'certs/tinfoil-cacert.pem',
'certs/tinfoilsecurity-gems-cert.pem'
]
s.signing_key = File.expand_path("~/.ssh/tinfoilsecurity-gems-key.pem") if $0 =~ /gem\z/
s.rubyforge_project = 'devise-two-factor'
s.files = `git ls-files`.split("\n").delete_if { |x| x.match('demo/*') }
s.test_files = `git ls-files -- spec/*`.split("\n")
s.require_paths = ['lib']
s.add_runtime_dependency 'railties'
s.add_runtime_dependency 'activesupport'
s.add_runtime_dependency 'attr_encrypted', '~> 1.3.2'
s.add_runtime_dependency 'devise', '~> 3.5.0'
s.add_runtime_dependency 'rotp', '~> 2'
s.add_development_dependency 'activemodel'
s.add_development_dependency 'bundler', '> 1.0'
s.add_development_dependency 'rspec', '> 3'
s.add_development_dependency 'simplecov'
s.add_development_dependency 'faker'
s.add_development_dependency 'timecop'
end
devise-two-factor-2.0.0/lib/ 0000775 0000000 0000000 00000000000 12576132612 0015626 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/lib/devise-two-factor.rb 0000664 0000000 0000000 00000002104 12576132612 0021512 0 ustar 00root root 0000000 0000000 require 'devise'
require 'devise_two_factor/models'
require 'devise_two_factor/strategies'
module Devise
# The length of generated OTP secrets
mattr_accessor :otp_secret_length
@@otp_secret_length = 128
# The number of seconds before and after the current
# time for which codes will be accepted
mattr_accessor :otp_allowed_drift
@@otp_allowed_drift = 30
# The key used to encrypt OTP secrets in the database
mattr_accessor :otp_secret_encryption_key
@@otp_secret_encryption_key = nil
# The length of all generated OTP backup codes
mattr_accessor :otp_backup_code_length
@@otp_backup_code_length = 16
# The number of backup codes generated by a call to
# generate_otp_backup_codes!
mattr_accessor :otp_number_of_backup_codes
@@otp_number_of_backup_codes = 5
end
Devise.add_module(:two_factor_authenticatable, :route => :session, :strategy => true,
:controller => :sessions, :model => true)
Devise.add_module(:two_factor_backupable, :route => :session, :strategy => true,
:controller => :sessions, :model => true)
devise-two-factor-2.0.0/lib/devise_two_factor/ 0000775 0000000 0000000 00000000000 12576132612 0021334 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/lib/devise_two_factor/models.rb 0000664 0000000 0000000 00000000167 12576132612 0023150 0 ustar 00root root 0000000 0000000 require 'devise_two_factor/models/two_factor_authenticatable'
require 'devise_two_factor/models/two_factor_backupable'
devise-two-factor-2.0.0/lib/devise_two_factor/models/ 0000775 0000000 0000000 00000000000 12576132612 0022617 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/lib/devise_two_factor/models/two_factor_authenticatable.rb 0000664 0000000 0000000 00000004472 12576132612 0030537 0 ustar 00root root 0000000 0000000 require 'attr_encrypted'
require 'rotp'
module Devise
module Models
module TwoFactorAuthenticatable
extend ActiveSupport::Concern
include Devise::Models::DatabaseAuthenticatable
included do
attr_encrypted :otp_secret, :key => self.otp_secret_encryption_key,
:mode => :per_attribute_iv_and_salt unless self.attr_encrypted?(:otp_secret)
attr_accessor :otp_attempt
end
def self.required_fields(klass)
[:encrypted_otp_secret, :encrypted_otp_secret_iv, :encrypted_otp_secret_salt, :consumed_timestep]
end
# This defaults to the model's otp_secret
# If this hasn't been generated yet, pass a secret as an option
def validate_and_consume_otp!(code, options = {})
otp_secret = options[:otp_secret] || self.otp_secret
return false unless otp_secret.present?
totp = self.otp(otp_secret)
return consume_otp! if totp.verify_with_drift(code, self.class.otp_allowed_drift)
false
end
def otp(otp_secret = self.otp_secret)
ROTP::TOTP.new(otp_secret)
end
def current_otp
otp.at(Time.now)
end
# ROTP's TOTP#timecode is private, so we duplicate it here
def current_otp_timestep
Time.now.utc.to_i / otp.interval
end
def otp_provisioning_uri(account, options = {})
otp_secret = options[:otp_secret] || self.otp_secret
ROTP::TOTP.new(otp_secret, options).provisioning_uri(account)
end
def clean_up_passwords
self.otp_attempt = nil
end
protected
# An OTP cannot be used more than once in a given timestep
# Storing timestep of last valid OTP is sufficient to satisfy this requirement
def consume_otp!
if self.consumed_timestep != current_otp_timestep
self.consumed_timestep = current_otp_timestep
return save(validate: false)
end
false
end
module ClassMethods
Devise::Models.config(self, :otp_secret_length,
:otp_allowed_drift,
:otp_secret_encryption_key)
def generate_otp_secret(otp_secret_length = self.otp_secret_length)
ROTP::Base32.random_base32(otp_secret_length)
end
end
end
end
end
devise-two-factor-2.0.0/lib/devise_two_factor/models/two_factor_backupable.rb 0000664 0000000 0000000 00000003333 12576132612 0027466 0 ustar 00root root 0000000 0000000 module Devise
module Models
# TwoFactorBackupable allows a user to generate backup codes which
# provide one-time access to their account in the event that they have
# lost access to their two-factor device
module TwoFactorBackupable
extend ActiveSupport::Concern
def self.required_fields(klass)
[:otp_backup_codes]
end
# 1) Invalidates all existing backup codes
# 2) Generates otp_number_of_backup_codes backup codes
# 3) Stores the hashed backup codes in the database
# 4) Returns a plaintext array of the generated backup codes
def generate_otp_backup_codes!
codes = []
number_of_codes = self.class.otp_number_of_backup_codes
code_length = self.class.otp_backup_code_length
number_of_codes.times do
codes << SecureRandom.hex(code_length / 2) # Hexstring has length 2*n
end
hashed_codes = codes.map { |code| Devise::Encryptor.digest(self.class, code) }
self.otp_backup_codes = hashed_codes
codes
end
# Returns true and invalidates the given code
# iff that code is a valid backup code.
def invalidate_otp_backup_code!(code)
codes = self.otp_backup_codes || []
codes.each do |backup_code|
next unless Devise::Encryptor.compare(self.class, backup_code, code)
codes.delete(backup_code)
self.otp_backup_codes = codes
return true
end
false
end
protected
module ClassMethods
Devise::Models.config(self, :otp_backup_code_length,
:otp_number_of_backup_codes,
:pepper)
end
end
end
end
devise-two-factor-2.0.0/lib/devise_two_factor/spec_helpers.rb 0000664 0000000 0000000 00000000243 12576132612 0024334 0 ustar 00root root 0000000 0000000 require 'devise_two_factor/spec_helpers/two_factor_authenticatable_shared_examples'
require 'devise_two_factor/spec_helpers/two_factor_backupable_shared_examples'
devise-two-factor-2.0.0/lib/devise_two_factor/spec_helpers/ 0000775 0000000 0000000 00000000000 12576132612 0024010 5 ustar 00root root 0000000 0000000 two_factor_authenticatable_shared_examples.rb 0000664 0000000 0000000 00000006612 12576132612 0035073 0 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/lib/devise_two_factor/spec_helpers shared_examples 'two_factor_authenticatable' do
before :each do
subject.otp_secret = subject.class.generate_otp_secret
end
describe 'required_fields' do
it 'should have the attr_encrypted fields for otp_secret' do
expect(Devise::Models::TwoFactorAuthenticatable.required_fields(subject.class)).to contain_exactly(:encrypted_otp_secret, :encrypted_otp_secret_iv, :encrypted_otp_secret_salt, :consumed_timestep)
end
end
describe '#otp_secret' do
it 'should be of the configured length' do
expect(subject.otp_secret.length).to eq(subject.class.otp_secret_length)
end
it 'stores the encrypted otp_secret' do
expect(subject.encrypted_otp_secret).to_not be_nil
end
it 'stores an iv for otp_secret' do
expect(subject.encrypted_otp_secret_iv).to_not be_nil
end
it 'stores a salt for otp_secret' do
expect(subject.encrypted_otp_secret_salt).to_not be_nil
end
end
describe '#validate_and_consume_otp!' do
let(:otp_secret) { '2z6hxkdwi3uvrnpn' }
before :each do
Timecop.freeze(Time.current)
subject.otp_secret = otp_secret
end
after :each do
Timecop.return
end
context 'with a stored consumed_timestep' do
context 'given a precisely correct OTP' do
let(:consumed_otp) { ROTP::TOTP.new(otp_secret).at(Time.now) }
before do
subject.validate_and_consume_otp!(consumed_otp)
end
it 'fails to validate' do
expect(subject.validate_and_consume_otp!(consumed_otp)).to be false
end
end
context 'given a previously valid OTP within the allowed drift' do
let(:consumed_otp) { ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift, true) }
before do
subject.validate_and_consume_otp!(consumed_otp)
end
it 'fails to validate' do
expect(subject.validate_and_consume_otp!(consumed_otp)).to be false
end
end
end
it 'validates a precisely correct OTP' do
otp = ROTP::TOTP.new(otp_secret).at(Time.now)
expect(subject.validate_and_consume_otp!(otp)).to be true
end
it 'validates an OTP within the allowed drift' do
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift, true)
expect(subject.validate_and_consume_otp!(otp)).to be true
end
it 'does not validate an OTP above the allowed drift' do
otp = ROTP::TOTP.new(otp_secret).at(Time.now + subject.class.otp_allowed_drift * 2, true)
expect(subject.validate_and_consume_otp!(otp)).to be false
end
it 'does not validate an OTP below the allowed drift' do
otp = ROTP::TOTP.new(otp_secret).at(Time.now - subject.class.otp_allowed_drift * 2, true)
expect(subject.validate_and_consume_otp!(otp)).to be false
end
end
describe '#otp_provisioning_uri' do
let(:otp_secret_length) { subject.class.otp_secret_length }
let(:account) { Faker::Internet.email }
let(:issuer) { "Tinfoil" }
it "should return uri with specified account" do
expect(subject.otp_provisioning_uri(account)).to match(%r{otpauth://totp/#{account}\?secret=\w{#{otp_secret_length}}})
end
it 'should return uri with issuer option' do
expect(subject.otp_provisioning_uri(account, issuer: issuer)).to match(%r{otpauth://totp/#{account}\?secret=\w{#{otp_secret_length}}&issuer=#{issuer}$})
end
end
end
devise-two-factor-2.0.0/lib/devise_two_factor/spec_helpers/two_factor_backupable_shared_examples.rb 0000664 0000000 0000000 00000005345 12576132612 0034110 0 ustar 00root root 0000000 0000000 shared_examples 'two_factor_backupable' do
describe 'required_fields' do
it 'has the attr_encrypted fields for otp_backup_codes' do
expect(Devise::Models::TwoFactorBackupable.required_fields(subject.class)).to contain_exactly(:otp_backup_codes)
end
end
describe '#generate_otp_backup_codes!' do
context 'with no existing recovery codes' do
before do
@plaintext_codes = subject.generate_otp_backup_codes!
end
it 'generates the correct number of new recovery codes' do
expect(subject.otp_backup_codes.length).to eq(subject.class.otp_number_of_backup_codes)
end
it 'generates recovery codes of the correct length' do
@plaintext_codes.each do |code|
expect(code.length).to eq(subject.class.otp_backup_code_length)
end
end
it 'generates distinct recovery codes' do
expect(@plaintext_codes.uniq).to contain_exactly(*@plaintext_codes)
end
it 'stores the codes as BCrypt hashes' do
subject.otp_backup_codes.each do |code|
# $algorithm$cost$(22 character salt + 31 character hash)
expect(code).to match(/\A\$[0-9a-z]{2}\$[0-9]{2}\$[A-Za-z0-9\.\/]{53}\z/)
end
end
end
context 'with existing recovery codes' do
let(:old_codes) { Faker::Lorem.words }
let(:old_codes_hashed) { old_codes.map { |x| Devise::Encryptor.digest(subject.class, x) } }
before do
subject.otp_backup_codes = old_codes_hashed
@plaintext_codes = subject.generate_otp_backup_codes!
end
it 'invalidates the existing recovery codes' do
expect((subject.otp_backup_codes & old_codes_hashed)).to match []
end
end
end
describe '#invalidate_otp_backup_code!' do
before do
@plaintext_codes = subject.generate_otp_backup_codes!
end
context 'given an invalid recovery code' do
it 'returns false' do
expect(subject.invalidate_otp_backup_code!('password')).to be false
end
end
context 'given a valid recovery code' do
it 'returns true' do
@plaintext_codes.each do |code|
expect(subject.invalidate_otp_backup_code!(code)).to be true
end
end
it 'invalidates that recovery code' do
code = @plaintext_codes.sample
subject.invalidate_otp_backup_code!(code)
expect(subject.invalidate_otp_backup_code!(code)).to be false
end
it 'does not invalidate the other recovery codes' do
code = @plaintext_codes.sample
subject.invalidate_otp_backup_code!(code)
@plaintext_codes.delete(code)
@plaintext_codes.each do |code|
expect(subject.invalidate_otp_backup_code!(code)).to be true
end
end
end
end
end
devise-two-factor-2.0.0/lib/devise_two_factor/strategies.rb 0000664 0000000 0000000 00000000177 12576132612 0024040 0 ustar 00root root 0000000 0000000 require 'devise_two_factor/strategies/two_factor_authenticatable'
require 'devise_two_factor/strategies/two_factor_backupable'
devise-two-factor-2.0.0/lib/devise_two_factor/strategies/ 0000775 0000000 0000000 00000000000 12576132612 0023506 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/lib/devise_two_factor/strategies/two_factor_authenticatable.rb 0000664 0000000 0000000 00000002164 12576132612 0031422 0 ustar 00root root 0000000 0000000 module Devise
module Strategies
class TwoFactorAuthenticatable < Devise::Strategies::DatabaseAuthenticatable
def authenticate!
resource = mapping.to.find_for_database_authentication(authentication_hash)
# We authenticate in two cases:
# 1. The password and the OTP are correct
# 2. The password is correct, and OTP is not required for login
# We check the OTP, then defer to DatabaseAuthenticatable
if validate(resource) { validate_otp(resource) }
super
end
fail(:not_found_in_database) unless resource
# We want to cascade to the next strategy if this one fails,
# but database authenticatable automatically halts on a bad password
@halted = false if @result == :failure
end
def validate_otp(resource)
return true unless resource.otp_required_for_login
return if params[scope]['otp_attempt'].nil?
resource.validate_and_consume_otp!(params[scope]['otp_attempt'])
end
end
end
end
Warden::Strategies.add(:two_factor_authenticatable, Devise::Strategies::TwoFactorAuthenticatable)
devise-two-factor-2.0.0/lib/devise_two_factor/strategies/two_factor_backupable.rb 0000664 0000000 0000000 00000001577 12576132612 0030365 0 ustar 00root root 0000000 0000000 module Devise
module Strategies
class TwoFactorBackupable < Devise::Strategies::DatabaseAuthenticatable
def authenticate!
resource = mapping.to.find_for_database_authentication(authentication_hash)
if validate(resource) { resource.invalidate_otp_backup_code!(params[scope]['otp_attempt']) }
# Devise fails to authenticate invalidated resources, but if we've
# gotten here, the object changed (Since we deleted a recovery code)
resource.save!
super
end
fail(:not_found_in_database) unless resource
# We want to cascade to the next strategy if this one fails,
# but database authenticatable automatically halts on a bad password
@halted = false if @result == :failure
end
end
end
end
Warden::Strategies.add(:two_factor_backupable, Devise::Strategies::TwoFactorBackupable)
devise-two-factor-2.0.0/lib/devise_two_factor/version.rb 0000664 0000000 0000000 00000000067 12576132612 0023351 0 ustar 00root root 0000000 0000000 module DeviseTwoFactor
VERSION = '2.0.0'.freeze
end
devise-two-factor-2.0.0/lib/generators/ 0000775 0000000 0000000 00000000000 12576132612 0017777 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/lib/generators/devise_two_factor/ 0000775 0000000 0000000 00000000000 12576132612 0023505 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/lib/generators/devise_two_factor/devise_two_factor_generator.rb 0000664 0000000 0000000 00000005340 12576132612 0031610 0 ustar 00root root 0000000 0000000 require 'rails/generators'
module DeviseTwoFactor
module Generators
class DeviseTwoFactorGenerator < Rails::Generators::NamedBase
argument :encryption_key_env, :type => :string, :required => true
desc 'Creates a migration to add the required attributes to NAME, and ' \
'adds the necessary Devise directives to the model'
def install_devise_two_factor
create_devise_two_factor_migration
inject_strategies_into_warden_config
inject_devise_directives_into_model
end
private
def create_devise_two_factor_migration
migration_arguments = [
"add_devise_two_factor_to_#{plural_name}",
"encrypted_otp_secret:string",
"encrypted_otp_secret_iv:string",
"encrypted_otp_secret_salt:string",
"consumed_timestep:integer",
"otp_required_for_login:boolean"
]
Rails::Generators.invoke('active_record:migration', migration_arguments)
end
def inject_strategies_into_warden_config
config_path = File.join('config', 'initializers', 'devise.rb')
content = " config.warden do |manager|\n" \
" manager.default_strategies(:scope => :#{singular_table_name}).unshift :two_factor_authenticatable\n" \
" end\n\n"
inject_into_file(config_path, content, after: "Devise.setup do |config|\n")
end
def inject_devise_directives_into_model
model_path = File.join('app', 'models', "#{file_path}.rb")
class_path = if namespaced?
class_name.to_s.split("::")
else
[class_name]
end
indent_depth = class_path.size
content = [
"devise :two_factor_authenticatable,",
" :otp_secret_encryption_key => ENV['#{encryption_key_env}']\n"
]
content << "attr_accessible :otp_attempt\n" if needs_attr_accessible?
content = content.map { |line| " " * indent_depth + line }.join("\n") << "\n"
inject_into_class(model_path, class_path.last, content)
# Remove :database_authenticatable from the list of loaded models
gsub_file(model_path, /(devise.*):(, )?database_authenticatable(, )?/, '\1\2')
end
def needs_attr_accessible?
!strong_parameters_enabled? && mass_assignment_security_enabled?
end
def strong_parameters_enabled?
defined?(ActionController::StrongParameters)
end
def mass_assignment_security_enabled?
defined?(ActiveModel::MassAssignmentSecurity)
end
end
end
end
devise-two-factor-2.0.0/spec/ 0000775 0000000 0000000 00000000000 12576132612 0016012 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/spec/devise/ 0000775 0000000 0000000 00000000000 12576132612 0017271 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/spec/devise/models/ 0000775 0000000 0000000 00000000000 12576132612 0020554 5 ustar 00root root 0000000 0000000 devise-two-factor-2.0.0/spec/devise/models/two_factor_authenticatable_spec.rb 0000664 0000000 0000000 00000001041 12576132612 0027473 0 ustar 00root root 0000000 0000000 require 'spec_helper'
require 'active_model'
class TwoFactorAuthenticatableDouble
include ::ActiveModel::Validations::Callbacks
extend ::Devise::Models
devise :two_factor_authenticatable, :otp_secret_encryption_key => 'test-key'
attr_accessor :consumed_timestep
def save(validate)
# noop for testing
true
end
end
describe ::Devise::Models::TwoFactorAuthenticatable do
context 'When included in a class' do
subject { TwoFactorAuthenticatableDouble.new }
it_behaves_like 'two_factor_authenticatable'
end
end
devise-two-factor-2.0.0/spec/devise/models/two_factor_backupable_spec.rb 0000664 0000000 0000000 00000000732 12576132612 0026435 0 ustar 00root root 0000000 0000000 require 'spec_helper'
class TwoFactorBackupableDouble
include ::ActiveModel::Validations::Callbacks
extend ::Devise::Models
devise :two_factor_authenticatable, :two_factor_backupable,
:otp_secret_encryption_key => 'test-key'
attr_accessor :otp_backup_codes
end
describe ::Devise::Models::TwoFactorBackupable do
context 'When included in a class' do
subject { TwoFactorBackupableDouble.new }
it_behaves_like 'two_factor_backupable'
end
end
devise-two-factor-2.0.0/spec/spec_helper.rb 0000664 0000000 0000000 00000001305 12576132612 0020627 0 ustar 00root root 0000000 0000000 require 'simplecov'
module SimpleCov::Configuration
def clean_filters
@filters = []
end
end
SimpleCov.configure do
clean_filters
load_profile 'test_frameworks'
end
ENV["COVERAGE"] && SimpleCov.start do
add_filter "/.rvm/"
end
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'rspec'
require 'faker'
require 'timecop'
require 'devise-two-factor'
require 'devise_two_factor/spec_helpers'
# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
RSpec.configure do |config|
config.order = 'random'
end