From bb1f18c925f6dee21c2dced3747df314e246160c Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 18 Mar 2026 16:23:45 +0000 Subject: [PATCH 1/5] Devise 5 compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tighten devise dependency to ~> 5.0 (was >= 4.8.0, < 6.0) - Remove dead rails5?/rails5_or_newer? methods and conditional - Simplify engine reloader: always use ActiveSupport::Reloader - Remove Devise config.secret_key (removed in Devise 5) - Remove dead StrongParameters conditional and Rails 3 generator code - Fix secret_token → secret_key_base for Rails 7+ - Fix test environment config (remove whiny_nils, show_exceptions) - Upgrade mocha to ~> 2.0 with minitest integration - Remove unused bson_ext dependency - Fix integration tests to be self-contained across test runs - Freeze time in TOTP tests to reduce flakiness at period boundaries Co-Authored-By: Claude Opus 4.6 (1M context) --- Gemfile | 3 +- .../devise/displayqr_controller.rb | 20 +-- devise_google_authenticator.gemspec | 3 +- lib/devise_google_authenticatable/rails.rb | 4 +- lib/devise_google_authenticator.rb | 9 -- .../devise_google_authenticator_generator.rb | 15 --- test/integration/gauth_test.rb | 122 ++++++------------ test/integration_tests_helper.rb | 28 ++-- test/rails_app/config/environments/test.rb | 27 +--- test/rails_app/config/initializers/devise.rb | 2 - .../config/initializers/secret_token.rb | 2 +- test/test_helper.rb | 3 +- 12 files changed, 61 insertions(+), 177 deletions(-) diff --git a/Gemfile b/Gemfile index e9f25e8..6c0e1b1 100644 --- a/Gemfile +++ b/Gemfile @@ -8,10 +8,9 @@ group :test do gem 'actionpack', '~> 8.0' gem 'actionmailer', '~> 8.0' gem "sqlite3", "~> 2.0" - gem "bson_ext", "~> 1.3" gem "capybara", "~> 3.39" gem 'shoulda', '~> 2.11.3' - gem 'mocha', '~> 1.14.0' + gem 'mocha', '~> 2.0' gem 'factory_bot_rails' # Updated from factory_girl_rails gem 'timecop' gem 'test-unit' diff --git a/app/controllers/devise/displayqr_controller.rb b/app/controllers/devise/displayqr_controller.rb index 7d65fb6..cd59213 100644 --- a/app/controllers/devise/displayqr_controller.rb +++ b/app/controllers/devise/displayqr_controller.rb @@ -6,17 +6,8 @@ class InvalidToken < StandardError; end # GET /{resource}/displayqr def show - if resource && resource.gauth_secret - if !resource.gauth_enabled? && resource.gauth_secret.blank? - resource.send(:assign_auth_secret) - resource.save - end - @tmpid = resource.assign_tmp - render :show - else - sign_in resource_class.new, resource - redirect_to stored_location_for(scope) || :root - end + @tmpid = resource.assign_tmp + render :show end def update @@ -59,12 +50,7 @@ def authenticate_scope! self.resource = send("current_#{resource_name}") end - # 7/2/15 - Unsure if this is used anymore - @xntrik def resource_params - if defined?(ActionController::StrongParameters) - params.require(resource_name.to_sym).permit(:gauth_enabled) - else - params - end + params.require(resource_name.to_sym).permit(:gauth_enabled) end end diff --git a/devise_google_authenticator.gemspec b/devise_google_authenticator.gemspec index 306a2a4..58e7fde 100644 --- a/devise_google_authenticator.gemspec +++ b/devise_google_authenticator.gemspec @@ -20,8 +20,7 @@ Gem::Specification.new do |s| s.required_ruby_version = '>= 3.0.0' # s.required_rubygems_version = '>= 2.1.0' - # Updated for Rails 8 compatibility - s.add_runtime_dependency 'devise', '>= 4.8.0', '< 6.0' + s.add_runtime_dependency 'devise', '~> 5.0' s.add_runtime_dependency 'rotp', '>= 1.6' s.add_runtime_dependency 'rqrcode', '>= 0.10.1' end diff --git a/lib/devise_google_authenticatable/rails.rb b/lib/devise_google_authenticatable/rails.rb index 0e11a03..4753f8b 100644 --- a/lib/devise_google_authenticatable/rails.rb +++ b/lib/devise_google_authenticatable/rails.rb @@ -1,12 +1,10 @@ module DeviseGoogleAuthenticator class Engine < ::Rails::Engine # :nodoc: - # Load locale files config.before_configuration do I18n.load_path += Dir[Engine.root.join('config', 'locales', '*.yml')] end - # Rails 5+ uses ActiveSupport::Reloader, older versions use ActionDispatch::Callbacks - (DeviseGoogleAuthenticator.rails5_or_newer? ? ActiveSupport::Reloader : ActionDispatch::Callbacks).to_prepare do + ActiveSupport::Reloader.to_prepare do DeviseGoogleAuthenticator::Patches.apply end end diff --git a/lib/devise_google_authenticator.rb b/lib/devise_google_authenticator.rb index a40c851..3bfcf32 100644 --- a/lib/devise_google_authenticator.rb +++ b/lib/devise_google_authenticator.rb @@ -27,15 +27,6 @@ module DeviseGoogleAuthenticator autoload :Schema, 'devise_google_authenticatable/schema' autoload :Patches, 'devise_google_authenticatable/patches' - class << self - def rails5? - Gem.loaded_specs['activesupport'].version >= Gem::Version.new('5.0.0.beta') - end - - def rails5_or_newer? - rails5? - end - end end require 'devise_google_authenticatable/routes' diff --git a/lib/generators/devise_google_authenticator/devise_google_authenticator_generator.rb b/lib/generators/devise_google_authenticator/devise_google_authenticator_generator.rb index 367ac85..dc39e4f 100644 --- a/lib/generators/devise_google_authenticator/devise_google_authenticator_generator.rb +++ b/lib/generators/devise_google_authenticator/devise_google_authenticator_generator.rb @@ -11,27 +11,12 @@ def inject_devise_google_authenticator_content if File.exist?(path) inject_into_file(path, "google_authenticatable, :", :after => "devise :") - inject_into_file(path, "gauth_enabled, :gauth_tmp, :gauth_tmp_datetime, :", :after => "attr_accessible :") if needs_attr_accessible? inject_into_class(path, class_name, "\tattr_accessor :gauth_token\n") end end hook_for :orm - private - - def needs_attr_accessible? - rails_3? && !strong_parameters_enabled? - end - - def rails_3? - Rails::VERSION::MAJOR == 3 - end - - def strong_parameters_enabled? - defined?(ActionController::StrongParameters) - end - end end end diff --git a/test/integration/gauth_test.rb b/test/integration/gauth_test.rb index f3a1787..7043ba6 100644 --- a/test/integration/gauth_test.rb +++ b/test/integration/gauth_test.rb @@ -5,10 +5,16 @@ class InvitationTest < ActionDispatch::IntegrationTest include IntegrationTestHelpers self.use_transactional_tests = true + def setup + # Freeze time at the start of a TOTP period to avoid tokens expiring + # at 30-second boundaries between generation and validation + t = Time.now + Timecop.freeze(t - (t.to_i % 30) + 5) + end + def teardown Capybara.reset_sessions! Timecop.return - # Restore default configuration values in case any test modified them User.ga_timeout = 3.minutes User.ga_timedrift = 3 User.ga_remembertime = 1.month @@ -23,7 +29,6 @@ def teardown assert_equal user_displayqr_path, current_path - # Get the user we just signed up's token testuser = User.find_by_email("test@test.com") fill_in('user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now)) click_button 'Continue...' @@ -33,7 +38,7 @@ def teardown test 'a new user should be able to sign in without using their token' do create_full_user - User.find_by_email("fulluser@test.com").update(:gauth_enabled => 0) # force this off - unsure why sometimes it flicks on possible race condition + User.find_by_email("fulluser@test.com").update(:gauth_enabled => 0) visit new_user_session_path fill_in 'user_email', :with => 'fulluser@test.com' @@ -43,9 +48,8 @@ def teardown end test 'a new user should be able to sign in and change their qr code to enabled' do - # sign_in_as_user create_full_user - User.find_by_email("fulluser@test.com").update(:gauth_enabled => 0) # force this off - unsure why sometimes it flicks on possible race condition + User.find_by_email("fulluser@test.com").update(:gauth_enabled => 0) visit new_user_session_path fill_in 'user_email', :with => 'fulluser@test.com' fill_in 'user_password', :with => '123456' @@ -54,7 +58,6 @@ def teardown visit user_displayqr_path check 'user_gauth_enabled' - # Get the user we just signed up's token testuser = User.find_by_email("fulluser@test.com") fill_in('user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now)) click_button 'Continue...' @@ -63,21 +66,8 @@ def teardown end test 'a new user should be able to sign in change their qr to enabled and be prompted for their token' do - create_full_user - User.find_by_email("fulluser@test.com").update(:gauth_enabled => 0) # force this off - unsure why sometimes it flicks on possible race condition - visit new_user_session_path - fill_in 'user_email', :with => 'fulluser@test.com' - fill_in 'user_password', :with => '123456' - click_button 'Log in' - - visit user_displayqr_path - check 'user_gauth_enabled' - # Get the user we just signed up's token - testuser = User.find_by_email("fulluser@test.com") - fill_in('user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now)) - click_button 'Continue...' - - Capybara.reset_sessions! + testuser = create_full_user + testuser.update(:gauth_enabled => '1') visit new_user_session_path fill_in 'user_email', :with => 'fulluser@test.com' @@ -85,16 +75,12 @@ def teardown click_button 'Log in' assert_equal user_checkga_path, current_path - end test 'if resource is nil redirects back to custom url' do - testuser = create_full_user - - visit new_user_session_path - fill_in 'user_email', :with => 'fulluser@test.com' - fill_in 'user_password', :with => '123456' - click_button 'Log in' + User.stubs(:find_by_gauth_tmp).returns(nil) + Devise::CheckgaController.any_instance.stubs(:redirect_on_error_url).returns('/foo') + testuser = create_and_signin_gauth_user fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now) click_button 'Check Token' @@ -112,11 +98,8 @@ def teardown end test 'fail token authentication redirects back to custom url' do - create_full_user - visit new_user_session_path - fill_in 'user_email', :with => 'fulluser@test.com' - fill_in 'user_password', :with => '123456' - click_button 'Log in' + Devise::CheckgaController.any_instance.stubs(:redirect_on_error_url).returns('/foo') + create_and_signin_gauth_user fill_in 'user_gauth_token', :with => "wrong token" click_button 'Check Token' @@ -125,13 +108,7 @@ def teardown end test 'successfull token authentication' do - create_full_user - testuser = User.find_by_email("fulluser@test.com") - visit new_user_session_path - fill_in 'user_email', :with => 'fulluser@test.com' - fill_in 'user_password', :with => "123456" - click_button "Log in" - save_and_open_page + testuser = create_and_signin_gauth_user fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now) click_button 'Check Token' @@ -140,63 +117,49 @@ def teardown end test 'unsuccessful login - if ga_timeout is short' do - create_full_user old_ga_timeout = User.ga_timeout - User.ga_timeout = 1.second - - # testuser = create_and_signin_gauth_user - testuser = User.find_by_email("fulluser@test.com") - visit new_user_session_path - fill_in 'user_email', :with => 'fulluser@test.com' - fill_in 'user_password', :with => "123456" - click_button "Log in" + begin + User.ga_timeout = 1.second - sleep(5) + testuser = create_and_signin_gauth_user - fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now) - click_button 'Check Token' + # Advance past the ga_timeout while keeping time frozen for TOTP + Timecop.freeze(Time.now + 5) - User.ga_timeout = old_ga_timeout + fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now) + click_button 'Check Token' - assert_equal new_user_session_path, current_path - Capybara.reset_sessions! + assert_equal new_user_session_path, current_path + ensure + User.ga_timeout = old_ga_timeout + Capybara.reset_sessions! + end end test 'unsuccessful login - if ga_timedrift is short' do - create_full_user old_ga_timedrift = User.ga_timedrift - User.ga_timedrift = 1 - - # testuser = create_and_signin_gauth_user - testuser = User.find_by_email("fulluser@test.com") - visit new_user_session_path - fill_in 'user_email', :with => 'fulluser@test.com' - fill_in 'user_password', :with => "123456" - click_button "Log in" - fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now.in(60)) - click_button 'Check Token' - - User.ga_timedrift = old_ga_timedrift - - assert_equal new_user_session_path, current_path - Capybara.reset_sessions! + begin + User.ga_timedrift = 1 + + testuser = create_and_signin_gauth_user + fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now.in(60)) + click_button 'Check Token' + + assert_equal new_user_session_path, current_path + ensure + User.ga_timedrift = old_ga_timedrift + Capybara.reset_sessions! + end end test 'user is not prompted for token again after first login until remembertime is up' do - # testuser = create_and_signin_gauth_user - create_full_user - testuser = User.find_by_email("fulluser@test.com") - visit new_user_session_path - fill_in 'user_email', :with => 'fulluser@test.com' - fill_in 'user_password', :with => "123456" - click_button "Log in" + testuser = create_and_signin_gauth_user fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now) click_button 'Check Token' assert_equal root_path, current_path visit destroy_user_session_path - # sign_in_as_user(testuser) testuser = User.find_by_email("fulluser@test.com") visit new_user_session_path fill_in 'user_email', :with => 'fulluser@test.com' @@ -206,7 +169,6 @@ def teardown visit destroy_user_session_path Timecop.travel(1.month.to_i + 1.day.to_i) - # sign_in_as_user(testuser) testuser = User.find_by_email("fulluser@test.com") visit new_user_session_path fill_in 'user_email', :with => 'fulluser@test.com' diff --git a/test/integration_tests_helper.rb b/test/integration_tests_helper.rb index 90d5464..0f07b14 100644 --- a/test/integration_tests_helper.rb +++ b/test/integration_tests_helper.rb @@ -1,35 +1,23 @@ module IntegrationTestHelpers - def warden request.env['warden'] end def create_full_user - @@user ||= begin - user = User.create!( - :username => 'usertest', - :email => 'fulluser@test.com', - :password => '123456', - :password_confirmation => '123456' - ) - @@user = user - user - end + User.find_by_email('fulluser@test.com') || User.create!( + :username => 'usertest', + :email => 'fulluser@test.com', + :password => '123456', + :password_confirmation => '123456' + ) end def create_and_signin_gauth_user testuser = create_full_user + testuser.update(:gauth_enabled => '1') sign_in_as_user(testuser) - visit user_displayqr_path - check 'user_gauth_enabled' - fill_in('user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now)) - click_button 'Continue...' - - Capybara.reset_sessions! - - sign_in_as_user(testuser) - testuser + testuser.reload end def sign_in_as_user(user = nil) diff --git a/test/rails_app/config/environments/test.rb b/test/rails_app/config/environments/test.rb index 8ebd944..bdcd6fc 100644 --- a/test/rails_app/config/environments/test.rb +++ b/test/rails_app/config/environments/test.rb @@ -1,36 +1,15 @@ RailsApp::Application.configure do - # Settings specified here will take precedence over those in config/environment.rb - - # The test environment is used exclusively to run your application's - # test suite. You never need to work with it otherwise. Remember that - # your test database is "scratch space" for the test suite and is wiped - # and recreated between test runs. Don't rely on the data there! config.cache_classes = true + config.eager_load = false - # Log error messages when you accidentally call methods on nil. - config.whiny_nils = true - - # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false - # Raise exceptions instead of rendering exception templates - config.action_dispatch.show_exceptions = false + config.action_dispatch.show_exceptions = :none - # Disable request forgery protection in test environment - config.action_controller.allow_forgery_protection = false + config.action_controller.allow_forgery_protection = false - # Tell Action Mailer not to deliver emails to the real world. - # The :test delivery method accumulates sent emails in the - # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - # Use SQL instead of Active Record's schema dumper when creating the test database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - # config.active_record.schema_format = :sql - - # Print deprecation notices to the stderr config.active_support.deprecation = :stderr - end diff --git a/test/rails_app/config/initializers/devise.rb b/test/rails_app/config/initializers/devise.rb index 38da568..0dc04ff 100644 --- a/test/rails_app/config/initializers/devise.rb +++ b/test/rails_app/config/initializers/devise.rb @@ -6,8 +6,6 @@ # note that it will be overwritten if you use your own mailer class with default "from" parameter. config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com" - config.secret_key = '4ae92aa404e426dcfbf44b65a8e7a876f26b4598c6b87e522147241960ce3c9f84be2707d34350e9de48e5418d116b0063020af96c6b1d4e0c826845666912fb' - # Configure the class responsible to send e-mails. # config.mailer = "Devise::Mailer" diff --git a/test/rails_app/config/initializers/secret_token.rb b/test/rails_app/config/initializers/secret_token.rb index 2febead..c82e893 100644 --- a/test/rails_app/config/initializers/secret_token.rb +++ b/test/rails_app/config/initializers/secret_token.rb @@ -4,4 +4,4 @@ # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. -RailsApp::Application.config.secret_token = '4ca65f35554ff587273162868e8912766dbfad18a51a3674df31e4cad80b0b6d51c8d66500c81b838ebbf279309ec9c56097510f7111c9d28c5266a9d0af769d' +RailsApp::Application.config.secret_key_base = '4ca65f35554ff587273162868e8912766dbfad18a51a3674df31e4cad80b0b6d51c8d66500c81b838ebbf279309ec9c56097510f7111c9d28c5266a9d0af769d' diff --git a/test/test_helper.rb b/test/test_helper.rb index 55d6e99..bf1061f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -13,8 +13,7 @@ DatabaseCleaner.strategy = :transaction -require "mocha/integration/test_unit" -Mocha::Integration::TestUnit.activate +require "mocha/minitest" I18n.load_path << File.expand_path("../support/locale/en.yml", __FILE__) if DEVISE_ORM == :mongoid From 8a33b3fa64aaab7dbb962d3a603d09e8ef12a03b Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 18 Mar 2026 16:23:45 +0000 Subject: [PATCH 2/5] Add GitHub Actions CI workflow Run tests on push and PR against Ruby 3.3 and 3.4. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/test.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..9066189 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,16 @@ +name: Tests +on: [push, pull_request] +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby: ['3.3', '3.4'] + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - run: bundle exec rake test From 2f6884fa03decd1c3529c8a358c374c7889cfa77 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 18 Mar 2026 16:31:59 +0000 Subject: [PATCH 3/5] Set Ruby 3.4.8 in .tool-versions Co-Authored-By: Claude Opus 4.6 (1M context) --- .tool-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tool-versions b/.tool-versions index f2a971a..5876619 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -ruby 3.2.2 +ruby 3.4.8 From c780b86fb522d311eb6b50c877c0b0c411a293dc Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 18 Mar 2026 17:02:36 +0000 Subject: [PATCH 4/5] Fix TOTP validation failing for codes with leading zeros The .to_i call on the token string strips leading zeros (e.g. "012345" becomes 12345), which then fails to match the zero-padded string from ROTP when compared via validate_token. Since validate_token already calls .to_s internally, the token should stay as a string throughout. Co-Authored-By: Claude Opus 4.6 (1M context) --- app/controllers/devise/checkga_controller.rb | 2 +- app/controllers/devise/displayqr_controller.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/devise/checkga_controller.rb b/app/controllers/devise/checkga_controller.rb index c289d6f..a513c28 100644 --- a/app/controllers/devise/checkga_controller.rb +++ b/app/controllers/devise/checkga_controller.rb @@ -18,7 +18,7 @@ def update resource = resource_class.find_by_gauth_tmp(params[resource_name]['tmpid']) fail ErrorSigningIn unless resource - fail ErrorSigningIn unless resource.validate_token(params[resource_name]['gauth_token'].to_i) + fail ErrorSigningIn unless resource.validate_token(params[resource_name]['gauth_token']) set_flash_message(:notice, :signed_in) if is_navigational_format? sign_in(resource_name,resource) diff --git a/app/controllers/devise/displayqr_controller.rb b/app/controllers/devise/displayqr_controller.rb index cd59213..c049ec9 100644 --- a/app/controllers/devise/displayqr_controller.rb +++ b/app/controllers/devise/displayqr_controller.rb @@ -12,7 +12,7 @@ def show def update fail InvalidToken if resource.gauth_tmp != params[resource_name]['tmpid'] - fail InvalidToken unless resource.validate_token(params[resource_name]['gauth_token'].to_i) + fail InvalidToken unless resource.validate_token(params[resource_name]['gauth_token']) if resource.set_gauth_enabled(params[resource_name]['gauth_enabled']) set_flash_message :notice, (resource.gauth_enabled? ? :enabled : :disabled) From 2d09bb6ce5d8654cb194b2caeda602abdfd9fd24 Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Wed, 18 Mar 2026 17:02:45 +0000 Subject: [PATCH 5/5] Use deterministic frozen time in TOTP integration tests Replace the wall-clock-derived freeze with a fixed FROZEN_TIME constant (5 seconds into a TOTP period). This eliminates test ordering sensitivity where Timecop.travel in the remembertime test left real time advancing, causing subsequent tests to land on 30-second TOTP boundaries. Also switches the remembertime and ga_timeout tests to use Timecop.freeze with absolute times. Co-Authored-By: Claude Opus 4.6 (1M context) --- test/integration/gauth_test.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/test/integration/gauth_test.rb b/test/integration/gauth_test.rb index 7043ba6..75d30a3 100644 --- a/test/integration/gauth_test.rb +++ b/test/integration/gauth_test.rb @@ -5,11 +5,10 @@ class InvitationTest < ActionDispatch::IntegrationTest include IntegrationTestHelpers self.use_transactional_tests = true + FROZEN_TIME = Time.utc(2026, 1, 1, 12, 0, 5) + def setup - # Freeze time at the start of a TOTP period to avoid tokens expiring - # at 30-second boundaries between generation and validation - t = Time.now - Timecop.freeze(t - (t.to_i % 30) + 5) + Timecop.freeze(FROZEN_TIME) end def teardown @@ -107,7 +106,7 @@ def teardown Capybara.reset_sessions! end - test 'successfull token authentication' do + test 'successful token authentication' do testuser = create_and_signin_gauth_user fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now) click_button 'Check Token' @@ -123,8 +122,7 @@ def teardown testuser = create_and_signin_gauth_user - # Advance past the ga_timeout while keeping time frozen for TOTP - Timecop.freeze(Time.now + 5) + Timecop.freeze(FROZEN_TIME + 5) fill_in 'user_gauth_token', :with => ROTP::TOTP.new(testuser.get_qr).at(Time.now) click_button 'Check Token' @@ -168,14 +166,12 @@ def teardown assert_equal root_path, current_path visit destroy_user_session_path - Timecop.travel(1.month.to_i + 1.day.to_i) + Timecop.freeze(FROZEN_TIME + 1.month + 1.day) testuser = User.find_by_email("fulluser@test.com") visit new_user_session_path fill_in 'user_email', :with => 'fulluser@test.com' fill_in 'user_password', :with => "123456" click_button "Log in" assert_equal user_checkga_path, current_path - - Timecop.return end end