devise-otp 0.6.0 → 0.7.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +0 -2
  3. data/.gitignore +3 -1
  4. data/CHANGELOG.md +51 -8
  5. data/README.md +8 -2
  6. data/app/controllers/devise_otp/devise/otp_credentials_controller.rb +46 -27
  7. data/app/controllers/devise_otp/devise/otp_tokens_controller.rb +24 -6
  8. data/app/views/devise/otp_credentials/show.html.erb +6 -6
  9. data/app/views/devise/otp_tokens/_token_secret.html.erb +3 -4
  10. data/app/views/devise/otp_tokens/edit.html.erb +26 -0
  11. data/app/views/devise/otp_tokens/show.html.erb +7 -14
  12. data/config/locales/en.yml +23 -14
  13. data/devise-otp.gemspec +1 -2
  14. data/lib/devise/strategies/database_authenticatable.rb +64 -0
  15. data/lib/devise-otp/version.rb +1 -1
  16. data/lib/devise-otp.rb +31 -11
  17. data/lib/devise_otp_authenticatable/controllers/helpers.rb +9 -10
  18. data/lib/devise_otp_authenticatable/controllers/public_helpers.rb +39 -0
  19. data/lib/devise_otp_authenticatable/controllers/url_helpers.rb +10 -0
  20. data/lib/devise_otp_authenticatable/engine.rb +2 -5
  21. data/lib/devise_otp_authenticatable/hooks/refreshable.rb +5 -0
  22. data/lib/devise_otp_authenticatable/models/otp_authenticatable.rb +22 -20
  23. data/lib/devise_otp_authenticatable/routes.rb +3 -1
  24. data/test/dummy/app/controllers/admin_posts_controller.rb +85 -0
  25. data/test/dummy/app/controllers/application_controller.rb +0 -1
  26. data/test/dummy/app/controllers/base_controller.rb +6 -0
  27. data/test/dummy/app/models/admin.rb +25 -0
  28. data/test/dummy/app/views/admin_posts/_form.html.erb +25 -0
  29. data/test/dummy/app/views/admin_posts/edit.html.erb +6 -0
  30. data/test/dummy/app/views/admin_posts/index.html.erb +25 -0
  31. data/test/dummy/app/views/admin_posts/new.html.erb +5 -0
  32. data/test/dummy/app/views/admin_posts/show.html.erb +15 -0
  33. data/test/dummy/app/views/base/home.html.erb +1 -0
  34. data/test/dummy/config/application.rb +0 -2
  35. data/test/dummy/config/routes.rb +4 -1
  36. data/test/dummy/db/migrate/20240604000001_create_admins.rb +9 -0
  37. data/test/dummy/db/migrate/20240604000002_add_devise_to_admins.rb +52 -0
  38. data/test/dummy/db/migrate/20240604000003_devise_otp_add_to_admins.rb +28 -0
  39. data/test/integration/disable_token_test.rb +53 -0
  40. data/test/integration/enable_otp_form_test.rb +57 -0
  41. data/test/integration/persistence_test.rb +3 -6
  42. data/test/integration/refresh_test.rb +32 -0
  43. data/test/integration/reset_token_test.rb +45 -0
  44. data/test/integration/sign_in_test.rb +10 -14
  45. data/test/integration/trackable_test.rb +50 -0
  46. data/test/integration_tests_helper.rb +24 -6
  47. data/test/models/otp_authenticatable_test.rb +62 -27
  48. data/test/test_helper.rb +1 -71
  49. metadata +26 -23
  50. data/lib/devise_otp_authenticatable/hooks/sessions.rb +0 -58
  51. data/lib/devise_otp_authenticatable/hooks.rb +0 -11
  52. data/test/integration/token_test.rb +0 -30
@@ -51,13 +51,10 @@ class PersistenceTest < ActionDispatch::IntegrationTest
51
51
  visit user_otp_token_path
52
52
  assert_equal user_otp_token_path, current_path
53
53
 
54
- enable_chrome_headless_downloads(page, "/tmp/devise-otp")
54
+ click_link("Download recovery codes")
55
55
 
