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,9 +0,0 @@
1
- class CreateUsers < ActiveRecord::Migration
2
- def change
3
- create_table :users do |t|
4
- t.string :name
5
-
6
- t.timestamps
7
- end
8
- end
9
- end
@@ -1,52 +0,0 @@
1
- class AddDeviseToUsers < ActiveRecord::Migration
2
- def self.up
3
- change_table(:users) do |t|
4
- ## Database authenticatable
5
- t.string :email, null: false, default: ''
6
- t.string :encrypted_password, null: false, default: ''
7
-
8
- ## Recoverable
9
- t.string :reset_password_token
10
- t.datetime :reset_password_sent_at
11
-
12
- ## Rememberable
13
- t.datetime :remember_created_at
14
-
15
- ## Trackable
16
- t.integer :sign_in_count, default: 0
17
- t.datetime :current_sign_in_at
18
- t.datetime :last_sign_in_at
19
- t.string :current_sign_in_ip
20
- t.string :last_sign_in_ip
21
-
22
- ## Confirmable
23
- # t.string :confirmation_token
24
- # t.datetime :confirmed_at
25
- # t.datetime :confirmation_sent_at
26
- # t.string :unconfirmed_email # Only if using reconfirmable
27
-
28
- ## Lockable
29
- t.integer :failed_attempts, default: 0 # Only if lock strategy is :failed_attempts
30
- t.string :unlock_token # Only if unlock strategy is :email or :both
31
- t.datetime :locked_at
32
-
33
- ## Token authenticatable
34
- t.string :authentication_token
35
-
36
- # Uncomment below if timestamps were not included in your original model.
37
- # t.timestamps
38
- end
39
-
40
- add_index :users, :email, unique: true
41
- add_index :users, :reset_password_token, unique: true
42
- # add_index :users, :confirmation_token, :unique => true
43
- add_index :users, :unlock_token, unique: true
44
- add_index :users, :authentication_token, unique: true
45
- end
46
-
47
- def self.down
48
- # By default, we don't want to make any assumption about how to roll back a migration when your
49
- # model already existed. Please edit below which fields you would like to remove in this migration.
50
- raise ActiveRecord::IrreversibleMigration
51
- end
52
- end
@@ -1,10 +0,0 @@
1
- class CreatePosts < ActiveRecord::Migration
2
- def change
3
- create_table :posts do |t|
4
- t.string :title
5
- t.text :body
6
-
7
- t.timestamps
8
- end
9
- end
10
- end
@@ -1,26 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>The page you were looking for doesn't exist (404)</title>
5
- <style type="text/css">
6
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
- div.dialog {
8
- width: 25em;
9
- padding: 0 4em;
10
- margin: 4em auto 0 auto;
11
- border: 1px solid #ccc;
12
- border-right-color: #999;
13
- border-bottom-color: #999;
14
- }
15
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
- </style>
17
- </head>
18
-
19
- <body>
20
- <!-- This file lives in public/404.html -->
21
- <div class="dialog">
22
- <h1>The page you were looking for doesn't exist.</h1>
23
- <p>You may have mistyped the address or the page may have moved.</p>
24
- </div>
25
- </body>
26
- </html>
@@ -1,26 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>The change you wanted was rejected (422)</title>
5
- <style type="text/css">
6
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
- div.dialog {
8
- width: 25em;
9
- padding: 0 4em;
10
- margin: 4em auto 0 auto;
11
- border: 1px solid #ccc;
12
- border-right-color: #999;
13
- border-bottom-color: #999;
14
- }
15
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
- </style>
17
- </head>
18
-
19
- <body>
20
- <!-- This file lives in public/422.html -->
21
- <div class="dialog">
22
- <h1>The change you wanted was rejected.</h1>
23
- <p>Maybe you tried to change something you didn't have access to.</p>
24
- </div>
25
- </body>
26
- </html>
@@ -1,25 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>We're sorry, but something went wrong (500)</title>
5
- <style type="text/css">
6
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
- div.dialog {
8
- width: 25em;
9
- padding: 0 4em;
10
- margin: 4em auto 0 auto;
11
- border: 1px solid #ccc;
12
- border-right-color: #999;
13
- border-bottom-color: #999;
14
- }
15
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
- </style>
17
- </head>
18
-
19
- <body>
20
- <!-- This file lives in public/500.html -->
21
- <div class="dialog">
22
- <h1>We're sorry, but something went wrong.</h1>
23
- </div>
24
- </body>
25
- </html>
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
-
4
- APP_PATH = File.expand_path('../../config/application', __FILE__)
5
- require File.expand_path('../../config/boot', __FILE__)
6
- require 'rails/commands'
@@ -1,63 +0,0 @@
1
- require 'test_helper'
2
- require 'integration_tests_helper'
3
-
4
- class PersistenceTest < ActionDispatch::IntegrationTest
5
- def setup
6
- @old_persistence = User.otp_trust_persistence
7
- User.otp_trust_persistence = 3.seconds
8
- end
9
-
10
- def teardown
11
- User.otp_trust_persistence = @old_persistence
12
- Capybara.reset_sessions!
13
- end
14
-
15
- test 'a user should be requested the otp challenge every log in' do
16
- # log in 1fa
17
- user = enable_otp_and_sign_in
18
- otp_challenge_for user
19
-
20
- visit user_token_path
21
- assert_equal user_token_path, current_path
22
-
23
- sign_out
24
- sign_user_in
25
-
26
- assert_equal user_credential_path, current_path
27
- end
28
-
29
- test 'a user should be able to set their browser as trusted' do
30
- # log in 1fa
31
- user = enable_otp_and_sign_in
32
- otp_challenge_for user
33
-
34
- visit user_token_path
35
- assert_equal user_token_path, current_path
36
-
37
- click_link('Trust this browser')
38
- assert_text 'Your browser is trusted.'
39
- sign_out
40
-
41
- sign_user_in
42
-
43
- assert_equal root_path, current_path
44
- end
45
-
46
- test 'trusted status should expire' do
47
- # log in 1fa
48
- user = enable_otp_and_sign_in
49
- otp_challenge_for user
50
-
51
- visit user_token_path
52
- assert_equal user_token_path, current_path
53
-
54
- click_link('Trust this browser')
55
- assert_text 'Your browser is trusted.'
56
- sign_out
57
-
58
- sleep User.otp_trust_persistence.to_i + 1
59
- sign_user_in
60
-
61
- assert_equal user_credential_path, current_path
62
- end
63
- end
@@ -1,103 +0,0 @@
1
- require 'test_helper'
2
- require 'integration_tests_helper'
3
-
4
- class RefreshTest < ActionDispatch::IntegrationTest
5
- def setup
6
- @old_refresh = User.otp_credentials_refresh
7
- User.otp_credentials_refresh = 1.second
8
- end
9
-
10
- def teardown
11
- User.otp_credentials_refresh = @old_refresh
12
- Capybara.reset_sessions!
13
- end
14
-
15
- test 'a user that just signed in should be able to access their OTP settings without refreshing' do
16
- sign_user_in
17
-
18
- visit user_token_path
19
- assert_equal user_token_path, current_path
20
- end
21
-
22
- test 'a user should be prompted for credentials when the credentials_refresh time is expired' do
23
- sign_user_in
24
- visit user_token_path
25
- assert_equal user_token_path, current_path
26
-
27
- sleep(2)
28
-
29
- visit user_token_path
30
- assert_equal refresh_user_credential_path, current_path
31
- end
32
-
33
- test 'a user should be able to access their OTP settings after refreshing' do
34
- sign_user_in
35
- visit user_token_path
36
- assert_equal user_token_path, current_path
37
-
38
- sleep(2)
39
-
40
- visit user_token_path
41
- assert_equal refresh_user_credential_path, current_path
42
-
43
- fill_in 'user_refresh_password', with: '12345678'
44
- click_button 'Continue...'
45
- assert_equal user_token_path, current_path
46
- end
47
-
48
- test 'a user should NOT be able to access their OTP settings unless refreshing' do
49
- sign_user_in
50
- visit user_token_path
51
- assert_equal user_token_path, current_path
52
-
53
- sleep(2)
54
-
55
- visit user_token_path
56
- assert_equal refresh_user_credential_path, current_path
57
-
58
- fill_in 'user_refresh_password', with: '12345670'
59
- click_button 'Continue...'
60
- assert_equal refresh_user_credential_path, current_path
61
- end
62
-
63
- test 'user should be asked their OTP challenge in order to refresh, if they have OTP' do
64
- enable_otp_and_sign_in_with_otp
65
-
66
- sleep(2)
67
- visit user_token_path
68
- assert_equal refresh_user_credential_path, current_path
69
-
70
- fill_in 'user_refresh_password', with: '12345678'
71
- click_button 'Continue...'
72
-
73
- assert_equal refresh_user_credential_path, current_path
74
- end
75
-
76
- test 'user should be finally be able to access their settings, if they provide both a password and a valid OTP token' do
77
- user = enable_otp_and_sign_in_with_otp
78
-
79
- sleep(2)
80
- visit user_token_path
81
- assert_equal refresh_user_credential_path, current_path
82
-
83
- fill_in 'user_refresh_password', with: '12345678'
84
- fill_in 'user_token', with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
85
- click_button 'Continue...'
86
-
87
- assert_equal user_token_path, current_path
88
- end
89
-
90
- test 'and rejected when the token is blank or null' do
91
- user = enable_otp_and_sign_in_with_otp
92
-
93
- sleep(2)
94
- visit user_token_path
95
- assert_equal refresh_user_credential_path, current_path
96
-
97
- fill_in 'user_refresh_password', with: '12345678'
98
- fill_in 'user_token', with: ''
99
- click_button 'Continue...'
100
-
101
- assert_equal refresh_user_credential_path, current_path
102
- end
103
- end
@@ -1,85 +0,0 @@
1
- require 'test_helper'
2
- require 'integration_tests_helper'
3
-
4
- class SignInTest < ActionDispatch::IntegrationTest
5
- def teardown
6
- Capybara.reset_sessions!
7
- end
8
-
9
- test 'a new user should be able to sign in without using their token' do
10
- create_full_user
11
-
12
- visit new_user_session_path
13
- fill_in 'user_email', with: 'user@email.invalid'
14
- fill_in 'user_password', with: '12345678'
15
- page.has_content?('Log in') ? click_button('Log in') : click_button('Sign in')
16
-
17
- assert_equal root_path, current_path
18
- end
19
-
20
- test 'a new user, just signed in, should be able to sign in and enable their OTP authentication' do
21
- user = sign_user_in
22
-
23
- visit user_token_path
24
- assert !page.has_content?('Your token secret')
25
-
26
- check 'user_otp_enabled'
27
- click_button 'Continue...'
28
-
29
- assert_equal user_token_path, current_path
30
-
31
- assert page.has_content?('Your token secret')
32
- assert !user.otp_auth_secret.nil?
33
- assert !user.otp_persistence_seed.nil?
34
- end
35
-
36
- test 'a new user should be able to sign in enable OTP and be prompted for their token' do
37
- enable_otp_and_sign_in
38
-
39
- assert_equal user_credential_path, current_path
40
- end
41
-
42
- test 'fail token authentication' do
43
- enable_otp_and_sign_in
44
- assert_equal user_credential_path, current_path
45
-
46
- fill_in 'user_token', with: '123456'
47
- click_button 'Submit Token'
48
-
49
- assert_equal new_user_session_path, current_path
50
- end
51
-
52
- test 'fail blank token authentication' do
53
- enable_otp_and_sign_in
54
- assert_equal user_credential_path, current_path
55
-
56
- fill_in 'user_token', with: ''
57
- click_button 'Submit Token'
58
-
59
- assert_equal user_credential_path, current_path
60
- end
61
-
62
- test 'successful token authentication' do
63
- user = enable_otp_and_sign_in
64
-
65
- fill_in 'user_token', with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
66
- click_button 'Submit Token'
67
-
68
- assert_equal root_path, current_path
69
- end
70
-
71
- test 'should fail if the the challenge times out' do
72
- old_timeout = User.otp_authentication_timeout
73
- User.otp_authentication_timeout = 1.second
74
-
75
- user = enable_otp_and_sign_in
76
-
77
- sleep(2)
78
-
79
- fill_in 'user_token', with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
80
- click_button 'Submit Token'
81
-
82
- User.otp_authentication_timeout = old_timeout
83
- assert_equal new_user_session_path, current_path
84
- end
85
- end
@@ -1,30 +0,0 @@
1
- require 'test_helper'
2
- require 'integration_tests_helper'
3
-
4
- class TokenTest < ActionDispatch::IntegrationTest
5
- def teardown
6
- Capybara.reset_sessions!
7
- end
8
-
9
- test 'disabling OTP after successfully enabling' do
10
- # log in 1fa
11
- user = enable_otp_and_sign_in
12
- assert_equal user_credential_path, current_path
13
-
14
- # otp two_factor
15
- fill_in 'user_token', with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
16
- click_button 'Submit Token'
17
- assert_equal root_path, current_path
18
-
19
- # disable OTP
20
- disable_otp
21
-
22
- # logout
23
- sign_out
24
-
25
- # log back in 1fa
26
- sign_user_in(user)
27
-
28
- assert_equal root_path, current_path
29
- end
30
- end