Skip to content
This repository has been archived by the owner on Jan 30, 2024. It is now read-only.

reset code after several faild attempts #119

Merged
merged 1 commit into from
Apr 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ add_index :the_resources, :expired_at
create_table :the_resources do |t|
# other devise fields

t.string :paranoid_verification_code
t.string :paranoid_verification_code
t.integer :paranoid_verification_attempt, default: 0
t.datetime :paranoid_verified_at
end
add_index :the_resources, :paranoid_verification_code
Expand Down
2 changes: 2 additions & 0 deletions app/views/devise/paranoid_verification_code/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@
<p><%= f.label :paranoid_verification_code, 'Verification code' %><br />
<%= f.text_field :paranoid_verification_code, value: '' %></p>

<p>After <strong><%= resource.paranoid_attempts_remaining %></strong> faild attemtps, code will be regenerated<p>

<p><%= f.submit "Submit" %></p>
<% end %>
4 changes: 4 additions & 0 deletions lib/devise_security_extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ module Devise
@@expire_after = 90.days
mattr_accessor :delete_expired_after
@@delete_expired_after = 90.days

# paranoid_verification will regenerate verifacation code after faild attempt
mattr_accessor :paranoid_code_regenerate_after_attempt
@@paranoid_code_regenerate_after_attempt = 10
end

# an security extension for devise
Expand Down
18 changes: 14 additions & 4 deletions lib/devise_security_extension/models/paranoid_verification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

module Devise
module Models

# PasswordExpirable takes care of change password after
module ParanoidVerification
extend ActiveSupport::Concern
Expand All @@ -12,13 +11,24 @@ def need_paranoid_verification?
end

def verify_code(code)
if code == paranoid_verification_code
update_without_password paranoid_verification_code: nil, paranoid_verified_at: Time.now
attempt = paranoid_verification_attempt

if (attempt += 1) >= Devise.paranoid_code_regenerate_after_attempt
generate_paranoid_code
elsif code == paranoid_verification_code
attempt = 0
update_without_password paranoid_verification_code: nil, paranoid_verified_at: Time.now, paranoid_verification_attempt: attempt
else
update_without_password paranoid_verification_attempt: attempt
end
end

def paranoid_attempts_remaining
Devise.paranoid_code_regenerate_after_attempt - paranoid_verification_attempt
end

def generate_paranoid_code
update_without_password paranoid_verification_code: Devise.verification_code_generator.call()
update_without_password paranoid_verification_code: Devise.verification_code_generator.call(), paranoid_verification_attempt: 0
end
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class AddVerificationAttemptColumn < ActiveRecord::Migration
def self.up
add_column :users, :paranoid_verification_attempt, :integer, default: 0
end

def self.down
remove_column :users, :paranoid_verification_attempt
end
end
68 changes: 68 additions & 0 deletions test/test_paranoid_verification.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ class TestPasswordVerifiable < ActiveSupport::TestCase
end

test "generate code" do
user = User.new
user.generate_paranoid_code
assert_equal(0, user.paranoid_verification_attempt)
user.verify_code('wrong')
assert_equal(1, user.paranoid_verification_attempt)
user.generate_paranoid_code
assert_equal(0, user.paranoid_verification_attempt)
end

test "generate code must reset attempt counter" do
user = User.new
user.generate_paranoid_code
# default generator generates 5 char string
Expand Down Expand Up @@ -54,4 +64,62 @@ class TestPasswordVerifiable < ActiveSupport::TestCase
user.verify_code('wrong')
assert_equal(nil, user.paranoid_verified_at)
end

test 'when code not match upon verification code too many attempts should generate new code' do
original_regenerate = Devise.paranoid_code_regenerate_after_attempt
Devise.paranoid_code_regenerate_after_attempt = 2

user = User.create(paranoid_verification_code: 'abcde')
user.verify_code('wrong')
assert_equal 'abcde', user.paranoid_verification_code
user.verify_code('wrong-again')
assert_not_equal 'abcde', user.paranoid_verification_code

Devise.paranoid_code_regenerate_after_attempt = original_regenerate
end

test 'upon generating new code due to too many attempts reset attempt counter' do
original_regenerate = Devise.paranoid_code_regenerate_after_attempt
Devise.paranoid_code_regenerate_after_attempt = 3

user = User.create(paranoid_verification_code: 'abcde')
user.verify_code('wrong')
assert_equal 1, user.paranoid_verification_attempt
user.verify_code('wrong-again')
assert_equal 2, user.paranoid_verification_attempt
user.verify_code('WRONG!')
assert_equal 0, user.paranoid_verification_attempt

Devise.paranoid_code_regenerate_after_attempt = original_regenerate
end


test 'by default paranoid code regenerate should have 10 attempts' do
user = User.new(paranoid_verification_code: 'abcde')
assert_equal 10, user.paranoid_attempts_remaining
end

test 'paranoid_attempts_remaining should re-callculate how many attemps remains after each wrong attempt' do
original_regenerate = Devise.paranoid_code_regenerate_after_attempt
Devise.paranoid_code_regenerate_after_attempt = 2

user = User.create(paranoid_verification_code: 'abcde')
assert_equal 2, user.paranoid_attempts_remaining

user.verify_code('WRONG!')
assert_equal 1, user.paranoid_attempts_remaining

Devise.paranoid_code_regenerate_after_attempt = original_regenerate
end

test 'when code not match upon verification code too many times, reset paranoid_attempts_remaining' do
original_regenerate = Devise.paranoid_code_regenerate_after_attempt
Devise.paranoid_code_regenerate_after_attempt = 1

user = User.create(paranoid_verification_code: 'abcde')
user.verify_code('wrong') # at this point code was regenerated
assert_equal Devise.paranoid_code_regenerate_after_attempt, user.paranoid_attempts_remaining

Devise.paranoid_code_regenerate_after_attempt = original_regenerate
end
end