56
- DownloadHelper.wait_for_download(count: 1) do
57
- click_link("Download recovery codes")
58
- end
59
-
60
- assert_equal 1, DownloadHelper.downloads.size
56
+ assert current_path.match?(/recovery\.text/)
57
+ assert page.body.match?(user.next_otp_recovery_tokens.values.join("\n"))
61
58
  end
62
59
 
63
60
  test "trusted status should expire" do
@@ -5,10 +5,12 @@ class RefreshTest < ActionDispatch::IntegrationTest
5
5
  def setup
6
6
  @old_refresh = User.otp_credentials_refresh
7
7
  User.otp_credentials_refresh = 1.second
8
+ Admin.otp_credentials_refresh = 1.second
8
9
  end
9
10
 
10
11
  def teardown
11
12
  User.otp_credentials_refresh = @old_refresh
13
+ Admin.otp_credentials_refresh = @old_refresh
12
14
  Capybara.reset_sessions!
13
15
  end
14
16
 
@@ -72,4 +74,34 @@ class RefreshTest < ActionDispatch::IntegrationTest
72
74
 
73
75
  assert_equal user_otp_token_path, current_path
74
76
  end
77
+
78
+ test "works for non-default warden scopes" do
79
+ admin = create_full_admin
80
+
81
+ admin.populate_otp_secrets!
82
+ admin.enable_otp!
83
+
84
+ visit new_admin_session_path
85
+ fill_in "admin_email", with: admin.email
86
+ fill_in "admin_password", with: admin.password
87
+
88
+ page.has_content?("Log in") ? click_button("Log in") : click_button("Sign in")
89
+
90
+ assert_equal admin_otp_credential_path, current_path
91
+
92
+ fill_in "token", with: ROTP::TOTP.new(admin.otp_auth_secret).at(Time.now)
93
+ click_button "Submit Token"
94
+ assert_equal "/", current_path
95
+
96
+ sleep(2)
97
+
98
+ visit admin_otp_token_path
99
+ assert_equal refresh_admin_otp_credential_path, current_path
100
+
101
+ fill_in "admin_refresh_password", with: "12345678"
102
+ click_button "Continue..."
103
+
104
+ assert_equal admin_otp_token_path, current_path
105
+ end
106
+
75
107
  end
@@ -0,0 +1,45 @@
1
+ require "test_helper"
2
+ require "integration_tests_helper"
3
+
4
+ class ResetTokenTest < ActionDispatch::IntegrationTest
5
+
6
+ def setup
7
+ # log in 1fa
8
+ @user = enable_otp_and_sign_in
9
+ assert_equal user_otp_credential_path, current_path
10
+
11
+ # otp 2fa
12
+ fill_in "token", with: ROTP::TOTP.new(@user.otp_auth_secret).at(Time.now)
13
+ click_button "Submit Token"
14
+ assert_equal root_path, current_path
15
+ end
16
+
17
+
18
+ def teardown
19
+ Capybara.reset_sessions!
20
+ end
21
+
22
+ test "redirects to otp_tokens#edit page" do
23
+ reset_otp
24
+
25
+ assert_equal "/users/otp/token/edit", current_path
26
+ end
27
+
28
+ test "generates new token secrets" do
29
+ # get auth secrets
30
+ auth_secret = @user.otp_auth_secret
31
+ recovery_secret = @user.otp_recovery_secret
32
+
33
+ # reset otp
34
+ reset_otp
35
+
36
+ # compare auth secrets
37
+ @user.reload
38
+ assert_not_nil @user.otp_auth_secret
39
+ assert_not_equal @user.otp_auth_secret, auth_secret
40
+
41
+ assert_not_nil @user.otp_recovery_secret
42
+ assert_not_equal @user.otp_recovery_secret, recovery_secret
43
+ end
44
+
45
+ end
@@ -17,20 +17,16 @@ class SignInTest < ActionDispatch::IntegrationTest
17
17
  assert_equal posts_path, current_path
18
18
  end
19
19
 
20
- test "a new user, just signed in, should be able to sign in and enable their OTP authentication" do
20
+ test "a new user, just signed in, should be able to see and click the 'Enable Two-Factor Authentication' link" do
21
21
  user = sign_user_in
