devise-otp 0.7.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +18 -8
  3. data/.gitignore +2 -0
  4. data/Appraisals +36 -0
  5. data/CHANGELOG.md +4 -1
  6. data/Gemfile +12 -0
  7. data/README.md +8 -7
  8. data/app/assets/stylesheets/devise-otp.css +4 -0
  9. data/app/controllers/devise_otp/devise/otp_credentials_controller.rb +4 -6
  10. data/app/controllers/devise_otp/devise/otp_tokens_controller.rb +7 -8
  11. data/app/views/devise/otp_tokens/show.html.erb +1 -1
  12. data/config/locales/en.yml +0 -2
  13. data/devise-otp.gemspec +8 -16
  14. data/gemfiles/rails_7.0.gemfile +25 -0
  15. data/gemfiles/rails_7.1.gemfile +21 -0
  16. data/gemfiles/rails_7.2.gemfile +17 -0
  17. data/gemfiles/rails_8.0.gemfile +17 -0
  18. data/lib/devise-otp/version.rb +1 -1
  19. data/lib/devise_otp_authenticatable/controllers/helpers.rb +5 -28
  20. data/lib/generators/active_record/templates/migration.rb +1 -1
  21. data/test/dummy/app/assets/javascripts/application.js +0 -1
  22. data/test/dummy/app/assets/stylesheets/application.css +1 -0
  23. data/test/dummy/app/views/layouts/application.html.erb +7 -1
  24. data/test/dummy/config/routes.rb +1 -1
  25. data/test/dummy/db/migrate/20240604000001_create_admins.rb +1 -1
  26. data/test/integration/disable_token_test.rb +3 -0
  27. data/test/integration/enable_otp_form_test.rb +17 -0
  28. data/test/integration/persistence_test.rb +3 -0
  29. data/test/integration/refresh_test.rb +9 -0
  30. data/test/integration/reset_token_test.rb +3 -0
  31. data/test/integration/sign_in_test.rb +30 -0
  32. data/test/orm/active_record.rb +6 -1
  33. metadata +19 -118
  34. data/app/assets/javascripts/devise-otp.js +0 -1
  35. data/app/assets/javascripts/qrcode.js +0 -609
  36. data/docs/QR_CODES.md +0 -48
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 591466bedc565bb6914c791657c39f3337ab5cb8c91bad78027ce2a27e7008ae
4
- data.tar.gz: b7b7edc112fd429cf51ad1c48adf126138b3f875cdb103c6259cd316237ae5d1
3
+ metadata.gz: 7a2884c76d255b2c2bb3b40859db7018c5668d49fcb6897141dacd8d7df0bc62
4
+ data.tar.gz: 3c7ee30dd96a9711b4b4194cb2b94cea6abb06113dda2ef58b70c9a96c998ec4
5
5
  SHA512:
6
- metadata.gz: 299c6b4523d6f180fa3c795b1fc56a00eceeafdff0f36e9086f26da9c958acbcbabd2329919105fa24cf433bc14eeeba44642a0dff75189473811dd48da3088f
7
- data.tar.gz: 6caad7adc9cd91b05f9e05cb0d0364e9aca50d7d9cc67b97c58aeb7d465f365bf42e4fad1f37f54d19d48452b844e9ede4156f8f25898e463a99951e5c66c8df
6
+ metadata.gz: b099c20c5c6d76fc2e1226511615bb43f2b081620f01bbf1bcc939cec66e286aa3536f8a654495907607e42d23e7f3efd9bb3377ed3a1a8a6ef522ec5e9568e1
7
+ data.tar.gz: 731d1dc34877d0fe91bb092b33ce4ee7c302c4cb75183daa3ff67a0df7f6d242bc86b3ab4e0923683b8408c8f1e6bab8e8a1d1c5fa10b9b0e104617a9b87ded7
@@ -7,28 +7,38 @@ on:
7
7
 
8
8
  jobs:
9
9
  rspec:
10
- runs-on: ubuntu-20.04
10
+ runs-on: ubuntu-latest
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
14
  ruby:
15
+ - '3.3'
16
+ - '3.2'
15
17
  - '3.1'
