devise-2fa 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.hound.yml +2 -0
  4. data/.ruby-style.yml +1248 -0
  5. data/.travis.yml +28 -0
  6. data/Gemfile +25 -0
  7. data/LICENSE +21 -0
  8. data/README.md +130 -0
  9. data/Rakefile +41 -0
  10. data/app/controllers/devise/credentials_controller.rb +100 -0
  11. data/app/controllers/devise/tokens_controller.rb +99 -0
  12. data/app/views/devise/credentials/refresh.html.erb +20 -0
  13. data/app/views/devise/credentials/show.html.erb +23 -0
  14. data/app/views/devise/tokens/_token_secret.html.erb +19 -0
  15. data/app/views/devise/tokens/_trusted_devices.html.erb +10 -0
  16. data/app/views/devise/tokens/recovery.html.erb +21 -0
  17. data/app/views/devise/tokens/recovery_codes.text.erb +3 -0
  18. data/app/views/devise/tokens/show.html.erb +19 -0
  19. data/config/locales/en.yml +57 -0
  20. data/devise-2fa.gemspec +27 -0
  21. data/lib/devise-2fa.rb +74 -0
  22. data/lib/devise-2fa/version.rb +5 -0
  23. data/lib/devise_two_factorable/controllers/helpers.rb +136 -0
  24. data/lib/devise_two_factorable/controllers/url_helpers.rb +30 -0
  25. data/lib/devise_two_factorable/engine.rb +22 -0
  26. data/lib/devise_two_factorable/helpers.rb +136 -0
  27. data/lib/devise_two_factorable/hooks.rb +11 -0
  28. data/lib/devise_two_factorable/hooks/sessions.rb +49 -0
  29. data/lib/devise_two_factorable/mapping.rb +12 -0
  30. data/lib/devise_two_factorable/models/two_factorable.rb +131 -0
  31. data/lib/devise_two_factorable/routes.rb +26 -0
  32. data/lib/devise_two_factorable/two_factorable.rb +131 -0
  33. data/lib/generators/active_record/devise_two_factor_generator.rb +32 -0
  34. data/lib/generators/active_record/templates/migration.rb +27 -0
  35. data/lib/generators/devise_two_factor/devise_two_factor_generator.rb +16 -0
  36. data/lib/generators/devise_two_factor/install_generator.rb +52 -0
  37. data/lib/generators/devise_two_factor/views_generator.rb +19 -0
  38. data/lib/generators/mongoid/devise_two_factor_generator.rb +34 -0
  39. data/test/dummy/README.rdoc +261 -0
  40. data/test/dummy/Rakefile +7 -0
  41. data/test/dummy/app/assets/javascripts/application.js +13 -0
  42. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  43. data/test/dummy/app/controllers/application_controller.rb +4 -0
  44. data/test/dummy/app/controllers/posts_controller.rb +83 -0
  45. data/test/dummy/app/helpers/application_helper.rb +2 -0
  46. data/test/dummy/app/helpers/posts_helper.rb +2 -0
  47. data/test/dummy/app/mailers/.gitkeep +0 -0
  48. data/test/dummy/app/models/post.rb +2 -0
  49. data/test/dummy/app/models/user.rb +20 -0
  50. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  51. data/test/dummy/app/views/posts/_form.html.erb +25 -0
  52. data/test/dummy/app/views/posts/edit.html.erb +6 -0
  53. data/test/dummy/app/views/posts/index.html.erb +25 -0
  54. data/test/dummy/app/views/posts/new.html.erb +5 -0
  55. data/test/dummy/app/views/posts/show.html.erb +15 -0
  56. data/test/dummy/config.ru +4 -0
  57. data/test/dummy/config/application.rb +67 -0
  58. data/test/dummy/config/boot.rb +10 -0
  59. data/test/dummy/config/database.yml +25 -0
  60. data/test/dummy/config/environment.rb +5 -0
  61. data/test/dummy/config/environments/development.rb +37 -0
  62. data/test/dummy/config/environments/production.rb +73 -0
  63. data/test/dummy/config/environments/test.rb +36 -0
  64. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  65. data/test/dummy/config/initializers/devise.rb +251 -0
  66. data/test/dummy/config/initializers/inflections.rb +15 -0
  67. data/test/dummy/config/initializers/mime_types.rb +5 -0
  68. data/test/dummy/config/initializers/secret_token.rb +8 -0
  69. data/test/dummy/config/initializers/session_store.rb +8 -0
  70. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  71. data/test/dummy/config/locales/en.yml +5 -0
  72. data/test/dummy/config/routes.rb +6 -0
  73. data/test/dummy/db/migrate/20130125101430_create_users.rb +9 -0
  74. data/test/dummy/db/migrate/20130131092406_add_devise_to_users.rb +52 -0
  75. data/test/dummy/db/migrate/20130131142320_create_posts.rb +10 -0
  76. data/test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb +28 -0
  77. data/test/dummy/lib/assets/.gitkeep +0 -0
  78. data/test/dummy/public/404.html +26 -0
  79. data/test/dummy/public/422.html +26 -0
  80. data/test/dummy/public/500.html +25 -0
  81. data/test/dummy/public/favicon.ico +0 -0
  82. data/test/dummy/script/rails +6 -0
  83. data/test/integration/persistence_test.rb +63 -0
  84. data/test/integration/refresh_test.rb +103 -0
  85. data/test/integration/sign_in_test.rb +85 -0
  86. data/test/integration/token_test.rb +30 -0
  87. data/test/integration_tests_helper.rb +64 -0
  88. data/test/model_tests_helper.rb +20 -0
  89. data/test/models/two_factorable_test.rb +120 -0
  90. data/test/orm/active_record.rb +4 -0
  91. data/test/orm/mongoid.rb +13 -0
  92. data/test/support/mongoid.yml +6 -0
  93. data/test/support/symmetric_encryption.yml +70 -0
  94. data/test/test_helper.rb +18 -0
  95. metadata +269 -0
