devise-2fa 0.1.1 → 0.2.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 (115) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +46 -0
  3. data/.gitignore +8 -0
  4. data/Gemfile +3 -22
  5. data/README.md +13 -14
  6. data/Rakefile +6 -28
  7. data/bin/rspec +10 -0
  8. data/bin/setup +12 -0
  9. data/{devise-2fa.gemspec → devise_2fa.gemspec} +15 -8
  10. data/lib/devise-2fa/version.rb +1 -1
  11. data/lib/devise_two_factorable/models/two_factorable.rb +5 -1
  12. data/{test → spec}/dummy/Rakefile +2 -3
  13. data/{test/dummy/app/mailers/.gitkeep → spec/dummy/app/assets/images/.keep} +0 -0
  14. data/spec/dummy/app/assets/javascripts/application.js +3 -0
  15. data/{test/dummy/lib/assets/.gitkeep → spec/dummy/app/assets/javascripts/channels/.keep} +0 -0
  16. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  17. data/{test → spec}/dummy/app/controllers/application_controller.rb +4 -1
  18. data/{test/dummy/public/favicon.ico → spec/dummy/app/controllers/concerns/.keep} +0 -0
  19. data/{test → spec}/dummy/app/helpers/application_helper.rb +0 -0
  20. data/spec/dummy/app/models/application_record.rb +3 -0
  21. data/spec/dummy/app/models/concerns/.keep +0 -0
  22. data/spec/dummy/app/models/user.rb +6 -0
  23. data/spec/dummy/app/views/layouts/application.html.erb +19 -0
  24. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  25. data/spec/dummy/bin/bundle +3 -0
  26. data/spec/dummy/bin/rails +4 -0
  27. data/spec/dummy/bin/rake +4 -0
  28. data/spec/dummy/bin/setup +25 -0
  29. data/spec/dummy/bin/update +25 -0
  30. data/spec/dummy/bin/yarn +11 -0
  31. data/spec/dummy/config.ru +5 -0
  32. data/spec/dummy/config/application.rb +14 -0
  33. data/spec/dummy/config/boot.rb +5 -0
  34. data/{test → spec}/dummy/config/database.yml +10 -10
  35. data/spec/dummy/config/environment.rb +5 -0
  36. data/spec/dummy/config/environments/development.rb +61 -0
  37. data/{test → spec}/dummy/config/environments/test.rb +15 -5
  38. data/spec/dummy/config/initializers/assets.rb +4 -0
  39. data/{test → spec}/dummy/config/initializers/backtrace_silencers.rb +0 -0
  40. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  41. data/{test → spec}/dummy/config/initializers/devise.rb +134 -56
  42. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  43. data/{test → spec}/dummy/config/initializers/inflections.rb +6 -5
  44. data/{test → spec}/dummy/config/initializers/mime_types.rb +0 -1
  45. data/{test → spec}/dummy/config/initializers/wrap_parameters.rb +5 -5
  46. data/spec/dummy/config/locales/devise.en.yml +68 -0
  47. data/spec/dummy/config/locales/devise.two_factor.en.yml +57 -0
  48. data/spec/dummy/config/locales/en.yml +2 -0
  49. data/spec/dummy/config/puma.rb +9 -0
  50. data/spec/dummy/config/routes.rb +4 -0
  51. data/spec/dummy/config/spring.rb +6 -0
  52. data/spec/dummy/config/storage.yml +8 -0
  53. data/spec/dummy/db/migrate/20190311184605_devise_create_users.rb +44 -0
  54. data/{test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb → spec/dummy/db/migrate/20190312222952_devise_two_factor_add_to_users.rb} +4 -5
  55. data/spec/dummy/db/schema.rb +39 -0
  56. data/spec/dummy/lib/assets/.keep +0 -0
  57. data/spec/dummy/package.json +5 -0
  58. data/spec/dummy/public/404.html +1 -0
  59. data/spec/dummy/public/422.html +1 -0
  60. data/spec/dummy/public/500.html +19 -0
  61. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  62. data/spec/dummy/public/apple-touch-icon.png +0 -0
  63. data/spec/dummy/public/favicon.ico +0 -0
  64. data/spec/dummy/storage/.keep +0 -0
  65. data/spec/models/user_spec.rb +33 -0
  66. data/spec/spec_helper.rb +69 -0
  67. data/spec/system/persistence_spec.rb +59 -0
  68. data/spec/system/refresh_spec.rb +100 -0
  69. data/spec/system/token_spec.rb +41 -0
  70. data/spec/system/users_spec.rb +98 -0
  71. metadata +213 -123
  72. data/.travis.yml +0 -28
  73. data/lib/devise_two_factorable/two_factorable.rb +0 -131
  74. data/test/dummy/README.rdoc +0 -261
  75. data/test/dummy/app/assets/javascripts/application.js +0 -13
  76. data/test/dummy/app/assets/stylesheets/application.css +0 -13
  77. data/test/dummy/app/controllers/posts_controller.rb +0 -83
  78. data/test/dummy/app/helpers/posts_helper.rb +0 -2
  79. data/test/dummy/app/models/post.rb +0 -2
  80. data/test/dummy/app/models/user.rb +0 -20
  81. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  82. data/test/dummy/app/views/posts/_form.html.erb +0 -25
  83. data/test/dummy/app/views/posts/edit.html.erb +0 -6
  84. data/test/dummy/app/views/posts/index.html.erb +0 -25
  85. data/test/dummy/app/views/posts/new.html.erb +0 -5
  86. data/test/dummy/app/views/posts/show.html.erb +0 -15
  87. data/test/dummy/config.ru +0 -4
  88. data/test/dummy/config/application.rb +0 -67
  89. data/test/dummy/config/boot.rb +0 -10
  90. data/test/dummy/config/environment.rb +0 -5
  91. data/test/dummy/config/environments/development.rb +0 -37
  92. data/test/dummy/config/environments/production.rb +0 -73
  93. data/test/dummy/config/initializers/secret_token.rb +0 -8
  94. data/test/dummy/config/initializers/session_store.rb +0 -8
  95. data/test/dummy/config/locales/en.yml +0 -5
  96. data/test/dummy/config/routes.rb +0 -6
  97. data/test/dummy/db/migrate/20130125101430_create_users.rb +0 -9
  98. data/test/dummy/db/migrate/20130131092406_add_devise_to_users.rb +0 -52
  99. data/test/dummy/db/migrate/20130131142320_create_posts.rb +0 -10
  100. data/test/dummy/public/404.html +0 -26
  101. data/test/dummy/public/422.html +0 -26
  102. data/test/dummy/public/500.html +0 -25
  103. data/test/dummy/script/rails +0 -6
  104. data/test/integration/persistence_test.rb +0 -63
  105. data/test/integration/refresh_test.rb +0 -103
  106. data/test/integration/sign_in_test.rb +0 -85
  107. data/test/integration/token_test.rb +0 -30
  108. data/test/integration_tests_helper.rb +0 -64
  109. data/test/model_tests_helper.rb +0 -20
  110. data/test/models/two_factorable_test.rb +0 -120
  111. data/test/orm/active_record.rb +0 -4
  112. data/test/orm/mongoid.rb +0 -13
  113. data/test/support/mongoid.yml +0 -6
  114. data/test/support/symmetric_encryption.yml +0 -70
  115. data/test/test_helper.rb +0 -18