18
+ - 'head'
19
+ rails:
20
+ - rails_8.0
21
+ - rails_7.2
22
+ - rails_7.1
23
+ - rails_7.0
24
+ exclude:
25
+ - ruby: '3.1'
26
+ rails: 'rails_8.0'
27
+
28
+ env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
29
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.rails }}.gemfile
16
30
 
17
31
  steps:
18
32
  - name: Checkout
19
- uses: actions/checkout@v2
33
+ uses: actions/checkout@v4
20
34
 
21
35
  - name: Setup Ruby
22
36
  uses: ruby/setup-ruby@v1
23
37
  with:
24
38
  ruby-version: ${{ matrix.ruby }}
25
-
26
- - name: Bundle
27
- run: |
28
- gem install bundler
29
- bundle install --jobs 4 --retry 3
39
+ bundler-cache: true
30
40
 
31
41
  - name: Run tests
32
42
  env:
33
43
  DEVISE_ORM: active_record
34
- run: rake test
44
+ run: bundle exec rake test
data/.gitignore CHANGED
@@ -38,7 +38,9 @@ test/dummy/db/*.sqlite3
38
38
  test/dummy/db/*.sqlite3-shm
39
39
  test/dummy/db/*.sqlite3-wal
40
40
 
41
+ # Ignore Gemfile.lock
41
42
  Gemfile.lock
43
+ gemfiles/*.lock
42
44
 
43
45
  # Generated test files
44
46
  tmp/*
data/Appraisals ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise 'rails_7.0' do
4
+ gem 'rails', '~> 7.0.0'
5
+ gem 'sqlite3', '~> 1.5.0'
6
+
7
+ # Fix: LoadError: cannot load such file -- base64
8
+ install_if '-> { Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.3.0") }' do
9
+ gem 'base64'
10
+ gem 'bigdecimal'
11
+ gem 'mutex_m'
12
+ gem 'drb'
13
+ gem 'logger'
14
+ end
15
+ end
16
+
17
+ appraise 'rails_7.1' do
18
+ gem 'rails', '~> 7.1.0'
19
+ gem 'sqlite3', '~> 1.5.0'
20
+
21
+ # Fix:
22
+ # warning: logger was loaded from the standard library, but will no longer be part of the default gems since Ruby 3.5.0.
23
+ # Add logger to your Gemfile or gemspec.
24
+ install_if '-> { Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0") }' do
25
+ gem 'logger'
26
+ end
27
+ end
28
+
29
+ appraise 'rails_7.2' do
30
+ gem 'rails', '~> 7.2.0'
31
+ gem 'sqlite3', '~> 1.5.0'
32
+ end
33
+
34
+ appraise 'rails_8.0' do
35
+ gem 'rails', '~> 8.0.0'
36
+ end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ - Upgrade gemspec to support Rails v7.2
6
+
3
7
  ## 0.7.0
4
8
 
5
9
  Breaking changes:
@@ -57,4 +61,3 @@ Fixes:
57
61
 
58
62
  - mandatory otp fix by @cotcomsol in #68
59
63
  - remove success message by @strzibny in #69
60
-
data/Gemfile CHANGED
@@ -2,3 +2,15 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in devise-otp.gemspec
4
4
  gemspec
5
+
6
+ gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
7
+
8
+ gem "capybara"
9
+ gem "minitest-reporters", ">= 0.5.0"
10
+ gem "puma"
11
+ gem "rake"
12
+ gem "rdoc"
13
+ gem "shoulda"
14
+ gem "sprockets-rails"
15
+ gem "sqlite3", "~> 2.1"
16
+ gem "standardrb"
data/README.md CHANGED
@@ -13,7 +13,7 @@ Some of the compatible token devices are:
13
13
  * [Google Authenticator](https://code.google.com/p/google-authenticator/)
14
14
  * [FreeOTP](https://fedorahosted.org/freeotp/)
15
15
 
16
- Device OTP was recently updated to work with Rails 7 and Turbo.
16
+ Device OTP was recently updated to work with Rails 7+ and Turbo.
17
17
 
18
18
  ## Sponsor
19
19
 
@@ -58,10 +58,13 @@ Don't forget to migrate:
58
58
 
59
59
  rake db:migrate
60
60
 
61
- Add the gem's JavaScript to you `application.js`:
61
+ ### Default CSS
62
62
 
63
- //= require devise-otp
63
+ To use the default CSS for devise-otp, just require the devise-otp.css file as usual in your application.css file (or equivalent):
64
64
 
65
+ *= require devise-otp
66
+
67
+ It might be even easier to just copy the styles to your project.
65
68
 
66
69
  ### Custom views
67
70
 
@@ -77,9 +80,7 @@ The install generator also installs an english copy of a Devise OTP i18n file. T
77
80
 
78
81
  ### QR codes
79
82
 
80
- By default, Devise OTP assumes that you use [Sprockets](https://github.com/rails/sprockets) to render assets and so will use the ([qrcode.js](/app/assets/javascripts/qrcode.js)) embeded library to render the QR code.
81
-
82
- If you need something more, have a look at [QR codes](/docs/QR_CODES.md) documentation file.
83
+ Devise OTP generates QR Codes directly as SVG's via the [rqrcode](https://github.com/whomwah/rqrcode), so there are no JavaScript (or Sprockets) dependencies.
83
84
 
84
85
  ## Configuration
85
86
 
@@ -102,7 +103,7 @@ Enforcing mandatory OTP requires adding the ensure\_mandatory\_{scope}\_otp! met
102
103
 
103
104
  ## Authors
104
105
 
105
- The project was originally started by Lele Forzani by forking [devise_google_authenticator](https://github.com/AsteriskLabs/devise_google_authenticator) and still contains some devise_google_authenticator code. It's now maintained by [Josef Strzibny](https://github.com/strzibny/).
106
+ The project was originally started by Lele Forzani by forking [devise_google_authenticator](https://github.com/AsteriskLabs/devise_google_authenticator) and still contains some devise_google_authenticator code. It's now maintained by [Josef Strzibny](https://github.com/strzibny/) and [Laney Stroup](https://github.com/strouptl).
106
107
 
107
108
  Contributions are welcome!
108
109
 
@@ -0,0 +1,4 @@
1
+ .qrcode-container {
2
+ max-width: 300px;
3
+ margin: 0 auto;
4
+ }
@@ -26,17 +26,15 @@ module DeviseOtp
26
26
  # signs the resource in, if the OTP token is valid and the user has a valid challenge
27
27
  #
28
28
  def update
29
- if @token.blank?
30
- otp_set_flash_message(:alert, :token_blank)
31
- redirect_to otp_credential_path_for(resource_name, challenge: @challenge, recovery: @recovery)
32
- elsif resource.otp_challenge_valid? && resource.validate_otp_token(@token, @recovery)
29
+ if resource.otp_challenge_valid? && resource.validate_otp_token(@token, @recovery)
33
30
  sign_in(resource_name, resource)
34
31
 
35
32
  otp_set_trusted_device_for(resource) if params[:enable_persistence] == "true"
36
33
  otp_refresh_credentials_for(resource)
37
34
  respond_with resource, location: after_sign_in_path_for(resource)
38
35
  else
39
- otp_set_flash_message :alert, :token_invalid
36
+ kind = (@token.blank? ? :token_blank : :token_invalid)
37
+ otp_set_flash_message :alert, kind, :now => true
40
38
  render :show
41
39
  end
42
40
  end
@@ -103,7 +101,7 @@ module DeviseOtp
103
101
  end
104
102
 
105
103
  def failed_refresh
106
- otp_set_flash_message :alert, :invalid_refresh
104
+ otp_set_flash_message :alert, :invalid_refresh, :now => true
107
105
  render :refresh
108
106
  end
109
107
 
@@ -33,9 +33,9 @@ module DeviseOtp
33
33
  if resource.valid_otp_token?(params[:confirmation_code])
34
34
  resource.enable_otp!
35
35
  otp_set_flash_message :success, :successfully_updated
36
- redirect_to action: :show
36
+ redirect_to otp_token_path_for(resource)
37
37
  else
38
- otp_set_flash_message :danger, :could_not_confirm
38
+ otp_set_flash_message :danger, :could_not_confirm, :now => true
39
39
  render :edit
40
40
  end
41
41
  end
@@ -48,7 +48,7 @@ module DeviseOtp
48
48
  otp_set_flash_message :success, :successfully_disabled_otp
49
49
  end
50
50
 
51
- redirect_to action: :show
51
+ redirect_to otp_token_path_for(resource)
52
52
  end
53
53
 
54
54
  #
@@ -59,7 +59,7 @@ module DeviseOtp
59
59
  otp_set_flash_message :success, :successfully_set_persistence
60
60
  end
61
61
 
62
- redirect_to action: :show
62
+ redirect_to otp_token_path_for(resource)
63
63
  end
64
64
 
65
65
  #
@@ -70,7 +70,7 @@ module DeviseOtp
70
70
  otp_set_flash_message :success, :successfully_cleared_persistence
71
71
  end
72
72
 
73
- redirect_to action: :show
73
+ redirect_to otp_token_path_for(resource)
74
74
  end
75
75
 
76
76
  #
@@ -81,7 +81,7 @@ module DeviseOtp
81
81
  otp_set_flash_message :notice, :successfully_reset_persistence
82
82
  end
83
83
 
84
- redirect_to action: :show
84
+ redirect_to otp_token_path_for(resource)
85
85
  end
86
86
 
87
87
  def recovery
@@ -100,7 +100,7 @@ module DeviseOtp
100
100
  otp_set_flash_message :success, :successfully_reset_otp
101
101
  end
102
102
 
103
- redirect_to action: :edit
103
+ redirect_to edit_otp_token_path_for(resource)
104
104
  end
105
105
 
106
106
  private
@@ -109,7 +109,6 @@ module DeviseOtp
109
109
  ensure_resource!
110
110
 
111
111
  if needs_credentials_refresh?(resource)
112
- otp_set_flash_message :notice, :need_to_refresh_credentials
113
112
  redirect_to refresh_otp_credential_path_for(resource)
114
113
  end
115
114
  end
@@ -7,7 +7,7 @@
7
7
  <%= render :partial => 'trusted_devices' if trusted_devices_enabled? %>
8
8
 
9
9
  <% unless otp_mandatory_on?(resource) %>
10
- <%= button_to I18n.t('disable_link', :scope => 'devise.otp.otp_tokens'), @resource, :method => :delete, :data => { "turbo-method": "DELETE" } %>
10
+ <%= button_to I18n.t('disable_link', :scope => 'devise.otp.otp_tokens'), otp_token_path_for(resource), :method => :delete, :data => { "turbo-method": "DELETE" } %>
11
11
  <% end %>
12
12
  <% else %>
13
13
  <%= link_to I18n.t('enable_link', :scope => 'devise.otp.otp_tokens'), edit_otp_token_path_for(resource) %>
@@ -14,7 +14,6 @@ en:
14
14
  otp_session_invalid: Session invalid. Please start again.
15
15
  token_invalid: 'The token you provided was invalid.'
16
16
  token_blank: 'You need to type in the token you generated with your device.'
17
- need_to_refresh_credentials: 'We need to check your credentials before you can change these settings.'
18
17
  valid_refresh: 'Thank you, your credentials were accepted.'
19
18
  invalid_refresh: 'Sorry, you provided the wrong credentials.'
20
19
  credentials_refresh:
@@ -41,7 +40,6 @@ en:
41
40
  successfully_set_persistence: 'Your device is now trusted.'
42
41
  successfully_cleared_persistence: 'Your device has been removed from the list of trusted devices.'
43
42
  successfully_reset_persistence: 'Your list of trusted devices has been cleared.'
44
- need_to_refresh_credentials: 'We need to check your credentials before you can change these settings.'
45
43
  recovery:
46
44
  title: 'Your Emergency Recovery Codes'
47
45
  explain: 'Take note or print these recovery codes. The will allow you to log back in in case your token device is lost, stolen, or unavailable.'
data/devise-otp.gemspec CHANGED
@@ -5,25 +5,17 @@ require_relative "lib/devise-otp/version"
5
5
  Gem::Specification.new do |gem|
6
6
  gem.name = "devise-otp"
7
7
  gem.version = Devise::OTP::VERSION
8
- gem.authors = ["Lele Forzani", "Josef Strzibny"]
9
- gem.email = ["lele@windmill.it", "strzibny@strzibny.name"]
10
- gem.description = "Time Based OTP/rfc6238 compatible authentication for Devise"
8
+ gem.authors = ["Lele Forzani", "Josef Strzibny", "Laney Stroup"]
9
+ gem.email = ["lele@windmill.it", "strzibny@strzibny.name", "laney@stroupsolutions.com"]
10
+ gem.description = "OTP authentication for Devise"
11
11
  gem.summary = "Time Based OTP/rfc6238 compatible authentication for Devise"
12
- gem.homepage = "http://git.windmill.it/wm/devise-otp"
12
+ gem.homepage = "https://github.com/wmlele/devise-otp"
13
13
 
14
14
  gem.files = `git ls-files`.split($/)
15
15
  gem.require_paths = ["lib"]
16
16
 
17
- gem.add_runtime_dependency "rails", ">= 6.1", "< 7.2"
18
- gem.add_runtime_dependency "devise", ">= 4.8.0", "< 5.0"
19
- gem.add_runtime_dependency "rotp", ">= 2.0.0"
20
-
21
- gem.add_development_dependency "capybara"
22
- gem.add_development_dependency "minitest-reporters", ">= 0.5.0"
23
- gem.add_development_dependency "puma"
24
- gem.add_development_dependency "rdoc"
25
- gem.add_development_dependency "shoulda"
26
- gem.add_development_dependency "sprockets-rails"
27
- gem.add_development_dependency "sqlite3", "~> 1.4"
28
- gem.add_development_dependency "standardrb"
17
+ gem.add_dependency "rails", ">= 7.0"
18
+ gem.add_dependency "devise", ">= 4.8.0", "< 5.0"
19
+ gem.add_dependency "rotp", ">= 2.0.0"
20
+ gem.add_dependency "rqrcode", "~> 2.0"
29
21
  end
@@ -0,0 +1,25 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
6
+ gem "capybara"
7
+ gem "minitest-reporters", ">= 0.5.0"
8
+ gem "puma"
9
+ gem "rake"
10
+ gem "rdoc"
11
+ gem "shoulda"
12
+ gem "sprockets-rails"
13
+ gem "sqlite3", "~> 1.5.0"
14
+ gem "standardrb"
15
+ gem "rails", "~> 7.0.0"
16
+
17
+ install_if -> { Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.3.0") } do
18
+ gem "base64"
19
+ gem "bigdecimal"
20
+ gem "mutex_m"
21
+ gem "drb"
22
+ gem "logger"
23
+ end
24
+
25
+ gemspec path: "../"
@@ -0,0 +1,21 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
6
+ gem "capybara"
7
+ gem "minitest-reporters", ">= 0.5.0"
8
+ gem "puma"
9
+ gem "rake"
10
+ gem "rdoc"
11
+ gem "shoulda"
12
+ gem "sprockets-rails"
13
+ gem "sqlite3", "~> 1.5.0"
14
+ gem "standardrb"
15
+ gem "rails", "~> 7.1.0"
16
+
17
+ install_if -> { Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0") } do
18
+ gem "logger"
19
+ end
20
+
21
+ gemspec path: "../"
@@ -0,0 +1,17 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
6
+ gem "capybara"
7
+ gem "minitest-reporters", ">= 0.5.0"
8
+ gem "puma"
9
+ gem "rake"
10
+ gem "rdoc"
11
+ gem "shoulda"
12
+ gem "sprockets-rails"
13
+ gem "sqlite3", "~> 1.5.0"
14
+ gem "standardrb"
15
+ gem "rails", "~> 7.2.0"
16
+
17
+ gemspec path: "../"
@@ -0,0 +1,17 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", git: "https://github.com/thoughtbot/appraisal.git"
6
+ gem "capybara"
7
+ gem "minitest-reporters", ">= 0.5.0"
8
+ gem "puma"
9
+ gem "rake"
10
+ gem "rdoc"
11
+ gem "shoulda"
12
+ gem "sprockets-rails"
13
+ gem "sqlite3", "~> 2.1"
14
+ gem "standardrb"
15
+ gem "rails", "~> 8.0.0"
16
+
17
+ gemspec path: "../"
@@ -1,5 +1,5 @@
1
1
  module Devise
2
2
  module OTP
3
- VERSION = "0.7.1"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
@@ -1,3 +1,5 @@
1
+ require "rqrcode"
2
+
1
3
  module DeviseOtpAuthenticatable
2
4
  module Controllers
3
5
  module Helpers
@@ -12,11 +14,8 @@ module DeviseOtpAuthenticatable
12
14
  #
13
15
  def otp_set_flash_message(key, kind, options = {})
14
16
  options[:scope] ||= "devise.otp.#{controller_name}"
15
- options[:default] = Array(options[:default]).unshift(kind.to_sym)
16
- options[:resource_name] = resource_name
17
- options = devise_i18n_options(options) if respond_to?(:devise_i18n_options, true)
18
- message = I18n.t("#{options[:resource_name]}.#{kind}", **options)
19
- flash[key] = message if message.present?
17
+
18
+ set_flash_message(key, kind, options)
20
19
  end
21
20
 
22
21
  def otp_t
@@ -122,33 +121,11 @@ module DeviseOtpAuthenticatable
122
121
  # returns the URL for the QR Code to initialize the Authenticator device
123
122
  #
124
123
  def otp_authenticator_token_image(resource)
125
- otp_authenticator_token_image_js(resource.otp_provisioning_uri)
126
- end
127
-
128
- private
129
-
130
- def otp_authenticator_token_image_js(otp_url)
131
124
  content_tag(:div, class: "qrcode-container") do
132
- content_tag(:div, id: "qrcode", class: "qrcode") do
133
- javascript_tag(%[
134
- new QRCode("qrcode", {
135
- text: "#{otp_url}",
136
- width: 256,
137
- height: 256,
138
- colorDark : "#000000",
139
- colorLight : "#ffffff",
140
- correctLevel : QRCode.CorrectLevel.H
141
- });
142
- ])
143
- end
125
+ raw RQRCode::QRCode.new(resource.otp_provisioning_uri).as_svg(:module_size => 5, :viewbox => true, :use_path => true)
144
126
  end
145
127
  end
146
128
 
147
- def otp_authenticator_token_image_google(otp_url)
148
- otp_url = Rack::Utils.escape(otp_url)
149
- url = "https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=#{otp_url}"
150
- image_tag(url, alt: "OTP Url QRCode")
151
- end
152
129
  end
153
130
  end
154
131
  end
@@ -1,4 +1,4 @@
1
- class DeviseOtpAddTo<%= table_name.camelize %> < ActiveRecord::Migration
1
+ class DeviseOtpAddTo<%= table_name.camelize %> < ActiveRecord::Migration[7.0]
2
2
  def self.up
3
3
  change_table :<%= table_name %> do |t|
4
4
  t.string :otp_auth_secret
@@ -11,4 +11,3 @@
11
11
  // GO AFTER THE REQUIRES BELOW.
12
12
  //
13
13
  //= require_tree .
14
- //= require devise-otp
@@ -8,6 +8,7 @@
8
8
  * You're free to add application-wide styles to this file and they'll appear at the top of the
9
9
  * compiled file, but it's generally better to create a new file per style scope.
10
10
  *
11
+ *= require devise-otp
11
12
  *= require_self
12
13
  *= require_tree .
13
14
  */
