devise-otp 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/Rakefile +17 -18
- data/app/controllers/devise_otp/devise/otp_credentials_controller.rb +15 -19
- data/app/controllers/devise_otp/devise/otp_tokens_controller.rb +7 -11
- data/app/views/devise/otp_credentials/show.html.erb +1 -1
- data/app/views/devise/otp_tokens/_token_secret.html.erb +4 -4
- data/app/views/devise/otp_tokens/recovery.html.erb +4 -4
- data/app/views/devise/otp_tokens/show.html.erb +5 -5
- data/config/locales/en.yml +4 -12
- data/devise-otp.gemspec +13 -13
- data/lib/devise-otp/version.rb +1 -1
- data/lib/devise-otp.rb +15 -29
- data/lib/devise_otp_authenticatable/controllers/helpers.rb +21 -23
- data/lib/devise_otp_authenticatable/controllers/url_helpers.rb +0 -2
- data/lib/devise_otp_authenticatable/engine.rb +6 -4
- data/lib/devise_otp_authenticatable/hooks/sessions.rb +4 -5
- data/lib/devise_otp_authenticatable/hooks.rb +1 -3
- data/lib/devise_otp_authenticatable/models/otp_authenticatable.rb +19 -25
- data/lib/devise_otp_authenticatable/routes.rb +11 -14
- data/lib/generators/active_record/devise_otp_generator.rb +1 -1
- data/lib/generators/devise_otp/devise_otp_generator.rb +12 -13
- data/lib/generators/devise_otp/install_generator.rb +3 -4
- data/lib/generators/devise_otp/views_generator.rb +5 -5
- data/test/dummy/Rakefile +1 -1
- data/test/dummy/app/controllers/posts_controller.rb +2 -2
- data/test/dummy/app/models/user.rb +8 -8
- data/test/dummy/config/application.rb +4 -4
- data/test/dummy/config/boot.rb +5 -5
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/development.rb +1 -1
- data/test/dummy/config/environments/production.rb +1 -1
- data/test/dummy/config/environments/test.rb +2 -2
- data/test/dummy/config/initializers/devise.rb +6 -8
- data/test/dummy/config/initializers/secret_token.rb +2 -2
- data/test/dummy/config/initializers/session_store.rb +1 -1
- data/test/dummy/config/initializers/wrap_parameters.rb +1 -1
- data/test/dummy/config/routes.rb +1 -1
- data/test/dummy/config.ru +1 -1
- data/test/dummy/db/migrate/20130131092406_add_devise_to_users.rb +12 -13
- data/test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb +13 -13
- data/test/dummy/script/rails +3 -3
- data/test/integration/persistence_test.rb +11 -12
- data/test/integration/refresh_test.rb +13 -14
- data/test/integration/sign_in_test.rb +24 -26
- data/test/integration/token_test.rb +5 -6
- data/test/integration_tests_helper.rb +16 -17
- data/test/model_tests_helper.rb +5 -7
- data/test/models/otp_authenticatable_test.rb +18 -19
- data/test/test_helper.rb +10 -10
- metadata +22 -62
@@ -1,8 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "test_helper"
|
2
|
+
require "integration_tests_helper"
|
3
3
|
|
4
4
|
class PersistenceTest < ActionDispatch::IntegrationTest
|
5
|
-
|
6
5
|
def setup
|
7
6
|
@old_persistence = User.otp_trust_persistence
|
8
7
|
User.otp_trust_persistence = 3.seconds
|
@@ -13,7 +12,7 @@ class PersistenceTest < ActionDispatch::IntegrationTest
|
|
13
12
|
Capybara.reset_sessions!
|
14
13
|
end
|
15
14
|
|
16
|
-
test
|
15
|
+
test "a user should be requested the otp challenge every log in" do
|
17
16
|
# log in 1fa
|
18
17
|
user = enable_otp_and_sign_in
|
19
18
|
otp_challenge_for user
|
@@ -27,7 +26,7 @@ class PersistenceTest < ActionDispatch::IntegrationTest
|
|
27
26
|
assert_equal user_otp_credential_path, current_path
|
28
27
|
end
|
29
28
|
|
30
|
-
test
|
29
|
+
test "a user should be able to set their browser as trusted" do
|
31
30
|
# log in 1fa
|
32
31
|
user = enable_otp_and_sign_in
|
33
32
|
otp_challenge_for user
|
@@ -35,8 +34,8 @@ class PersistenceTest < ActionDispatch::IntegrationTest
|
|
35
34
|
visit user_otp_token_path
|
36
35
|
assert_equal user_otp_token_path, current_path
|
37
36
|
|
38
|
-
click_link(
|
39
|
-
assert_text
|
37
|
+
click_link("Trust this browser")
|
38
|
+
assert_text "Your browser is trusted."
|
40
39
|
sign_out
|
41
40
|
|
42
41
|
sign_user_in
|
@@ -44,7 +43,7 @@ class PersistenceTest < ActionDispatch::IntegrationTest
|
|
44
43
|
assert_equal root_path, current_path
|
45
44
|
end
|
46
45
|
|
47
|
-
test
|
46
|
+
test "a user should be able to download its recovery codes" do
|
48
47
|
# log in 1fa
|
49
48
|
user = enable_otp_and_sign_in
|
50
49
|
otp_challenge_for user
|
@@ -55,13 +54,13 @@ class PersistenceTest < ActionDispatch::IntegrationTest
|
|
55
54
|
enable_chrome_headless_downloads(page, "/tmp/devise-otp")
|
56
55
|
|
57
56
|
DownloadHelper.wait_for_download(count: 1) do
|
58
|
-
click_link(
|
57
|
+
click_link("Download recovery codes")
|
59
58
|
end
|
60
59
|
|
61
60
|
assert_equal 1, DownloadHelper.downloads.size
|
62
61
|
end
|
63
62
|
|
64
|
-
test
|
63
|
+
test "trusted status should expire" do
|
65
64
|
# log in 1fa
|
66
65
|
user = enable_otp_and_sign_in
|
67
66
|
otp_challenge_for user
|
@@ -69,8 +68,8 @@ class PersistenceTest < ActionDispatch::IntegrationTest
|
|
69
68
|
visit user_otp_token_path
|
70
69
|
assert_equal user_otp_token_path, current_path
|
71
70
|
|
72
|
-
click_link(
|
73
|
-
assert_text
|
71
|
+
click_link("Trust this browser")
|
72
|
+
assert_text "Your browser is trusted."
|
74
73
|
sign_out
|
75
74
|
|
76
75
|
sleep User.otp_trust_persistence.to_i + 1
|
@@ -1,8 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "test_helper"
|
2
|
+
require "integration_tests_helper"
|
3
3
|
|
4
4
|
class RefreshTest < ActionDispatch::IntegrationTest
|
5
|
-
|
6
5
|
def setup
|
7
6
|
@old_refresh = User.otp_credentials_refresh
|
8
7
|
User.otp_credentials_refresh = 1.second
|
@@ -13,14 +12,14 @@ class RefreshTest < ActionDispatch::IntegrationTest
|
|
13
12
|
Capybara.reset_sessions!
|
14
13
|
end
|
15
14
|
|
16
|
-
test
|
15
|
+
test "a user that just signed in should be able to access their OTP settings without refreshing" do
|
17
16
|
sign_user_in
|
18
17
|
|
19
18
|
visit user_otp_token_path
|
20
19
|
assert_equal user_otp_token_path, current_path
|
21
20
|
end
|
22
21
|
|
23
|
-
test
|
22
|
+
test "a user should be prompted for credentials when the credentials_refresh time is expired" do
|
24
23
|
sign_user_in
|
25
24
|
visit user_otp_token_path
|
26
25
|
assert_equal user_otp_token_path, current_path
|
@@ -31,7 +30,7 @@ class RefreshTest < ActionDispatch::IntegrationTest
|
|
31
30
|
assert_equal refresh_user_otp_credential_path, current_path
|
32
31
|
end
|
33
32
|
|
34
|
-
test
|
33
|
+
test "a user should be able to access their OTP settings after refreshing" do
|
35
34
|
sign_user_in
|
36
35
|
visit user_otp_token_path
|
37
36
|
assert_equal user_otp_token_path, current_path
|
@@ -41,12 +40,12 @@ class RefreshTest < ActionDispatch::IntegrationTest
|
|
41
40
|
visit user_otp_token_path
|
42
41
|
assert_equal refresh_user_otp_credential_path, current_path
|
43
42
|
|
44
|
-
fill_in
|
45
|
-
click_button
|
43
|
+
fill_in "user_refresh_password", with: "12345678"
|
44
|
+
click_button "Continue..."
|
46
45
|
assert_equal user_otp_token_path, current_path
|
47
46
|
end
|
48
47
|
|
49
|
-
test
|
48
|
+
test "a user should NOT be able to access their OTP settings unless refreshing" do
|
50
49
|
sign_user_in
|
51
50
|
visit user_otp_token_path
|
52
51
|
assert_equal user_otp_token_path, current_path
|
@@ -56,20 +55,20 @@ class RefreshTest < ActionDispatch::IntegrationTest
|
|
56
55
|
visit user_otp_token_path
|
57
56
|
assert_equal refresh_user_otp_credential_path, current_path
|
58
57
|
|
59
|
-
fill_in
|
60
|
-
click_button
|
58
|
+
fill_in "user_refresh_password", with: "12345670"
|
59
|
+
click_button "Continue..."
|
61
60
|
assert_equal refresh_user_otp_credential_path, current_path
|
62
61
|
end
|
63
62
|
|
64
|
-
test
|
63
|
+
test "user should be finally be able to access their settings, and just password is enough" do
|
65
64
|
user = enable_otp_and_sign_in_with_otp
|
66
65
|
|
67
66
|
sleep(2)
|
68
67
|
visit user_otp_token_path
|
69
68
|
assert_equal refresh_user_otp_credential_path, current_path
|
70
69
|
|
71
|
-
fill_in
|
72
|
-
click_button
|
70
|
+
fill_in "user_refresh_password", with: "12345678"
|
71
|
+
click_button "Continue..."
|
73
72
|
|
74
73
|
assert_equal user_otp_token_path, current_path
|
75
74
|
end
|
@@ -1,76 +1,74 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "test_helper"
|
2
|
+
require "integration_tests_helper"
|
3
3
|
|
4
4
|
class SignInTest < ActionDispatch::IntegrationTest
|
5
|
-
|
6
5
|
def teardown
|
7
6
|
Capybara.reset_sessions!
|
8
7
|
end
|
9
8
|
|
10
|
-
test
|
9
|
+
test "a new user should be able to sign in without using their token" do
|
11
10
|
create_full_user
|
12
11
|
|
13
12
|
visit posts_path
|
14
|
-
fill_in
|
15
|
-
fill_in
|
16
|
-
page.has_content?(
|
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")
|
17
16
|
|
18
17
|
assert_equal posts_path, current_path
|
19
18
|
end
|
20
19
|
|
21
|
-
test
|
20
|
+
test "a new user, just signed in, should be able to sign in and enable their OTP authentication" do
|
22
21
|
user = sign_user_in
|
23
22
|
|
24
23
|
visit user_otp_token_path
|
25
|
-
assert !page.has_content?(
|
24
|
+
assert !page.has_content?("Your token secret")
|
26
25
|
|
27
|
-
check
|
28
|
-
click_button
|
26
|
+
check "user_otp_enabled"
|
27
|
+
click_button "Continue..."
|
29
28
|
|
30
29
|
assert_equal user_otp_token_path, current_path
|
31
30
|
|
32
|
-
assert page.has_content?(
|
31
|
+
assert page.has_content?("Your token secret")
|
33
32
|
assert !user.otp_auth_secret.nil?
|
34
33
|
assert !user.otp_persistence_seed.nil?
|
35
34
|
end
|
36
35
|
|
37
|
-
test
|
36
|
+
test "a new user should be able to sign in enable OTP and be prompted for their token" do
|
38
37
|
enable_otp_and_sign_in
|
39
38
|
|
40
39
|
assert_equal user_otp_credential_path, current_path
|
41
40
|
end
|
42
41
|
|
43
|
-
test
|
42
|
+
test "fail token authentication" do
|
44
43
|
enable_otp_and_sign_in
|
45
44
|
assert_equal user_otp_credential_path, current_path
|
46
45
|
|
47
|
-
fill_in
|
48
|
-
click_button
|
46
|
+
fill_in "user_token", with: "123456"
|
47
|
+
click_button "Submit Token"
|
49
48
|
|
50
49
|
assert_equal new_user_session_path, current_path
|
51
50
|
end
|
52
51
|
|
53
|
-
test
|
52
|
+
test "fail blank token authentication" do
|
54
53
|
enable_otp_and_sign_in
|
55
54
|
assert_equal user_otp_credential_path, current_path
|
56
55
|
|
57
|
-
fill_in
|
58
|
-
click_button
|
56
|
+
fill_in "user_token", with: ""
|
57
|
+
click_button "Submit Token"
|
59
58
|
|
60
59
|
assert_equal user_otp_credential_path, current_path
|
61
60
|
end
|
62
61
|
|
63
|
-
test
|
62
|
+
test "successful token authentication" do
|
64
63
|
user = enable_otp_and_sign_in
|
65
64
|
|
66
|
-
fill_in
|
67
|
-
click_button
|
65
|
+
fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
|
66
|
+
click_button "Submit Token"
|
68
67
|
|
69
68
|
assert_equal root_path, current_path
|
70
69
|
end
|
71
70
|
|
72
|
-
|
73
|
-
test 'should fail if the the challenge times out' do
|
71
|
+
test "should fail if the the challenge times out" do
|
74
72
|
old_timeout = User.otp_authentication_timeout
|
75
73
|
User.otp_authentication_timeout = 1.second
|
76
74
|
|
@@ -78,8 +76,8 @@ class SignInTest < ActionDispatch::IntegrationTest
|
|
78
76
|
|
79
77
|
sleep(2)
|
80
78
|
|
81
|
-
fill_in
|
82
|
-
click_button
|
79
|
+
fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
|
80
|
+
click_button "Submit Token"
|
83
81
|
|
84
82
|
User.otp_authentication_timeout = old_timeout
|
85
83
|
assert_equal new_user_session_path, current_path
|
@@ -1,20 +1,19 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "test_helper"
|
2
|
+
require "integration_tests_helper"
|
3
3
|
|
4
4
|
class TokenTest < ActionDispatch::IntegrationTest
|
5
|
-
|
6
5
|
def teardown
|
7
6
|
Capybara.reset_sessions!
|
8
7
|
end
|
9
8
|
|
10
|
-
test
|
9
|
+
test "disabling OTP after successfully enabling" do
|
11
10
|
# log in 1fa
|
12
11
|
user = enable_otp_and_sign_in
|
13
12
|
assert_equal user_otp_credential_path, current_path
|
14
13
|
|
15
14
|
# otp 2fa
|
16
|
-
fill_in
|
17
|
-
click_button
|
15
|
+
fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
|
16
|
+
click_button "Submit Token"
|
18
17
|
assert_equal root_path, current_path
|
19
18
|
|
20
19
|
# disable OTP
|
@@ -2,15 +2,15 @@ class ActionDispatch::IntegrationTest
|
|
2
2
|
include Warden::Test::Helpers
|
3
3
|
|
4
4
|
def warden
|
5
|
-
request.env[
|
5
|
+
request.env["warden"]
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def create_full_user
|
9
9
|
@user ||= begin
|
10
10
|
user = User.create!(
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
11
|
+
email: "user@email.invalid",
|
12
|
+
password: "12345678",
|
13
|
+
password_confirmation: "12345678"
|
14
14
|
)
|
15
15
|
user
|
16
16
|
end
|
@@ -18,8 +18,8 @@ class ActionDispatch::IntegrationTest
|
|
18
18
|
|
19
19
|
def enable_otp_and_sign_in_with_otp
|
20
20
|
enable_otp_and_sign_in.tap do |user|
|
21
|
-
fill_in
|
22
|
-
click_button
|
21
|
+
fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
|
22
|
+
click_button "Submit Token"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -27,8 +27,8 @@ class ActionDispatch::IntegrationTest
|
|
27
27
|
user = create_full_user
|
28
28
|
sign_user_in(user)
|
29
29
|
visit user_otp_token_path
|
30
|
-
check
|
31
|
-
click_button
|
30
|
+
check "user_otp_enabled"
|
31
|
+
click_button "Continue..."
|
32
32
|
|
33
33
|
Capybara.reset_sessions!
|
34
34
|
|
@@ -37,14 +37,14 @@ class ActionDispatch::IntegrationTest
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def otp_challenge_for(user)
|
40
|
-
fill_in
|
41
|
-
click_button
|
40
|
+
fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
|
41
|
+
click_button "Submit Token"
|
42
42
|
end
|
43
43
|
|
44
44
|
def disable_otp
|
45
45
|
visit user_otp_token_path
|
46
|
-
uncheck
|
47
|
-
click_button
|
46
|
+
uncheck "user_otp_enabled"
|
47
|
+
click_button "Continue..."
|
48
48
|
end
|
49
49
|
|
50
50
|
def sign_out
|
@@ -55,11 +55,10 @@ class ActionDispatch::IntegrationTest
|
|
55
55
|
user ||= create_full_user
|
56
56
|
resource_name = user.class.name.underscore
|
57
57
|
visit send("new_#{resource_name}_session_path")
|
58
|
-
fill_in "#{resource_name}_email", :
|
59
|
-
fill_in "#{resource_name}_password", :
|
58
|
+
fill_in "#{resource_name}_email", with: user.email
|
59
|
+
fill_in "#{resource_name}_password", with: user.password
|
60
60
|
|
61
|
-
page.has_content?(
|
61
|
+
page.has_content?("Log in") ? click_button("Log in") : click_button("Sign in")
|
62
62
|
user
|
63
63
|
end
|
64
|
-
|
65
64
|
end
|
data/test/model_tests_helper.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
class ActiveSupport::TestCase
|
2
|
-
|
3
2
|
#
|
4
3
|
# Helpers for creating new users
|
5
4
|
#
|
@@ -9,14 +8,13 @@ class ActiveSupport::TestCase
|
|
9
8
|
"user-#{@@unique_identity_count}@mail.invalid"
|
10
9
|
end
|
11
10
|
|
12
|
-
def valid_attributes(attributes={})
|
13
|
-
{
|
14
|
-
|
15
|
-
|
11
|
+
def valid_attributes(attributes = {})
|
12
|
+
{email: unique_identity,
|
13
|
+
password: "12345678",
|
14
|
+
password_confirmation: "12345678"}.update(attributes)
|
16
15
|
end
|
17
16
|
|
18
|
-
def new_user(attributes={})
|
17
|
+
def new_user(attributes = {})
|
19
18
|
User.new(valid_attributes(attributes)).save
|
20
19
|
end
|
21
|
-
|
22
20
|
end
|
@@ -1,32 +1,31 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "test_helper"
|
2
|
+
require "model_tests_helper"
|
3
3
|
|
4
4
|
class OtpAuthenticatableTest < ActiveSupport::TestCase
|
5
|
-
|
6
5
|
def setup
|
7
6
|
new_user
|
8
7
|
end
|
9
8
|
|
10
|
-
test
|
9
|
+
test "new users have a non-nil secret set" do
|
11
10
|
assert_not_nil User.first.otp_auth_secret
|
12
11
|
end
|
13
12
|
|
14
|
-
test
|
13
|
+
test "new users have OTP disabled by default" do
|
15
14
|
assert !User.first.otp_enabled
|
16
15
|
end
|
17
16
|
|
18
|
-
test
|
17
|
+
test "users should have an instance of TOTP/ROTP objects" do
|
19
18
|
u = User.first
|
20
19
|
assert u.time_based_otp.is_a? ROTP::TOTP
|
21
20
|
assert u.recovery_otp.is_a? ROTP::HOTP
|
22
21
|
end
|
23
22
|
|
24
|
-
test
|
23
|
+
test "users should have their otp_auth_secret/persistence_seed set on creation" do
|
25
24
|
assert User.first.otp_auth_secret
|
26
25
|
assert User.first.otp_persistence_seed
|
27
26
|
end
|
28
27
|
|
29
|
-
test
|
28
|
+
test "reset_otp_credentials should generate new secrets and disable OTP" do
|
30
29
|
u = User.first
|
31
30
|
u.update_attribute(:otp_enabled, true)
|
32
31
|
assert u.otp_enabled
|
@@ -39,7 +38,7 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
|
|
39
38
|
assert !u.otp_enabled
|
40
39
|
end
|
41
40
|
|
42
|
-
test
|
41
|
+
test "reset_otp_persistence should generate new persistence_seed but NOT change the otp_auth_secret" do
|
43
42
|
u = User.first
|
44
43
|
u.update_attribute(:otp_enabled, true)
|
45
44
|
assert u.otp_enabled
|
@@ -47,22 +46,22 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
|
|
47
46
|
otp_persistence_seed = u.otp_persistence_seed
|
48
47
|
|
49
48
|
u.reset_otp_persistence!
|
50
|
-
assert
|
49
|
+
assert(otp_auth_secret == u.otp_auth_secret)
|
51
50
|
assert !(otp_persistence_seed == u.otp_persistence_seed)
|
52
51
|
assert u.otp_enabled
|
53
52
|
end
|
54
53
|
|
55
|
-
test
|
54
|
+
test "generating a challenge, should retrieve the user later" do
|
56
55
|
u = User.first
|
57
56
|
u.update_attribute(:otp_enabled, true)
|
58
57
|
challenge = u.generate_otp_challenge!
|
59
58
|
|
60
59
|
w = User.find_valid_otp_challenge(challenge)
|
61
60
|
assert w.is_a? User
|
62
|
-
assert_equal w,u
|
61
|
+
assert_equal w, u
|
63
62
|
end
|
64
63
|
|
65
|
-
test
|
64
|
+
test "expiring the challenge, should retrieve nothing" do
|
66
65
|
u = User.first
|
67
66
|
u.update_attribute(:otp_enabled, true)
|
68
67
|
challenge = u.generate_otp_challenge!(1.second)
|
@@ -72,7 +71,7 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
|
|
72
71
|
assert_nil w
|
73
72
|
end
|
74
73
|
|
75
|
-
test
|
74
|
+
test "expired challenges should not be valid" do
|
76
75
|
u = User.first
|
77
76
|
u.update_attribute(:otp_enabled, true)
|
78
77
|
challenge = u.generate_otp_challenge!(1.second)
|
@@ -80,14 +79,14 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
|
|
80
79
|
assert_equal false, u.otp_challenge_valid?
|
81
80
|
end
|
82
81
|
|
83
|
-
test
|
82
|
+
test "null otp challenge" do
|
84
83
|
u = User.first
|
85
84
|
u.update_attribute(:otp_enabled, true)
|
86
|
-
assert_equal false, u.validate_otp_token(
|
85
|
+
assert_equal false, u.validate_otp_token("")
|
87
86
|
assert_equal false, u.validate_otp_token(nil)
|
88
87
|
end
|
89
88
|
|
90
|
-
test
|
89
|
+
test "generated otp token should be valid for the user" do
|
91
90
|
u = User.first
|
92
91
|
u.update_attribute(:otp_enabled, true)
|
93
92
|
|
@@ -97,7 +96,7 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
|
|
97
96
|
assert_equal true, u.validate_otp_token(token)
|
98
97
|
end
|
99
98
|
|
100
|
-
test
|
99
|
+
test "generated otp token, out of drift window, should be NOT valid for the user" do
|
101
100
|
u = User.first
|
102
101
|
u.update_attribute(:otp_enabled, true)
|
103
102
|
|
@@ -109,7 +108,7 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
|
|
109
108
|
end
|
110
109
|
end
|
111
110
|
|
112
|
-
test
|
111
|
+
test "recovery secrets should be valid, and valid only once" do
|
113
112
|
u = User.first
|
114
113
|
u.update_attribute(:otp_enabled, true)
|
115
114
|
recovery = u.next_otp_recovery_tokens
|
data/test/test_helper.rb
CHANGED
@@ -4,21 +4,21 @@ DEVISE_ORM = (ENV["DEVISE_ORM"] || :active_record).to_sym
|
|
4
4
|
puts "\n==> Devise.orm = #{DEVISE_ORM.inspect}"
|
5
5
|
require "dummy/config/environment"
|
6
6
|
require "orm/#{DEVISE_ORM}"
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
7
|
+
require "rails/test_help"
|
8
|
+
require "capybara/rails"
|
9
|
+
require "capybara/cuprite"
|
10
|
+
require "minitest/reporters"
|
11
11
|
|
12
12
|
MiniTest::Reporters.use!
|
13
13
|
|
14
|
-
#I18n.load_path << File.expand_path("../support/locale/en.yml", __FILE__) if DEVISE_ORM == :mongoid
|
14
|
+
# I18n.load_path << File.expand_path("../support/locale/en.yml", __FILE__) if DEVISE_ORM == :mongoid
|
15
15
|
|
16
|
-
#ActiveSupport::Deprecation.silenced = true
|
16
|
+
# ActiveSupport::Deprecation.silenced = true
|
17
17
|
|
18
18
|
# Use a module to not pollute the global namespace
|
19
19
|
module CapybaraHelper
|
20
20
|
def self.register_driver(driver_name, args = [])
|
21
|
-
opts = {
|
21
|
+
opts = {headless: true, js_errors: true, window_size: [1920, 1200], browser_options: {}}
|
22
22
|
args.each do |arg|
|
23
23
|
opts[:browser_options][arg] = nil
|
24
24
|
end
|
@@ -33,12 +33,12 @@ end
|
|
33
33
|
CapybaraHelper.register_driver(:headless_chrome, %w[disable-gpu no-sandbox disable-dev-shm-usage])
|
34
34
|
|
35
35
|
# Configure Capybara JS driver
|
36
|
-
Capybara.current_driver
|
36
|
+
Capybara.current_driver = :headless_chrome
|
37
37
|
Capybara.javascript_driver = :headless_chrome
|
38
38
|
|
39
39
|
# Configure Capybara server
|
40
40
|
Capybara.run_server = true
|
41
|
-
Capybara.server
|
41
|
+
Capybara.server = :puma, {Silent: true}
|
42
42
|
|
43
43
|
class ActionDispatch::IntegrationTest
|
44
44
|
include Capybara::DSL
|
@@ -53,7 +53,7 @@ class ActionDispatch::IntegrationTest
|
|
53
53
|
# See: https://github.com/rubycdp/ferrum/blob/master/lib/ferrum/page.rb
|
54
54
|
def enable_chrome_headless_downloads(session, directory)
|
55
55
|
page = session.driver.browser.page
|
56
|
-
page.command(
|
56
|
+
page.command("Page.setDownloadBehavior", behavior: "allow", downloadPath: directory)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|