diff --git a/activerecord/lib/active_record/secure_token.rb b/activerecord/lib/active_record/secure_token.rb index 23d4292cbb..b1a13fe673 100644 --- a/activerecord/lib/active_record/secure_token.rb +++ b/activerecord/lib/active_record/secure_token.rb @@ -13,35 +13,25 @@ module ActiveRecord # # user = User.new # user.save - # user.token # => "44539a6a59835a4ee9d7b112" - # user.auth_token # => "e2426a93718d1817a43abbaa" + # user.token # => "4kUgL2pdQMSCQtjE" + # user.auth_token # => "77TMHrHJFvFDwodq8w7Ev2m7" # user.regenerate_token # => true # user.regenerate_auth_token # => true # - # SecureRandom is used to generate the 24-character unique token, so collisions are highly unlikely. - # We'll check to see if the generated token has been used already using #exists?, and retry up to 10 - # times to find another unused token. After that a RuntimeError is raised if the problem persists. + # SecureRandom::base58 is used to generate the 24-character unique token, so collisions are highly unlikely. # # Note that it's still possible to generate a race condition in the database in the same way that # validates_presence_of can. You're encouraged to add a unique index in the database to deal with # this even more unlikely scenario. def has_secure_token(attribute = :token) # Load securerandom only when has_secure_key is used. - require 'securerandom' - define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token(attribute) } - before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token(attribute)) } + require 'active_support/core_ext/securerandom' + define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token } + before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token) } end - def generate_unique_secure_token(attribute) - 10.times do |i| - SecureRandom.hex(12).tap do |token| - if exists?(attribute => token) - raise "Couldn't generate a unique token in 10 attempts!" if i == 9 - else - return token - end - end - end + def generate_unique_secure_token + SecureRandom.base58(24) end end end diff --git a/activerecord/test/cases/secure_token_test.rb b/activerecord/test/cases/secure_token_test.rb index dc12b528dc..3f7455d12d 100644 --- a/activerecord/test/cases/secure_token_test.rb +++ b/activerecord/test/cases/secure_token_test.rb @@ -22,18 +22,4 @@ class SecureTokenTest < ActiveRecord::TestCase assert_not_equal @user.token, old_token assert_not_equal @user.auth_token, old_auth_token end - - def test_raise_after_ten_unsuccessful_attempts_to_generate_a_unique_token - User.stubs(:exists?).returns(*Array.new(10, true)) - assert_raises(RuntimeError) do - @user.save - end - end - - def test_return_unique_token_after_nine_unsuccessful_attempts - User.stubs(:exists?).returns(*Array.new(10) { |i| i == 9 ? false : true }) - @user.save - assert_not_nil @user.token - assert_not_nil @user.auth_token - end end