22
22
 
23
23
  visit user_otp_token_path
24
- assert !page.has_content?("Your token secret")
24
+ assert page.has_content?("Disabled")
25
25
 
26
- check "user_otp_enabled"
27
- click_button "Continue..."
26
+ click_link "Enable Two-Factor Authentication"
28
27
 
29
- assert_equal user_otp_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?
28
+ assert page.has_content?("Enable Two-Factor Authentication")
29
+ assert_equal edit_user_otp_token_path, current_path
34
30
  end
35
31
 
36
32
  test "a new user should be able to sign in enable OTP and be prompted for their token" do
@@ -43,17 +39,17 @@ class SignInTest < ActionDispatch::IntegrationTest
43
39
  enable_otp_and_sign_in
44
40
  assert_equal user_otp_credential_path, current_path
45
41
 
46
- fill_in "user_token", with: "123456"
42
+ fill_in "token", with: "123456"
47
43
  click_button "Submit Token"
48
44
 
49
- assert_equal new_user_session_path, current_path
45
+ assert_equal user_otp_credential_path, current_path
50
46
  end
51
47
 
52
48
  test "fail blank token authentication" do
53
49
  enable_otp_and_sign_in
54
50
  assert_equal user_otp_credential_path, current_path
55
51
 
56
- fill_in "user_token", with: ""
52
+ fill_in "token", with: ""
57
53
  click_button "Submit Token"
58
54
 
59
55
  assert_equal user_otp_credential_path, current_path
@@ -62,7 +58,7 @@ class SignInTest < ActionDispatch::IntegrationTest
62
58
  test "successful token authentication" do
63
59
  user = enable_otp_and_sign_in
64
60
 
65
- fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
61
+ fill_in "token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
66
62
  click_button "Submit Token"
67
63
 
68
64
  assert_equal root_path, current_path
@@ -76,7 +72,7 @@ class SignInTest < ActionDispatch::IntegrationTest
76
72
 
77
73
  sleep(2)
78
74
 
79
- fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
75
+ fill_in "token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
80
76
  click_button "Submit Token"
81
77
 
82
78
  User.otp_authentication_timeout = old_timeout
@@ -0,0 +1,50 @@
1
+ require "test_helper"
2
+ require "integration_tests_helper"
3
+
4
+ class TrackableTest < ActionDispatch::IntegrationTest
5
+
6
+ def setup
7
+ @user = sign_user_in
8
+
9
+ @user.reload
10
+
11
+ @sign_in_count = @user.sign_in_count
12
+ @current_sign_in_at = @user.current_sign_in_at
13
+
14
+ sign_out
15
+ end
16
+
17
+ def teardown
18
+ Capybara.reset_sessions!
19
+ end
20
+
21
+ test "if otp is disabled, it should update devise trackable fields as usual when the user signs in" do
22
+ sign_user_in(@user)
23
+
24
+ @user.reload
25
+
26
+ assert_not_equal @sign_in_count, @user.sign_in_count
27
+ assert_not_equal @current_sign_in_at, @user.current_sign_in_at
28
+ end
29
+
30
+ test "if otp is enabled, it should not update devise trackable fields until user enters their user token to complete their sign in" do
31
+ @user.populate_otp_secrets!
32
+ @user.enable_otp!
33
+
34
+ sign_user_in(@user)
35
+
36
+ @user.reload
37
+
38
+ assert_equal @sign_in_count, @user.sign_in_count
39
+ assert_equal @current_sign_in_at, @user.current_sign_in_at
40
+
41
+ fill_in "token", with: ROTP::TOTP.new(@user.otp_auth_secret).at(Time.now)
42
+ click_button "Submit Token"
43
+
44
+ @user.reload
45
+
46
+ assert_not_equal @sign_in_count, @user.sign_in_count
47
+ assert_not_equal @current_sign_in_at, @user.current_sign_in_at
48
+ end
49
+
50
+ end
@@ -16,18 +16,31 @@ class ActionDispatch::IntegrationTest
16
16
  end
17
17
  end
18
18
 
