Skip to content

Commit

Permalink
Ensure authentication_otp returns a boolean value (#85)
Browse files Browse the repository at this point in the history
* Ensure `authentication_otp` returns a boolean value

ref. #84
#57 (comment)

* fix lint violations
  • Loading branch information
EmCousin authored May 30, 2021
1 parent 58f47a6 commit 56c3e1c
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 31 deletions.
64 changes: 40 additions & 24 deletions lib/active_model/one_time_password.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,37 +58,17 @@ def authenticate_otp(code, options = {})
return true if backup_codes_enabled? && authenticate_backup_code(code)

if otp_counter_based
hotp = ROTP::HOTP.new(otp_column, digits: otp_digits)
result = hotp.verify(code, otp_counter)
if result && options[:auto_increment]
self.otp_counter += 1
save if respond_to?(:changed?) && !new_record?
end
result
otp_counter == authenticate_hotp(code, options)
else
totp = ROTP::TOTP.new(otp_column, digits: otp_digits)
if drift = options[:drift]
totp.verify(code, drift_behind: drift)
else
totp.verify(code)
end
authenticate_totp(code, options).present?
end
end

def otp_code(options = {})
if otp_counter_based
if options[:auto_increment]
self.otp_counter += 1
save if respond_to?(:changed?) && !new_record?
end
ROTP::HOTP.new(otp_column, digits: otp_digits).at(self.otp_counter)
hotp_code(options)
else
if options.is_a? Hash
time = options.fetch(:time, Time.now)
else
time = options
end
ROTP::TOTP.new(otp_column, digits: otp_digits).at(time)
totp_code(options)
end
end

Expand Down Expand Up @@ -153,6 +133,42 @@ def backup_codes_enabled?

private

def authenticate_hotp(code, options = {})
hotp = ROTP::HOTP.new(otp_column, digits: otp_digits)
result = hotp.verify(code, otp_counter)
if result && options[:auto_increment]
self.otp_counter += 1
save if respond_to?(:changed?) && !new_record?
end
result
end

def authenticate_totp(code, options = {})
totp = ROTP::TOTP.new(otp_column, digits: otp_digits)
if (drift = options[:drift])
totp.verify(code, drift_behind: drift)
else
totp.verify(code)
end
end

def hotp_code(options = {})
if options[:auto_increment]
self.otp_counter += 1
save if respond_to?(:changed?) && !new_record?
end
ROTP::HOTP.new(otp_column, digits: otp_digits).at(otp_counter)
end

def totp_code(options = {})
time = if options.is_a?(Hash)
options.fetch(:time, Time.now)
else
options
end
ROTP::TOTP.new(otp_column, digits: otp_digits).at(time)
end

def authenticate_backup_code(code)
backup_codes_column_name = self.class.otp_backup_codes_column_name
backup_codes = public_send(backup_codes_column_name)
Expand Down
14 changes: 7 additions & 7 deletions test/one_time_password_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,30 +60,30 @@ def test_opt_in_two_factor

@opt_in.otp_regenerate_secret
code = @opt_in.otp_code
assert @opt_in.authenticate_otp(code)
assert_equal true, @opt_in.authenticate_otp(code)
end

def test_authenticate_with_otp_when_drift_is_allowed
code = @user.otp_code(Time.now - 30)
assert @user.authenticate_otp(code, drift: 60)
assert_equal true, @user.authenticate_otp(code, drift: 60)

code = @visitor.otp_code(Time.now - 30)
assert @visitor.authenticate_otp(code, drift: 60)
assert_equal true, @visitor.authenticate_otp(code, drift: 60)
end

def test_authenticate_with_backup_code
backup_code = @user.public_send(@user.otp_backup_codes_column_name).first
assert @user.authenticate_otp(backup_code)
assert_equal true, @user.authenticate_otp(backup_code)

backup_code = @user.public_send(@user.otp_backup_codes_column_name).last
@user.otp_regenerate_backup_codes
assert !@user.authenticate_otp(backup_code)
assert_equal true, !@user.authenticate_otp(backup_code)
end

def test_authenticate_with_one_time_backup_code
backup_code = @user.public_send(@user.otp_backup_codes_column_name).first
assert @user.authenticate_otp(backup_code)
assert !@user.authenticate_otp(backup_code)
assert_equal true, @user.authenticate_otp(backup_code)
assert_equal true, !@user.authenticate_otp(backup_code)
end

def test_otp_code
Expand Down

0 comments on commit 56c3e1c

Please sign in to comment.