@@ -8,7 +8,13 @@
8
8
  </head>
9
9
  <body>
10
10
 
11
- <%= yield %>
11
+ <div id="alerts">
12
+ <% flash.keys.each do |key| %>
13
+ <%= content_tag :p, flash[key], :id => key %>
14
+ <% end %>
15
+ </div>
16
+
17
+ <%= yield %>
12
18
 
13
19
  </body>
14
20
  </html>
@@ -1,6 +1,6 @@
1
1
  Dummy::Application.routes.draw do
2
- devise_for :users
3
2
  devise_for :admins
3
+ devise_for :users
4
4
 
5
5
  resources :posts
6
6
  resources :admin_posts
@@ -1,4 +1,4 @@
1
- class CreateAdmins < ActiveRecord::Migration[7.1]
1
+ class CreateAdmins < ActiveRecord::Migration[5.0]
2
2
  def change
3
3
  create_table :admins do |t|
4
4
  t.string :name
@@ -23,6 +23,9 @@ class DisableTokenTest < ActionDispatch::IntegrationTest
23
23
  disable_otp
24
24
 
25
25
  assert page.has_content? "Disabled"
26
+ within "#alerts" do
27
+ assert page.has_content? 'Two-Factor Authentication has been disabled.'
28
+ end
26
29
 