19
+ def create_full_admin
20
+ @admin ||= begin
21
+ admin = Admin.create!(
22
+ email: "admin@email.invalid",
23
+ password: "12345678",
24
+ password_confirmation: "12345678"
25
+ )
26
+ admin
27
+ end
28
+ end
29
+
19
30
  def enable_otp_and_sign_in_with_otp
20
31
  enable_otp_and_sign_in.tap do |user|
21
- fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
32
+ fill_in "token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
22
33
  click_button "Submit Token"
23
34
  end
24
35
  end
25
36
 
26
37
  def enable_otp_and_sign_in
27
38
  user = create_full_user
39
+ user.populate_otp_secrets!
40
+
28
41
  sign_user_in(user)
29
- visit user_otp_token_path
30
- check "user_otp_enabled"
42
+ visit edit_user_otp_token_path
43
+ fill_in "confirmation_code", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
31
44
  click_button "Continue..."
32
45
 
33
46
  Capybara.reset_sessions!
@@ -37,14 +50,18 @@ class ActionDispatch::IntegrationTest
37
50
  end
38
51
 
39
52
  def otp_challenge_for(user)
40
- fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
53
+ fill_in "token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
41
54
  click_button "Submit Token"
42
55
  end
43
56
 
44
57
  def disable_otp
45
58
  visit user_otp_token_path
46
- uncheck "user_otp_enabled"
47
- click_button "Continue..."
59
+ click_button "Disable Two-Factor Authentication"
60
+ end
61
+
62
+ def reset_otp
63
+ visit user_otp_token_path
64
+ click_button "Reset Token Secret"
48
65
  end
49
66
 
50
67
  def sign_out
@@ -61,4 +78,5 @@ class ActionDispatch::IntegrationTest
61
78
  page.has_content?("Log in") ? click_button("Log in") : click_button("Sign in")
62
79
  user
63
80
  end
81
+
64
82
  end
@@ -6,42 +6,70 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
6
6
  new_user
7
7
  end
8
8
 
9
- test "new users have a non-nil secret set" do
10
- assert_not_nil User.first.otp_auth_secret
9
+ test "new users do not have a secret set" do
10
+ user = User.first
11
+
12
+ [:otp_auth_secret, :otp_recovery_secret, :otp_persistence_seed].each do |field|
13
+ assert_nil user.send(field)
14
+ end
11
15
  end
12
16
 
13
17
  test "new users have OTP disabled by default" do
14
18
  assert !User.first.otp_enabled
15
19
  end
16
20
 
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
+ test "populating otp secrets should populate all required fields" do
22
+ user = User.first
23
+ user.populate_otp_secrets!
24
+
25
+ [:otp_auth_secret, :otp_recovery_secret, :otp_persistence_seed].each do |field|
26
+ assert_not_nil user.send(field)
27
+ end
21
28
  end
22
29
 
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
30
+ test "time_based_otp and recover_otp fields should be an instance of TOTP/ROTP objects" do
31
+ user = User.first
32
+ user.populate_otp_secrets!
33
+
34
+ assert user.time_based_otp.is_a? ROTP::TOTP
35
+ assert user.recovery_otp.is_a? ROTP::HOTP
26
36
  end
27
37
 
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
38
+ test "clear_otp_fields should clear all otp fields" do
39
+ user = User.first
40
+ user.populate_otp_secrets!
34
41
 
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
42
+ user.enable_otp!
43
+ user.generate_otp_challenge!
44
+ user.update(
45
+ :otp_failed_attempts => 1,
46
+ :otp_recovery_counter => 1
47
+ )
48
+
49
+
50
+ assert user.otp_enabled
51
+ [:otp_auth_secret, :otp_recovery_secret, :otp_persistence_seed].each do |field|
52
+ assert_not_nil user.send(field)
53
+ end
54
+ [:otp_failed_attempts, :otp_recovery_counter].each do |field|
55
+ assert_not user.send(field) == 0
56
+ end
57
+
58
+ user.clear_otp_fields!
59
+ [:otp_auth_secret, :otp_recovery_secret, :otp_persistence_seed].each do |field|
60
+ assert_nil user.send(field)
61
+ end
62
+ [:otp_failed_attempts, :otp_recovery_counter].each do |field|
63
+ assert user.send(field) == 0
64
+ end
39
65
  end