@@ -0,0 +1,120 @@
1
+ require 'test_helper'
2
+ require 'model_tests_helper'
3
+
4
+ class TwoFactorableTest < ActiveSupport::TestCase
5
+ def setup
6
+ new_user
7
+ end
8
+
9
+ test 'new users have a non-nil secret set' do
10
+ assert_not_nil User.first.otp_auth_secret
11
+ end
12
+
13
+ test 'new users have OTP disabled by default' do
14
+ assert !User.first.otp_enabled
15
+ end
16
+
17
+ test 'users should have an instance of TOTP/ROTP objects' do
18
+ u = User.first
19
+ assert u.time_based_otp.is_a? ROTP::TOTP
20
+ assert u.recovery_otp.is_a? ROTP::HOTP
21
+ end
22
+
23
+ test 'users should have their otp_auth_secret/persistence_seed set on creation' do
24
+ assert User.first.otp_auth_secret
25
+ assert User.first.otp_persistence_seed
26
+ end
27
+
28
+ test 'reset_otp_credentials should generate new secrets and disable OTP' do
29
+ u = User.first
30
+ u.update_attribute(:otp_enabled, true)
31
+ assert u.otp_enabled
32
+ otp_auth_secret = u.otp_auth_secret
33
+ otp_persistence_seed = u.otp_persistence_seed
34
+
35
+ u.reset_otp_credentials!
36
+ assert !(otp_auth_secret == u.otp_auth_secret)
37
+ assert !(otp_persistence_seed == u.otp_persistence_seed)
38
+ assert !u.otp_enabled
39
+ end
40
+
41
+ test 'reset_otp_persistence should generate new persistence_seed but NOT change the otp_auth_secret' do
42
+ u = User.first
43
+ u.update_attribute(:otp_enabled, true)
44
+ assert u.otp_enabled
45
+ otp_auth_secret = u.otp_auth_secret
46
+ otp_persistence_seed = u.otp_persistence_seed
47
+
48
+ u.reset_otp_persistence!
49
+ assert (otp_auth_secret == u.otp_auth_secret)
50
+ assert !(otp_persistence_seed == u.otp_persistence_seed)
51
+ assert u.otp_enabled
52
+ end
53
+
54
+ test 'generating a challenge, should retrieve the user later' do
55
+ u = User.first
56
+ u.update_attribute(:otp_enabled, true)
57
+ challenge = u.generate_otp_challenge!
58
+
59
+ w = User.find_valid_otp_challenge(challenge)
60
+ assert w.is_a? User
61
+ assert_equal w, u
62
+ end
63
+
64
+ test 'expiring the challenge, should retrieve nothing' do
65
+ u = User.first
66
+ u.update_attribute(:otp_enabled, true)
67
+ challenge = u.generate_otp_challenge!(1.second)
68
+ sleep(2)
69
+
70
+ w = User.find_valid_otp_challenge(challenge)
71
+ assert_nil w
72
+ end
73
+
74
+ test 'expired challenges should not be valid' do
75
+ u = User.first
76
+ u.update_attribute(:otp_enabled, true)
77
+ challenge = u.generate_otp_challenge!(1.second)
78
+ sleep(2)
79
+ assert_equal false, u.otp_challenge_valid?
80
+ end
81
+
82
+ test 'null otp challenge' do
83
+ u = User.first
84
+ u.update_attribute(:otp_enabled, true)
85
+ assert_equal false, u.validate_otp_token('')
86
+ assert_equal false, u.validate_otp_token(nil)
87
+ end
88
+
89
+ test 'generated otp token should be valid for the user' do
90
+ u = User.first
91
+ u.update_attribute(:otp_enabled, true)
92
+
93
+ secret = u.otp_auth_secret
94
+ token = ROTP::TOTP.new(secret).now
95
+
96
+ assert_equal true, u.validate_otp_token(token)
97
+ end
98
+
99
+ test 'generated otp token, out of drift window, should be NOT valid for the user' do
100
+ u = User.first
101
+ u.update_attribute(:otp_enabled, true)
102
+
103
+ secret = u.otp_auth_secret
104
+
105
+ [3.minutes.from_now, 3.minutes.ago].each do |time|
106
+ token = ROTP::TOTP.new(secret).at(time)
107
+ assert_equal false, u.valid_otp_token?(token)
108
+ end
109
+ end
110
+
111
+ test 'recovery secrets should be valid, and valid only once' do
112
+ u = User.first
113
+ u.update_attribute(:otp_enabled, true)
114
+ recovery = u.next_otp_recovery_tokens
115
+
116
+ assert u.valid_otp_recovery_token? recovery.fetch(0)
117
+ assert_equal false, u.valid_otp_recovery_token?(recovery.fetch(0))
118
+ assert u.valid_otp_recovery_token? recovery.fetch(2)
119
+ end
120
+ end
@@ -0,0 +1,4 @@
1
+ ActiveRecord::Migration.verbose = false
2
+ ActiveRecord::Base.logger = Logger.new(nil)
3
+
4
+ ActiveRecord::Migrator.migrate(File.expand_path('../../dummy/db/migrate/', __FILE__))
@@ -0,0 +1,13 @@
1
+ require 'mongoid/version'
2
+
3
+ Mongoid.configure do |config|
4
+ config.load!('test/support/mongoid.yml')
5
+ config.use_utc = true
6
+ config.include_root_in_json = true
7
+ end
8
+
9
+ class ActiveSupport::TestCase
10
+ setup do
11
+ Mongoid.purge!
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ test:
2
+ <%= Mongoid::VERSION.to_i > 4 ? 'clients' : 'sessions' %>:
3
+ default:
4
+ database: devise-2fa-test-suite
5
+ hosts:
6
+ - localhost:<%= ENV['MONGODB_PORT'] || '27017' %>
@@ -0,0 +1,70 @@
1
+ #
2
+ # Symmetric Encryption for Ruby
3
+ #
4
+ ---
5
+ # For the development and test environments the test symmetric encryption keys
6
+ # can be placed directly in the source code.
7
+ # And therefore no RSA private key is required
8
+ development: &development_defaults
9
+ key: 1234567890ABCDEF1234567890ABCDEF
10
+ iv: 1234567890ABCDEF
11
+ cipher_name: aes-128-cbc
12
+
13
+ test:
14
+ <<: *development_defaults
15
+
16
+ production:
17
+ # Since the key to encrypt and decrypt with must NOT be stored along with the
18
+ # source code, we only hold a RSA key that is used to unlock the file
19
+ # containing the actual symmetric encryption key
20
+ #
21
+ # Sample RSA Key, DO NOT use this RSA key, generate a new one using
22
+ # openssl genrsa 2048
23
+ private_rsa_key: |
24
+ -----BEGIN RSA PRIVATE KEY-----
25
+ MIIEpAIBAAKCAQEAxIL9H/jYUGpA38v6PowRSRJEo3aNVXULNM/QNRpx2DTf++KH
26
+ 6DcuFTFcNSSSxG9n4y7tKi755be8N0uwCCuOzvXqfWmXYjbLwK3Ib2vm0btpHyvA
27
+ qxgqeJOOCxKdW/cUFLWn0tACUcEjVCNfWEGaFyvkOUuR7Ub9KfhbW9cZO3BxZMUf
28
+ IPGlHl/gWyf484sXygd+S7cpDTRRzo9RjG74DwfE0MFGf9a1fTkxnSgeOJ6asTOy
29
+ fp9tEToUlbglKaYGpOGHYQ9TV5ZsyJ9jRUyb4SP5wK2eK6dHTxTcHvT03kD90Hv4
30
+ WeKIXv3WOjkwNEyMdpnJJfSDb5oquQvCNi7ZSQIDAQABAoIBAQCbzR7TUoBugU+e
31
+ ICLvpC2wOYOh9kRoFLwlyv3QnH7WZFWRZzFJszYeJ1xr5etXQtyjCnmOkGAg+WOI
32
+ k8GlOKOpAuA/PpB/leJFiYL4lBwU/PmDdTT0cdx6bMKZlNCeMW8CXGQKiFDOcMqJ
33
+ 0uGtH5YD+RChPIEeFsJxnC8SyZ9/t2ra7XnMGiCZvRXIUDSEIIsRx/mOymJ7bL+h
34
+ Lbp46IfXf6ZuIzwzoIk0JReV/r+wdmkAVDkrrMkCmVS4/X1wN/Tiik9/yvbsh/CL
35
+ ztC55eSIEjATkWxnXfPASZN6oUfQPEveGH3HzNjdncjH/Ho8FaNMIAfFpBhhLPi9
36
+ nG5sbH+BAoGBAOdoUyVoAA/QUa3/FkQaa7Ajjehe5MR5k6VtaGtcxrLiBjrNR7x+
37
+ nqlZlGvWDMiCz49dgj+G1Qk1bbYrZLRX/Hjeqy5dZOGLMfgf9eKUmS1rDwAzBMcj
38
+ M9jnnJEBx8HIlNzaR6wzp3GMd0rrccs660A8URvzkgo9qNbvMLq9vyUtAoGBANll
39
+ SY1Iv9uaIz8klTXU9YzYtsfUmgXzw7K8StPdbEbo8F1J3JPJB4D7QHF0ObIaSWuf
40
+ suZqLsvWlYGuJeyX2ntlBN82ORfvUdOrdrbDlmPyj4PfFVl0AK3U3Ai374DNrjKR
41
+ hF6YFm4TLDaJhUjeV5C43kbE1N2FAMS9LYtPJ44NAoGAFDGHZ/E+aCLerddfwwun
42
+ MBS6MnftcLPHTZ1RimTrNfsBXipBw1ItWEvn5s0kCm9X24PmdNK4TnhqHYaF4DL5
43
+ ZjbQK1idEA2Mi8GGPIKJJ2x7P6I0HYiV4qy7fe/w1ZlCXE90B7PuPbtrQY9wO7Ll
44
+ ipJ45X6I1PnyfOcckn8yafUCgYACtPAlgjJhWZn2v03cTbqA9nHQKyV/zXkyUIXd
45
+ /XPLrjrP7ouAi5A8WuSChR/yx8ECRgrEM65Be3qBEtoGCB4AS1G0NcigM6qhKBFi
46
+ VS0aMXr3+V8argcUIwJaWW/x+p2go48yXlJpLHPweeXe8mXEt4iM+QZte6p2yKQ4
47
+ h9PGQQKBgQCqSydmXBnXGIVTp2sH/2GnpxLYnDBpcJE0tM8bJ42HEQQgRThIChsn
48
+ PnGA91G9MVikYapgI0VYBHQOTsz8rTIUzsKwXG+TIaK+W84nxH5y6jUkjqwxZmAz
49
+ r1URaMAun2PfAB4g2N/kEZTExgeOGqXjFhvvjdzl97ux2cTyZhaTXg==
50
+ -----END RSA PRIVATE KEY-----
51
+
52
+ # List Symmetric Key files in the order of current / latest first
53
+ ciphers:
54
+ -
55
+ # Filename containing Symmetric Encryption Key encrypted using the
56
+ # RSA public key derived from the private key above
57
+ key_filename: /etc/rails/.rails.key
58
+ iv_filename: /etc/rails/.rails.iv
59
+
60
+ # Encryption cipher_name
61
+ # Recommended values:
62
+ # aes-256-cbc
63
+ # 256 AES CBC Algorithm. Very strong
64
+ # Ruby 1.8.7 MRI Approximately 100,000 encryptions or decryptions per second
65
+ # JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
66
+ # aes-128-cbc
67
+ # 128 AES CBC Algorithm. Less strong.
68
+ # Ruby 1.8.7 MRI Approximately 100,000 encryptions or decryptions per second
69
+ # JRuby 1.6.7 with Ruby 1.8.7 Approximately 22,000 encryptions or decryptions per second
70
+ cipher_name: aes-256-cbc
@@ -0,0 +1,18 @@
1
+ ENV['RAILS_ENV'] = 'test'
2
+ DEVISE_ORM = (ENV['DEVISE_ORM'] || :active_record).to_sym
3
+
4
+ $LOAD_PATH.unshift File.dirname(__FILE__)
5
+ puts "\n==> Devise.orm = #{DEVISE_ORM.inspect}"
6
+ require 'dummy/config/environment'
7
+ require "orm/#{DEVISE_ORM}"
8
+ require 'rails/test_help'
9
+ require 'capybara/rails'
10
+ require 'minitest/reporters'
11
+
12
+ I18n.load_path << File.expand_path("../support/locale/en.yml", __FILE__) if DEVISE_ORM == :mongoid
13
+
14
+ MiniTest::Reporters.use!
15
+
16
+ class ActionDispatch::IntegrationTest
17
+ include Capybara::DSL
18
+ end
metadata ADDED
@@ -0,0 +1,269 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise-2fa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - William A. Todd
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-04-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: devise
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.2.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.2.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: rotp
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rqrcode
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.10.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.10.1
61
+ - !ruby/object:Gem::Dependency
62
+ name: symmetric-encryption
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.8'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.8'
75
+ - !ruby/object:Gem::Dependency
76
+ name: sqlite3
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ description: Time Based OTP/rfc6238 authentication for Devise
90
+ email:
91
+ - info@investinwaffles.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files: []
95
+ files:
96
+ - ".gitignore"
97
+ - ".hound.yml"
98
+ - ".ruby-style.yml"
99
+ - ".travis.yml"
100
+ - Gemfile
101
+ - LICENSE
102
+ - README.md
103
+ - Rakefile
104
+ - app/controllers/devise/credentials_controller.rb
105
+ - app/controllers/devise/tokens_controller.rb
106
+ - app/views/devise/credentials/refresh.html.erb
107
+ - app/views/devise/credentials/show.html.erb
108
+ - app/views/devise/tokens/_token_secret.html.erb
109
+ - app/views/devise/tokens/_trusted_devices.html.erb
110
+ - app/views/devise/tokens/recovery.html.erb
111
+ - app/views/devise/tokens/recovery_codes.text.erb
112
+ - app/views/devise/tokens/show.html.erb
113
+ - config/locales/en.yml
114
+ - devise-2fa.gemspec
115
+ - lib/devise-2fa.rb
116
+ - lib/devise-2fa/version.rb
117
+ - lib/devise_two_factorable/controllers/helpers.rb
118
+ - lib/devise_two_factorable/controllers/url_helpers.rb
119
+ - lib/devise_two_factorable/engine.rb
120
+ - lib/devise_two_factorable/helpers.rb
121
+ - lib/devise_two_factorable/hooks.rb
122
+ - lib/devise_two_factorable/hooks/sessions.rb
123
+ - lib/devise_two_factorable/mapping.rb
124
+ - lib/devise_two_factorable/models/two_factorable.rb
125
+ - lib/devise_two_factorable/routes.rb
126
+ - lib/devise_two_factorable/two_factorable.rb
127
+ - lib/generators/active_record/devise_two_factor_generator.rb
128
+ - lib/generators/active_record/templates/migration.rb
129
+ - lib/generators/devise_two_factor/devise_two_factor_generator.rb
130
+ - lib/generators/devise_two_factor/install_generator.rb
131
+ - lib/generators/devise_two_factor/views_generator.rb
132
+ - lib/generators/mongoid/devise_two_factor_generator.rb
133
+ - test/dummy/README.rdoc
134
+ - test/dummy/Rakefile
135
+ - test/dummy/app/assets/javascripts/application.js
136
+ - test/dummy/app/assets/stylesheets/application.css
137
+ - test/dummy/app/controllers/application_controller.rb
138
+ - test/dummy/app/controllers/posts_controller.rb
139
+ - test/dummy/app/helpers/application_helper.rb
140
+ - test/dummy/app/helpers/posts_helper.rb
141
+ - test/dummy/app/mailers/.gitkeep
142
+ - test/dummy/app/models/post.rb
143
+ - test/dummy/app/models/user.rb
144
+ - test/dummy/app/views/layouts/application.html.erb
145
+ - test/dummy/app/views/posts/_form.html.erb
146
+ - test/dummy/app/views/posts/edit.html.erb
147
+ - test/dummy/app/views/posts/index.html.erb
148
+ - test/dummy/app/views/posts/new.html.erb
149
+ - test/dummy/app/views/posts/show.html.erb
150
+ - test/dummy/config.ru
151
+ - test/dummy/config/application.rb
152
+ - test/dummy/config/boot.rb
153
+ - test/dummy/config/database.yml
154
+ - test/dummy/config/environment.rb
155
+ - test/dummy/config/environments/development.rb
156
+ - test/dummy/config/environments/production.rb
157
+ - test/dummy/config/environments/test.rb
158
+ - test/dummy/config/initializers/backtrace_silencers.rb
159
+ - test/dummy/config/initializers/devise.rb
160
+ - test/dummy/config/initializers/inflections.rb
161
+ - test/dummy/config/initializers/mime_types.rb
162
+ - test/dummy/config/initializers/secret_token.rb
163
+ - test/dummy/config/initializers/session_store.rb
164
+ - test/dummy/config/initializers/wrap_parameters.rb
165
+ - test/dummy/config/locales/en.yml
166
+ - test/dummy/config/routes.rb
167
+ - test/dummy/db/migrate/20130125101430_create_users.rb
168
+ - test/dummy/db/migrate/20130131092406_add_devise_to_users.rb
169
+ - test/dummy/db/migrate/20130131142320_create_posts.rb
170
+ - test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb
171
+ - test/dummy/lib/assets/.gitkeep
172
+ - test/dummy/public/404.html
173
+ - test/dummy/public/422.html
174
+ - test/dummy/public/500.html
175
+ - test/dummy/public/favicon.ico
176
+ - test/dummy/script/rails
177
+ - test/integration/persistence_test.rb
178
+ - test/integration/refresh_test.rb
179
+ - test/integration/sign_in_test.rb
180
+ - test/integration/token_test.rb
181
+ - test/integration_tests_helper.rb
182
+ - test/model_tests_helper.rb
183
+ - test/models/two_factorable_test.rb
184
+ - test/orm/active_record.rb
185
+ - test/orm/mongoid.rb
186
+ - test/support/mongoid.yml
187
+ - test/support/symmetric_encryption.yml
188
+ - test/test_helper.rb
189
+ homepage: http://www.github.com/williamatodd/devise-2fa
190
+ licenses:
191
+ - MIT
192
+ metadata: {}
193
+ post_install_message:
194
+ rdoc_options: []
195
+ require_paths:
196
+ - lib
197
+ required_ruby_version: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ required_rubygems_version: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ requirements: []
208
+ rubyforge_project:
209
+ rubygems_version: 2.6.1
210
+ signing_key:
211
+ specification_version: 4
212
+ summary: Includes ActiveRecord and Mongoid ORM support
213
+ test_files:
214
+ - test/dummy/README.rdoc
215
+ - test/dummy/Rakefile
216
+ - test/dummy/app/assets/javascripts/application.js
217
+ - test/dummy/app/assets/stylesheets/application.css
218
+ - test/dummy/app/controllers/application_controller.rb
219
+ - test/dummy/app/controllers/posts_controller.rb
220
+ - test/dummy/app/helpers/application_helper.rb
221
+ - test/dummy/app/helpers/posts_helper.rb
222
+ - test/dummy/app/mailers/.gitkeep
223
+ - test/dummy/app/models/post.rb
224
+ - test/dummy/app/models/user.rb
225
+ - test/dummy/app/views/layouts/application.html.erb
226
+ - test/dummy/app/views/posts/_form.html.erb
227
+ - test/dummy/app/views/posts/edit.html.erb
228
+ - test/dummy/app/views/posts/index.html.erb
229
+ - test/dummy/app/views/posts/new.html.erb
230
+ - test/dummy/app/views/posts/show.html.erb
231
+ - test/dummy/config.ru
232
+ - test/dummy/config/application.rb
233
+ - test/dummy/config/boot.rb
234
+ - test/dummy/config/database.yml
235
+ - test/dummy/config/environment.rb
236
+ - test/dummy/config/environments/development.rb
237
+ - test/dummy/config/environments/production.rb
238
+ - test/dummy/config/environments/test.rb
239
+ - test/dummy/config/initializers/backtrace_silencers.rb
240
+ - test/dummy/config/initializers/devise.rb
241
+ - test/dummy/config/initializers/inflections.rb
242
+ - test/dummy/config/initializers/mime_types.rb
243
+ - test/dummy/config/initializers/secret_token.rb
244
+ - test/dummy/config/initializers/session_store.rb
245
+ - test/dummy/config/initializers/wrap_parameters.rb
246
+ - test/dummy/config/locales/en.yml
247
+ - test/dummy/config/routes.rb
248
+ - test/dummy/db/migrate/20130125101430_create_users.rb
249
+ - test/dummy/db/migrate/20130131092406_add_devise_to_users.rb
250
+ - test/dummy/db/migrate/20130131142320_create_posts.rb
251
+ - test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb
252
+ - test/dummy/lib/assets/.gitkeep
253
+ - test/dummy/public/404.html
254
+ - test/dummy/public/422.html
255
+ - test/dummy/public/500.html
256
+ - test/dummy/public/favicon.ico
257
+ - test/dummy/script/rails
258
+ - test/integration/persistence_test.rb
259
+ - test/integration/refresh_test.rb
260
+ - test/integration/sign_in_test.rb
261
+ - test/integration/token_test.rb
262
+ - test/integration_tests_helper.rb
263
+ - test/model_tests_helper.rb
264
+ - test/models/two_factorable_test.rb
265
+ - test/orm/active_record.rb
266
+ - test/orm/mongoid.rb
267
+ - test/support/mongoid.yml
268
+ - test/support/symmetric_encryption.yml
269
+ - test/test_helper.rb