27
30
  # logout
28
31
  sign_out
@@ -20,6 +20,10 @@ class EnableOtpFormTest < ActionDispatch::IntegrationTest
20
20
  assert_equal user_otp_token_path, current_path
21
21
  assert page.has_content?("Enabled")
22
22
 
23
+ within "#alerts" do
24
+ assert page.has_content? 'Your Two-Factor Authentication settings have been updated.'
25
+ end
26
+
23
27
  user.reload
24
28
  assert user.otp_enabled?
25
29
  end
@@ -37,6 +41,15 @@ class EnableOtpFormTest < ActionDispatch::IntegrationTest
37
41
 
38
42
  user.reload
39
43
  assert_not user.otp_enabled?
44
+
45
+ within "#alerts" do
46
+ assert page.has_content? 'The Confirmation Code you entered did not match the QR code shown below.'
47
+ end
48
+
49
+ visit "/"
50
+ within "#alerts" do
51
+ assert !page.has_content?('The Confirmation Code you entered did not match the QR code shown below.')
52
+ end
40
53
  end
41
54
 
42
55
  test "a user should not be able enable their OTP authentication with a blank confirmation code" do
@@ -50,6 +63,10 @@ class EnableOtpFormTest < ActionDispatch::IntegrationTest
50
63
 