40
66
 
41
67
  test "reset_otp_persistence should generate new persistence_seed but NOT change the otp_auth_secret" do
42
68
  u = User.first
43
- u.update_attribute(:otp_enabled, true)
69
+ u.populate_otp_secrets!
70
+ u.enable_otp!
44
71
  assert u.otp_enabled
72
+
45
73
  otp_auth_secret = u.otp_auth_secret
46
74
  otp_persistence_seed = u.otp_persistence_seed
47
75
 
@@ -53,7 +81,8 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
53
81
 
54
82
  test "generating a challenge, should retrieve the user later" do
55
83
  u = User.first
56
- u.update_attribute(:otp_enabled, true)
84
+ u.populate_otp_secrets!
85
+ u.enable_otp!
57
86
  challenge = u.generate_otp_challenge!
58
87
 
59
88
  w = User.find_valid_otp_challenge(challenge)
@@ -63,7 +92,8 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
63
92
 
64
93
  test "expiring the challenge, should retrieve nothing" do
65
94
  u = User.first
66
- u.update_attribute(:otp_enabled, true)
95
+ u.populate_otp_secrets!
96
+ u.enable_otp!
67
97
  challenge = u.generate_otp_challenge!(1.second)
68
98
  sleep(2)
69
99
 
@@ -73,7 +103,8 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
73
103
 
74
104
  test "expired challenges should not be valid" do
75
105
  u = User.first
76
- u.update_attribute(:otp_enabled, true)
106
+ u.populate_otp_secrets!
107
+ u.enable_otp!
77
108
  challenge = u.generate_otp_challenge!(1.second)
78
109
  sleep(2)
79
110
  assert_equal false, u.otp_challenge_valid?
@@ -81,14 +112,16 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
81
112
 
82
113
  test "null otp challenge" do
83
114
  u = User.first
84
- u.update_attribute(:otp_enabled, true)
115
+ u.populate_otp_secrets!
116
+ u.enable_otp!
85
117
  assert_equal false, u.validate_otp_token("")
86
118
  assert_equal false, u.validate_otp_token(nil)
87
119
  end
88
120
 
89
121
  test "generated otp token should be valid for the user" do
90
122
  u = User.first
91
- u.update_attribute(:otp_enabled, true)
123
+ u.populate_otp_secrets!
124
+ u.enable_otp!
92
125
 
93
126
  secret = u.otp_auth_secret
94
127
  token = ROTP::TOTP.new(secret).now
@@ -98,7 +131,8 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
98
131
 
99
132
  test "generated otp token, out of drift window, should be NOT valid for the user" do
100
133
  u = User.first
101
- u.update_attribute(:otp_enabled, true)
134
+ u.populate_otp_secrets!
135
+ u.enable_otp!
102
136
 
103
137
  secret = u.otp_auth_secret
104
138
 
@@ -110,7 +144,8 @@ class OtpAuthenticatableTest < ActiveSupport::TestCase
110
144
 
111
145
  test "recovery secrets should be valid, and valid only once" do
112
146
  u = User.first
113
- u.update_attribute(:otp_enabled, true)
147
+ u.populate_otp_secrets!
148
+ u.enable_otp!
114
149
  recovery = u.next_otp_recovery_tokens
115
150
 
116
151
  assert u.valid_otp_recovery_token? recovery.fetch(0)
data/test/test_helper.rb CHANGED
@@ -6,86 +6,16 @@ require "dummy/config/environment"
6
6
  require "orm/#{DEVISE_ORM}"
7
7
  require "rails/test_help"
8
8
  require "capybara/rails"
9
- require "capybara/cuprite"
10
9
  require "minitest/reporters"
11
10
 
12
- MiniTest::Reporters.use!
11
+ Minitest::Reporters.use!
13
12
 
14
13
  # I18n.load_path << File.expand_path("../support/locale/en.yml", __FILE__) if DEVISE_ORM == :mongoid
15
14
 
16
15
  # ActiveSupport::Deprecation.silenced = true
17
16
 