@@ -1,64 +0,0 @@
1
- class ActionDispatch::IntegrationTest
2
- include Warden::Test::Helpers
3
-
4
- def warden
5
- request.env['warden']
6
- end
7
-
8
- def create_full_user
9
- @user ||= begin
10
- user = User.create!(
11
- email: 'user@email.invalid',
12
- password: '12345678',
13
- password_confirmation: '12345678'
14
- )
15
- user
16
- end
17
- end
18
-
19
- def enable_otp_and_sign_in_with_otp
20
- enable_otp_and_sign_in.tap do |user|
21
- fill_in 'user_token', with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
22
- click_button 'Submit Token'
23
- end
24
- end
25
-
26
- def enable_otp_and_sign_in
27
- user = create_full_user
28
- sign_user_in(user)
29
- visit user_token_path
30
- check 'user_otp_enabled'
31
- click_button 'Continue...'
32
-
33
- Capybara.reset_sessions!
34
-
35
- sign_user_in(user)
36
- user
37
- end
38
-
39
- def otp_challenge_for(user)
40
- fill_in 'user_token', with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
41
- click_button 'Submit Token'
42
- end
43
-
44
- def disable_otp
45
- visit user_token_path
46
- uncheck 'user_otp_enabled'
47
- click_button 'Continue...'
48
- end
49
-
50
- def sign_out
51
- logout :user
52
- end
53
-
54
- def sign_user_in(user = nil)
55
- user ||= create_full_user
56
- resource_name = user.class.name.underscore
57
- visit send("new_#{resource_name}_session_path")
58
- fill_in "#{resource_name}_email", with: user.email
59
- fill_in "#{resource_name}_password", with: user.password
60
-
61
- page.has_content?('Log in') ? click_button('Log in') : click_button('Sign in')
62
- user
63
- end
64
- end
@@ -1,20 +0,0 @@
1
- class ActiveSupport::TestCase
2
- #
3
- # Helpers for creating new users
4
- #
5
- def unique_identity
6
- @@unique_identity_count ||= 0
7
- @@unique_identity_count += 1
8
- "user-#{@@unique_identity_count}@mail.invalid"
9
- end
10
-
11
- def valid_attributes(attributes = {})
12
- { email: unique_identity,
13
- password: '12345678',
14
- password_confirmation: '12345678' }.update(attributes)
15
- end
16
-
17
- def new_user(attributes = {})
18
- User.new(valid_attributes(attributes)).save
19
- end
20
- end
@@ -1,120 +0,0 @@
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
@@ -1,4 +0,0 @@
1
- ActiveRecord::Migration.verbose = false
2
- ActiveRecord::Base.logger = Logger.new(nil)
3
-
4
- ActiveRecord::Migrator.migrate(File.expand_path('../../dummy/db/migrate/', __FILE__))
@@ -1,13 +0,0 @@
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
@@ -1,6 +0,0 @@
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' %>
@@ -1,70 +0,0 @@
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
@@ -1,18 +0,0 @@
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