51
64
  assert page.has_content?("To Enable Two-Factor Authentication")
52
65
 
66
+ within "#alerts" do
67
+ assert page.has_content? 'The Confirmation Code you entered did not match the QR code shown below.'
68
+ end
69
+
53
70
  user.reload
54
71
  assert_not user.otp_enabled?
55
72
  end
@@ -36,6 +36,9 @@ class PersistenceTest < ActionDispatch::IntegrationTest
36
36
 
37
37
  click_link("Trust this browser")
38
38
  assert_text "Your browser is trusted."
39
+ within "#alerts" do
40
+ assert page.has_content? 'Your device is now trusted.'
41
+ end
39
42
  sign_out
40
43
 
41
44
  sign_user_in
@@ -60,6 +60,15 @@ class RefreshTest < ActionDispatch::IntegrationTest
60
60
  fill_in "user_refresh_password", with: "12345670"
61
61
  click_button "Continue..."
62
62
  assert_equal refresh_user_otp_credential_path, current_path
63
+
64
+ within "#alerts" do
65
+ assert page.has_content? 'Sorry, you provided the wrong credentials.'
66
+ end
67
+
68
+ visit "/"
69
+ within "#alerts" do
70
+ assert !page.has_content?('Sorry, you provided the wrong credentials.')
71
+ end
63
72
  end
64
73
 
65
74
  test "user should be finally be able to access their settings, and just password is enough" do
@@ -23,6 +23,9 @@ class ResetTokenTest < ActionDispatch::IntegrationTest
23
23
  reset_otp
24
24
 
25
25
  assert_equal "/users/otp/token/edit", current_path
26
+ within "#alerts" do
27
+ assert page.has_content? 'Your token secret has been reset. Please confirm your new token secret below.'
28
+ end
26
29
  end
27
30
 
28
31
  test "generates new token secrets" do