18
- # Use a module to not pollute the global namespace
19
- module CapybaraHelper
20
- def self.register_driver(driver_name, args = [])
21
- opts = {headless: true, js_errors: true, window_size: [1920, 1200], browser_options: {}}
22
- args.each do |arg|
23
- opts[:browser_options][arg] = nil
24
- end
25
-
26
- Capybara.register_driver(driver_name) do |app|
27
- Capybara::Cuprite::Driver.new(app, opts)
28
- end
29
- end
30
- end
31
-
32
- # Register our own custom drivers
33
- CapybaraHelper.register_driver(:headless_chrome, %w[disable-gpu no-sandbox disable-dev-shm-usage])
34
-
35
- # Configure Capybara JS driver
36
- Capybara.current_driver = :headless_chrome
37
- Capybara.javascript_driver = :headless_chrome
38
-
39
- # Configure Capybara server
40
- Capybara.run_server = true
41
- Capybara.server = :puma, {Silent: true}
42
-
43
17
  class ActionDispatch::IntegrationTest
44
18
  include Capybara::DSL
45
-
46
- # What capybara calls a "page" in its DSL is actually a Capybara::Session
47
- # and doesn't know about the *command* method that allows us to play with
48
- # the Chrome API.
49
- # See: https://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session
50
- #
51
- # To enable downloads we need to do it on the browser's page object, so fetch it
52
- # from this long method chain.
53
- # See: https://github.com/rubycdp/ferrum/blob/master/lib/ferrum/page.rb
54
- def enable_chrome_headless_downloads(session, directory)
55
- page = session.driver.browser.page
56
- page.command("Page.setDownloadBehavior", behavior: "allow", downloadPath: directory)
57
- end
58
- end
59
-
60
- # From https://collectiveidea.com/blog/archives/2012/01/27/testing-file-downloads-with-capybara-and-chromedriver
61
- module DownloadHelper
62
- extend self
63
-
64
- TIMEOUT = 10
65
-
66
- def downloads
67
- Dir["/tmp/devise-otp/*"]
68
- end
69
-
70
- def wait_for_download(count: 1)
71
- yield if block_given?
72
-
73
- Timeout.timeout(TIMEOUT) do
74
- sleep 0.2 until downloaded?(count)
75
- end
76
- end
77
-
78
- def downloaded?(count)
79
- !downloading? && downloads.size == count
80
- end
81
-
82
- def downloading?
83
- downloads.grep(/\.crdownload$/).any?
84
- end
85
-
86
- def clear_downloads
87
- FileUtils.rm_f(downloads)
88
- end
89
19
  end
90
20
 
91
21
  require "devise-otp"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise-otp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lele Forzani
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-07-06 00:00:00.000000000 Z
12
+ date: 2024-06-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -79,20 +79,6 @@ dependencies:
79
79
  - - ">="
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
- - !ruby/object:Gem::Dependency
83
- name: cuprite
84
- requirement: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: '0'
89
- type: :development
90
- prerelease: false
91
- version_requirements: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: '0'
96
82
  - !ruby/object:Gem::Dependency
97
83
  name: minitest-reporters
98
84
  requirement: !ruby/object:Gem::Requirement
@@ -167,16 +153,16 @@ dependencies:
167
153
  name: sqlite3
168
154
  requirement: !ruby/object:Gem::Requirement
169
155
  requirements:
170
- - - ">="
156
+ - - "~>"
171
157
  - !ruby/object:Gem::Version
172
- version: '0'
158
+ version: '1.4'
173
159
  type: :development
174
160
  prerelease: false
175
161
  version_requirements: !ruby/object:Gem::Requirement
176
162
  requirements:
177
- - - ">="
163
+ - - "~>"
178
164
  - !ruby/object:Gem::Version
179
- version: '0'
165
+ version: '1.4'
180
166
  - !ruby/object:Gem::Dependency
181
167
  name: standardrb
182
168
  requirement: !ruby/object:Gem::Requirement
@@ -214,6 +200,7 @@ files:
214
200
  - app/views/devise/otp_credentials/show.html.erb
215
201
  - app/views/devise/otp_tokens/_token_secret.html.erb
216
202
  - app/views/devise/otp_tokens/_trusted_devices.html.erb
203
+ - app/views/devise/otp_tokens/edit.html.erb
217
204
  - app/views/devise/otp_tokens/recovery.html.erb
218
205
  - app/views/devise/otp_tokens/recovery_codes.text.erb
219
206
  - app/views/devise/otp_tokens/show.html.erb
@@ -222,11 +209,12 @@ files:
222
209
  - docs/QR_CODES.md
223
210
  - lib/devise-otp.rb
224
211
  - lib/devise-otp/version.rb
212
+ - lib/devise/strategies/database_authenticatable.rb
225
213
  - lib/devise_otp_authenticatable/controllers/helpers.rb
214
+ - lib/devise_otp_authenticatable/controllers/public_helpers.rb
226
215
  - lib/devise_otp_authenticatable/controllers/url_helpers.rb
227
216
  - lib/devise_otp_authenticatable/engine.rb
228
- - lib/devise_otp_authenticatable/hooks.rb
229
- - lib/devise_otp_authenticatable/hooks/sessions.rb
217
+ - lib/devise_otp_authenticatable/hooks/refreshable.rb
230
218
  - lib/devise_otp_authenticatable/models/otp_authenticatable.rb
231
219
  - lib/devise_otp_authenticatable/routes.rb
232
220
  - lib/generators/active_record/devise_otp_generator.rb
@@ -239,13 +227,22 @@ files:
239
227
  - test/dummy/app/assets/config/manifest.js
240
228
  - test/dummy/app/assets/javascripts/application.js
241
229
  - test/dummy/app/assets/stylesheets/application.css
230
+ - test/dummy/app/controllers/admin_posts_controller.rb
242
231
  - test/dummy/app/controllers/application_controller.rb
232
+ - test/dummy/app/controllers/base_controller.rb
243
233
  - test/dummy/app/controllers/posts_controller.rb
244
234
  - test/dummy/app/helpers/application_helper.rb
245
235
  - test/dummy/app/helpers/posts_helper.rb
246
236
  - test/dummy/app/mailers/.gitkeep
237
+ - test/dummy/app/models/admin.rb
247
238
  - test/dummy/app/models/post.rb
248
239
  - test/dummy/app/models/user.rb
240
+ - test/dummy/app/views/admin_posts/_form.html.erb
241
+ - test/dummy/app/views/admin_posts/edit.html.erb
242
+ - test/dummy/app/views/admin_posts/index.html.erb
243
+ - test/dummy/app/views/admin_posts/new.html.erb
244
+ - test/dummy/app/views/admin_posts/show.html.erb
245
+ - test/dummy/app/views/base/home.html.erb
249
246
  - test/dummy/app/views/layouts/application.html.erb
250
247
  - test/dummy/app/views/posts/_form.html.erb
251
248
  - test/dummy/app/views/posts/edit.html.erb
@@ -273,16 +270,22 @@ files:
273
270
  - test/dummy/db/migrate/20130131092406_add_devise_to_users.rb
274
271
  - test/dummy/db/migrate/20130131142320_create_posts.rb
275
272
  - test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb
273
+ - test/dummy/db/migrate/20240604000001_create_admins.rb
274
+ - test/dummy/db/migrate/20240604000002_add_devise_to_admins.rb
275
+ - test/dummy/db/migrate/20240604000003_devise_otp_add_to_admins.rb
276
276
  - test/dummy/lib/assets/.gitkeep
277
277
  - test/dummy/public/404.html
278
278
  - test/dummy/public/422.html
279
279
  - test/dummy/public/500.html
280
280
  - test/dummy/public/favicon.ico
281
281
  - test/dummy/script/rails
282
+ - test/integration/disable_token_test.rb
283
+ - test/integration/enable_otp_form_test.rb
282
284
  - test/integration/persistence_test.rb
283
285
  - test/integration/refresh_test.rb
286
+ - test/integration/reset_token_test.rb
284
287
  - test/integration/sign_in_test.rb
285
- - test/integration/token_test.rb
288
+ - test/integration/trackable_test.rb
286
289
  - test/integration_tests_helper.rb
287
290
  - test/model_tests_helper.rb
288
291
  - test/models/otp_authenticatable_test.rb