devise 1.1.9 → 1.2.rc

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of devise might be problematic. Click here for more details.

Files changed (121) hide show
  1. data/CHANGELOG.rdoc +34 -26
  2. data/README.rdoc +134 -100
  3. data/app/controllers/devise/confirmations_controller.rb +1 -1
  4. data/app/controllers/devise/omniauth_callbacks_controller.rb +26 -0
  5. data/app/controllers/devise/passwords_controller.rb +1 -1
  6. data/app/controllers/devise/registrations_controller.rb +59 -6
  7. data/app/controllers/devise/sessions_controller.rb +3 -2
  8. data/app/controllers/devise/unlocks_controller.rb +1 -1
  9. data/app/helpers/devise_helper.rb +4 -2
  10. data/app/mailers/devise/mailer.rb +27 -10
  11. data/app/views/devise/confirmations/new.html.erb +1 -1
  12. data/app/views/devise/passwords/edit.html.erb +2 -2
  13. data/app/views/devise/passwords/new.html.erb +1 -1
  14. data/app/views/devise/registrations/edit.html.erb +1 -1
  15. data/app/views/devise/registrations/new.html.erb +1 -1
  16. data/app/views/devise/sessions/new.html.erb +1 -1
  17. data/app/views/devise/shared/_links.erb +6 -0
  18. data/app/views/devise/unlocks/new.html.erb +1 -1
  19. data/config/locales/en.yml +9 -2
  20. data/lib/devise.rb +116 -58
  21. data/lib/devise/controllers/helpers.rb +103 -107
  22. data/lib/devise/controllers/internal_helpers.rb +23 -7
  23. data/lib/devise/controllers/scoped_views.rb +4 -6
  24. data/lib/devise/controllers/url_helpers.rb +3 -5
  25. data/lib/devise/encryptors/base.rb +1 -1
  26. data/lib/devise/encryptors/restful_authentication_sha1.rb +4 -4
  27. data/lib/devise/failure_app.rb +29 -21
  28. data/lib/devise/hooks/forgetable.rb +2 -1
  29. data/lib/devise/hooks/rememberable.rb +11 -9
  30. data/lib/devise/mapping.rb +12 -5
  31. data/lib/devise/models.rb +0 -14
  32. data/lib/devise/models/authenticatable.rb +40 -30
  33. data/lib/devise/models/confirmable.rb +11 -15
  34. data/lib/devise/models/database_authenticatable.rb +23 -35
  35. data/lib/devise/models/encryptable.rb +65 -0
  36. data/lib/devise/models/lockable.rb +8 -7
  37. data/lib/devise/models/omniauthable.rb +23 -0
  38. data/lib/devise/models/recoverable.rb +5 -3
  39. data/lib/devise/models/registerable.rb +13 -0
  40. data/lib/devise/models/rememberable.rb +38 -30
  41. data/lib/devise/models/timeoutable.rb +20 -3
  42. data/lib/devise/models/token_authenticatable.rb +19 -7
  43. data/lib/devise/models/validatable.rb +16 -4
  44. data/lib/devise/modules.rb +15 -8
  45. data/lib/devise/omniauth.rb +47 -0
  46. data/lib/devise/omniauth/config.rb +30 -0
  47. data/lib/devise/omniauth/test_helpers.rb +57 -0
  48. data/lib/devise/omniauth/url_helpers.rb +29 -0
  49. data/lib/devise/orm/active_record.rb +2 -0
  50. data/lib/devise/orm/mongoid.rb +4 -2
  51. data/lib/devise/rails.rb +26 -46
  52. data/lib/devise/rails/routes.rb +64 -20
  53. data/lib/devise/rails/warden_compat.rb +18 -20
  54. data/lib/devise/schema.rb +13 -14
  55. data/lib/devise/strategies/authenticatable.rb +33 -7
  56. data/lib/devise/strategies/database_authenticatable.rb +1 -1
  57. data/lib/devise/strategies/rememberable.rb +1 -1
  58. data/lib/devise/strategies/token_authenticatable.rb +6 -2
  59. data/lib/devise/test_helpers.rb +11 -1
  60. data/lib/devise/version.rb +1 -1
  61. data/lib/generators/active_record/templates/migration.rb +1 -0
  62. data/lib/generators/devise/orm_helpers.rb +3 -2
  63. data/lib/generators/templates/devise.rb +70 -39
  64. data/test/controllers/helpers_test.rb +43 -67
  65. data/test/controllers/internal_helpers_test.rb +29 -8
  66. data/test/controllers/url_helpers_test.rb +2 -1
  67. data/test/failure_app_test.rb +56 -21
  68. data/test/generators/generators_test_helper.rb +4 -0
  69. data/test/generators/install_generator_test.rb +14 -0
  70. data/test/generators/views_generator_test.rb +37 -0
  71. data/test/integration/authenticatable_test.rb +147 -62
  72. data/test/integration/database_authenticatable_test.rb +22 -0
  73. data/test/integration/http_authenticatable_test.rb +12 -2
  74. data/test/integration/omniauthable_test.rb +107 -0
  75. data/test/integration/recoverable_test.rb +39 -20
  76. data/test/integration/registerable_test.rb +30 -4
  77. data/test/integration/rememberable_test.rb +57 -34
  78. data/test/integration/timeoutable_test.rb +10 -1
  79. data/test/integration/token_authenticatable_test.rb +12 -17
  80. data/test/mailers/confirmation_instructions_test.rb +4 -0
  81. data/test/mailers/reset_password_instructions_test.rb +4 -0
  82. data/test/mailers/unlock_instructions_test.rb +4 -0
  83. data/test/mapping_test.rb +37 -3
  84. data/test/models/confirmable_test.rb +3 -3
  85. data/test/models/database_authenticatable_test.rb +14 -71
  86. data/test/models/encryptable_test.rb +65 -0
  87. data/test/models/lockable_test.rb +17 -1
  88. data/test/models/recoverable_test.rb +17 -0
  89. data/test/models/rememberable_test.rb +186 -125
  90. data/test/models/token_authenticatable_test.rb +1 -13
  91. data/test/models_test.rb +5 -5
  92. data/test/omniauth/url_helpers_test.rb +47 -0
  93. data/test/rails_app/app/active_record/admin.rb +4 -1
  94. data/test/rails_app/app/active_record/user.rb +5 -4
  95. data/test/rails_app/app/controllers/{sessions_controller.rb → admins/sessions_controller.rb} +1 -1
  96. data/test/rails_app/app/controllers/home_controller.rb +9 -0
  97. data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +7 -0
  98. data/test/rails_app/app/mongoid/admin.rb +4 -1
  99. data/test/rails_app/app/mongoid/shim.rb +16 -3
  100. data/test/rails_app/app/mongoid/user.rb +5 -5
  101. data/test/rails_app/config/initializers/devise.rb +52 -28
  102. data/test/rails_app/config/routes.rb +14 -6
  103. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +21 -17
  104. data/test/rails_app/db/schema.rb +17 -51
  105. data/test/rails_app/lib/shared_admin.rb +9 -0
  106. data/test/rails_app/lib/shared_user.rb +23 -0
  107. data/test/routes_test.rb +42 -9
  108. data/test/support/integration.rb +3 -3
  109. data/test/support/webrat/integrations/rails.rb +7 -0
  110. data/test/test_helper.rb +2 -0
  111. data/test/test_helpers_test.rb +29 -0
  112. metadata +60 -30
  113. data/Gemfile +0 -27
  114. data/Gemfile.lock +0 -115
  115. data/Rakefile +0 -55
  116. data/TODO +0 -3
  117. data/lib/devise/encryptors/bcrypt.rb +0 -19
  118. data/lib/generators/devise_install_generator.rb +0 -4
  119. data/lib/generators/devise_views_generator.rb +0 -4
  120. data/test/indifferent_hash.rb +0 -33
  121. data/test/support/test_silencer.rb +0 -5
@@ -5,7 +5,8 @@
5
5
  Warden::Manager.before_logout do |record, warden, options|
6
6
  if record.respond_to?(:forget_me!)
7
7
  record.forget_me! unless record.frozen?
8
- cookie_options = record.cookie_domain? ? { :domain => record.cookie_domain } : {}
8
+ cookie_options = Rails.configuration.session_options.slice(:path, :domain, :secure)
9
+ cookie_options.merge!(record.cookie_options)
9
10
  warden.cookies.delete("remember_#{options[:scope]}_token", cookie_options)
10
11
  end
11
12
  end
@@ -10,20 +10,22 @@ module Devise
10
10
 
11
11
  if succeeded? && resource.respond_to?(:remember_me!) && remember_me?
12
12
  resource.remember_me!(extend_remember_period?)
13
-
14
- configuration = {
15
- :value => resource.class.serialize_into_cookie(resource),
16
- :expires => resource.remember_expires_at,
17
- :path => "/"
18
- }
19
-
20
- configuration[:domain] = resource.cookie_domain if resource.cookie_domain?
21
- cookies.signed["remember_#{scope}_token"] = configuration
13
+ cookies.signed["remember_#{scope}_token"] = cookie_values(resource)
22
14
  end
23
15
  end
24
16
 
25
17
  protected
26
18
 
19
+ def cookie_values(resource)
20
+ options = Rails.configuration.session_options.slice(:path, :domain, :secure)
21
+ options.merge!(resource.cookie_options)
22
+ options.merge!(
23
+ :value => resource.class.serialize_into_cookie(resource),
24
+ :expires => resource.remember_expires_at
25
+ )
26
+ options
27
+ end
28
+
27
29
  def succeeded?
28
30
  @result == :success
29
31
  end
@@ -22,7 +22,7 @@ module Devise
22
22
  # # is the modules included in the class
23
23
  #
24
24
  class Mapping #:nodoc:
25
- attr_reader :singular, :plural, :path, :controllers, :path_names, :class_name
25
+ attr_reader :singular, :scoped_path, :path, :controllers, :path_names, :class_name, :sign_out_via
26
26
  alias :name :singular
27
27
 
28
28
  # Receives an object and find a scope for it. If a scope cannot be found,
@@ -37,12 +37,17 @@ module Devise
37
37
  Devise.mappings.each_value { |m| return m.name if duck.is_a?(m.to) }
38
38
  end
39
39
 
40
- raise "Could not find a valid mapping for #{duck}"
40
+ raise "Could not find a valid mapping for #{duck.inspect}"
41
+ end
42
+
43
+ def self.find_by_path!(path, path_type=:fullpath)
44
+ Devise.mappings.each_value { |m| return m if path.include?(m.send(path_type)) }
45
+ raise "Could not find a valid mapping for path #{path.inspect}"
41
46
  end
42
47
 
43
48
  def initialize(name, options) #:nodoc:
44
- @plural = (options[:as] ? "#{options[:as]}_#{name}" : name).to_sym
45
- @singular = (options[:singular] || @plural.to_s.singularize).to_sym
49
+ @scoped_path = options[:as] ? "#{options[:as]}/#{name}" : name.to_s
50
+ @singular = (options[:singular] || @scoped_path.tr('/', '_').singularize).to_sym
46
51
 
47
52
  @class_name = (options[:class_name] || name.to_s.classify).to_s
48
53
  @ref = ActiveSupport::Dependencies.ref(@class_name)
@@ -57,6 +62,8 @@ module Devise
57
62
  @path_names = Hash.new { |h,k| h[k] = k.to_s }
58
63
  @path_names.merge!(:registration => "")
59
64
  @path_names.merge!(options[:path_names] || {})
65
+
66
+ @sign_out_via = options[:sign_out_via] || Devise.sign_out_via
60
67
  end
61
68
 
62
69
  # Return modules for the mapping.
@@ -82,7 +89,7 @@ module Devise
82
89
  end
83
90
 
84
91
  def fullpath
85
- "#{@path_prefix}/#{@path}".squeeze("/")
92
+ "/#{@path_prefix}/#{@path}".squeeze("/")
86
93
  end
87
94
 
88
95
  # Create magic predicates for verifying what module is activated by this map.
@@ -47,20 +47,6 @@ module Devise
47
47
  def devise(*modules)
48
48
  include Devise::Models::Authenticatable
49
49
  options = modules.extract_options!
50
-
51
- if modules.delete(:authenticatable)
52
- ActiveSupport::Deprecation.warn ":authenticatable as module is deprecated. Please give :database_authenticatable instead.", caller
53
- modules << :database_authenticatable
54
- end
55
-
56
- if modules.delete(:activatable)
57
- ActiveSupport::Deprecation.warn ":activatable as module is deprecated. It's included in your model by default.", caller
58
- end
59
-
60
- if modules.delete(:http_authenticatable)
61
- ActiveSupport::Deprecation.warn ":http_authenticatable as module is deprecated and is on by default. Revert by setting :http_authenticatable => false.", caller
62
- end
63
-
64
50
  self.devise_modules += Devise::ALL & modules.map(&:to_sym).uniq
65
51
 
66
52
  devise_modules_hook! do
@@ -4,18 +4,25 @@ module Devise
4
4
  module Models
5
5
  # Authenticable module. Holds common settings for authentication.
6
6
  #
7
- # == Configuration:
7
+ # == Options
8
8
  #
9
- # You can overwrite configuration values by setting in globally in Devise,
10
- # using devise method or overwriting the respective instance method.
9
+ # Authenticatable adds the following options to devise_for:
11
10
  #
12
- # authentication_keys: parameters used for authentication. By default [:email].
11
+ # * +authentication_keys+: parameters used for authentication. By default [:email].
13
12
  #
14
- # http_authenticatable: if this model allows http authentication. By default true.
15
- # It also accepts an array specifying the strategies that should allow http.
13
+ # * +request_keys+: parameters from the request object used for authentication.
14
+ # By specifying a symbol (which should be a request method), it will automatically be
15
+ # passed to find_for_authentication method and considered in your model lookup.
16
16
  #
17
- # params_authenticatable: if this model allows authentication through request params. By default true.
18
- # It also accepts an array specifying the strategies that should allow params authentication.
17
+ # For instance, if you set :request_keys to [:subdomain], :subdomain will be considered
18
+ # as key on authentication. This can also be a hash where the value is a boolean expliciting
19
+ # if the value is required or not.
20
+ #
21
+ # * +http_authenticatable+: if this model allows http authentication. By default true.
22
+ # It also accepts an array specifying the strategies that should allow http.
23
+ #
24
+ # * +params_authenticatable+: if this model allows authentication through request params. By default true.
25
+ # It also accepts an array specifying the strategies that should allow params authentication.
19
26
  #
20
27
  # == Active?
21
28
  #
@@ -66,8 +73,11 @@ module Devise
66
73
  :inactive
67
74
  end
68
75
 
76
+ def authenticatable_salt
77
+ end
78
+
69
79
  module ClassMethods
70
- Devise::Models.config(self, :authentication_keys, :http_authenticatable, :params_authenticatable)
80
+ Devise::Models.config(self, :authentication_keys, :request_keys, :case_insensitive_keys, :http_authenticatable, :params_authenticatable)
71
81
 
72
82
  def params_authenticatable?(strategy)
73
83
  params_authenticatable.is_a?(Array) ?
@@ -90,44 +100,44 @@ module Devise
90
100
  # end
91
101
  #
92
102
  def find_for_authentication(conditions)
93
- filter_auth_params(conditions)
94
- find(:first, :conditions => conditions)
103
+ case_insensitive_keys.each { |k| conditions[k].try(:downcase!) }
104
+ to_adapter.find_first(conditions)
95
105
  end
96
106
 
97
107
  # Find an initialize a record setting an error if it can't be found.
98
108
  def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
99
- if value.present?
100
- conditions = { attribute => value }
101
- record = find(:first, :conditions => conditions)
102
- end
109
+ find_or_initialize_with_errors([attribute], { attribute => value }, error)
110
+ end
111
+
112
+ # Find an initialize a group of attributes based on a list of required attributes.
113
+ def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
114
+ case_insensitive_keys.each { |k| attributes[k].try(:downcase!) }
115
+
116
+ attributes = attributes.slice(*required_attributes)
117
+ attributes.delete_if { |key, value| value.blank? }
103
118
 
119
+ if attributes.size == required_attributes.size
120
+ record = to_adapter.find_first(attributes)
121
+ end
122
+
104
123
  unless record
105
124
  record = new
106
- if value.present?
107
- record.send(:"#{attribute}=", value)
108
- else
109
- error = :blank
125
+
126
+ required_attributes.each do |key|
127
+ value = attributes[key]
128
+ record.send("#{key}=", value)
129
+ record.errors.add(key, value.present? ? error : :blank)
110
130
  end
111
- record.errors.add(attribute, error)
112
131
  end
113
132
 
114
133
  record
115
134
  end
116
135
 
117
- protected
118
-
119
- # Force keys to be string to avoid injection on mongoid related database.
120
- def filter_auth_params(conditions)
121
- conditions.each do |k, v|
122
- conditions[k] = v.to_s
123
- end
124
- end
125
-
126
136
  # Generate a token by looping and ensuring does not already exist.
127
137
  def generate_token(column)
128
138
  loop do
129
139
  token = Devise.friendly_token
130
- break token unless find(:first, :conditions => { column => token })
140
+ break token unless to_adapter.find_first({ column => token })
131
141
  end
132
142
  end
133
143
  end
@@ -3,28 +3,24 @@ module Devise
3
3
  # Confirmable is responsible to verify if an account is already confirmed to
4
4
  # sign in, and to send emails with confirmation instructions.
5
5
  # Confirmation instructions are sent to the user email after creating a
6
- # record, after updating it's email and also when manually requested by
7
- # a new confirmation instruction request.
8
- # Whenever the user update it's email, his account is automatically unconfirmed,
9
- # it means it won't be able to sign in again without confirming the account
10
- # again through the email that was sent.
6
+ # record and when manually requested by a new confirmation instruction request.
11
7
  #
12
- # Configuration:
8
+ # == Options
13
9
  #
14
- # confirm_within: the time you want the user will have to confirm it's account
15
- # without blocking his access. When confirm_within is zero, the
16
- # user won't be able to sign in without confirming. You can
17
- # use this to let your user access some features of your
18
- # application without confirming the account, but blocking it
19
- # after a certain period (ie 7 days). By default confirm_within is
20
- # zero, it means users always have to confirm to sign in.
10
+ # Confirmable adds the following options to devise_for:
21
11
  #
22
- # Examples:
12
+ # * +confirm_within+: the time you want to allow the user to access his account
13
+ # before confirming it. After this period, the user access is denied. You can
14
+ # use this to let your user access some features of your application without
15
+ # confirming the account, but blocking it after a certain period (ie 7 days).
16
+ # By default confirm_within is zero, it means users always have to confirm to sign in.
17
+ #
18
+ # == Examples
23
19
  #
24
20
  # User.find(1).confirm! # returns true unless it's already confirmed
25
21
  # User.find(1).confirmed? # true/false
26
22
  # User.find(1).send_confirmation_instructions # manually send instructions
27
- # User.find(1).resend_confirmation! # generates a new token and resent it
23
+ #
28
24
  module Confirmable
29
25
  extend ActiveSupport::Concern
30
26
 
@@ -1,25 +1,18 @@
1
1
  require 'devise/strategies/database_authenticatable'
2
+ require 'bcrypt'
2
3
 
3
4
  module Devise
4
5
  module Models
5
6
  # Authenticable Module, responsible for encrypting password and validating
6
7
  # authenticity of a user while signing in.
7
8
  #
8
- # Configuration:
9
+ # == Options
9
10
  #
10
- # You can overwrite configuration values by setting in globally in Devise,
11
- # using devise method or overwriting the respective instance method.
11
+ # DatabaseAuthenticable adds the following options to devise_for:
12
12
  #
13
- # pepper: encryption key used for creating encrypted password. Each time
14
- # password changes, it's gonna be encrypted again, and this key
15
- # is added to the password and salt to create a secure hash.
16
- # Always use `rake secret' to generate a new key.
13
+ # * +stretches+: the cost given to bcrypt.
17
14
  #
18
- # stretches: defines how many times the password will be encrypted.
19
- #
20
- # encryptor: the encryptor going to be used. By default :sha1.
21
- #
22
- # Examples:
15
+ # == Examples
23
16
  #
24
17
  # User.find(1).valid_password?('password123') # returns true/false
25
18
  #
@@ -29,22 +22,18 @@ module Devise
29
22
  included do
30
23
  attr_reader :password, :current_password
31
24
  attr_accessor :password_confirmation
25
+ before_save :downcase_keys
32
26
  end
33
27
 
34
- # Regenerates password salt and encrypted password each time password is set,
35
- # and then trigger any "after_changed_password"-callbacks.
28
+ # Generates password encryption based on the given value.
36
29
  def password=(new_password)
37
30
  @password = new_password
38
-
39
- if @password.present?
40
- self.password_salt = self.class.password_salt
41
- self.encrypted_password = password_digest(@password)
42
- end
31
+ self.encrypted_password = password_digest(@password) if @password.present?
43
32
  end
44
33
 
45
34
  # Verifies whether an incoming_password (ie from sign in) is the user password.
46
- def valid_password?(incoming_password)
47
- Devise.secure_compare(password_digest(incoming_password), self.encrypted_password)
35
+ def valid_password?(password)
36
+ ::BCrypt::Password.new(self.encrypted_password) == "#{password}#{self.class.pepper}"
48
37
  end
49
38
 
50
39
  # Set password and password confirmation to nil
@@ -78,26 +67,25 @@ module Devise
78
67
  def after_database_authentication
79
68
  end
80
69
 
70
+ # A reliable way to expose the salt regardless of the implementation.
71
+ def authenticatable_salt
72
+ self.encrypted_password[0,29] if self.encrypted_password
73
+ end
74
+
81
75
  protected
82
76
 
83
- # Digests the password using the configured encryptor.
77
+ # Downcase case-insensitive keys
78
+ def downcase_keys
79
+ self.class.case_insensitive_keys.each { |k| self[k].try(:downcase!) }
80
+ end
81
+
82
+ # Digests the password using bcrypt.
84
83
  def password_digest(password)
85
- if self.password_salt.present?
86
- self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
87
- end
84
+ ::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
88
85
  end
89
86
 
90
87
  module ClassMethods
91
- Devise::Models.config(self, :pepper, :stretches, :encryptor)
92
-
93
- # Returns the class for the configured encryptor.
94
- def encryptor_class
95
- @encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
96
- end
97
-
98
- def password_salt
99
- self.encryptor_class.salt(self.stretches)
100
- end
88
+ Devise::Models.config(self, :pepper, :stretches)
101
89
 
102
90
  # We assume this method already gets the sanitized values from the
103
91
  # DatabaseAuthenticatable strategy. If you are using this method on
@@ -0,0 +1,65 @@
1
+ require 'devise/strategies/database_authenticatable'
2
+
3
+ module Devise
4
+ module Models
5
+ # Encryptable Module adds support to several encryptors.
6
+ #
7
+ # == Options
8
+ #
9
+ # Encryptable adds the following options to devise_for:
10
+ #
11
+ # * +pepper+: a random string used to provide a more secure hash.
12
+ #
13
+ # * +encryptor+: the encryptor going to be used. By default is nil.
14
+ #
15
+ # == Examples
16
+ #
17
+ # User.find(1).valid_password?('password123') # returns true/false
18
+ #
19
+ module Encryptable
20
+ extend ActiveSupport::Concern
21
+
22
+ included do
23
+ attr_reader :password, :current_password
24
+ attr_accessor :password_confirmation
25
+ end
26
+
27
+ # Generates password salt.
28
+ def password=(new_password)
29
+ self.password_salt = self.class.password_salt if new_password.present?
30
+ super
31
+ end
32
+
33
+ def authenticatable_salt
34
+ self.password_salt
35
+ end
36
+
37
+ # Verifies whether an incoming_password (ie from sign in) is the user password.
38
+ def valid_password?(incoming_password)
39
+ password_digest(incoming_password) == self.encrypted_password
40
+ end
41
+
42
+ protected
43
+
44
+ # Digests the password using the configured encryptor.
45
+ def password_digest(password)
46
+ if self.password_salt.present?
47
+ self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
48
+ end
49
+ end
50
+
51
+ module ClassMethods
52
+ Devise::Models.config(self, :encryptor)
53
+
54
+ # Returns the class for the configured encryptor.
55
+ def encryptor_class
56
+ @encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
57
+ end
58
+
59
+ def password_salt
60
+ self.encryptor_class.salt(self.stretches)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -7,13 +7,14 @@ module Devise
7
7
  # will unlock the user automatically after some configured time (ie 2.hours).
8
8
  # It's also possible to setup lockable to use both email and time strategies.
9
9
  #
10
- # Configuration:
10
+ # == Options
11
11
  #
12
- # maximum_attempts: how many attempts should be accepted before blocking the user.
13
- # lock_strategy: lock the user account by :failed_attempts or :none.
14
- # unlock_strategy: unlock the user account by :time, :email, :both or :none.
15
- # unlock_in: the time you want to lock the user after to lock happens. Only
16
- # available when unlock_strategy is :time or :both.
12
+ # Lockable adds the following options to devise_for:
13
+ #
14
+ # * +maximum_attempts+: how many attempts should be accepted before blocking the user.
15
+ # * +lock_strategy+: lock the user account by :failed_attempts or :none.
16
+ # * +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
17
+ # * +unlock_in+: the time you want to lock the user after to lock happens. Only available when unlock_strategy is :time or :both.
17
18
  #
18
19
  module Lockable
19
20
  extend ActiveSupport::Concern
@@ -131,7 +132,7 @@ module Devise
131
132
  # with an email not found error.
132
133
  # Options must contain the user email
133
134
  def send_unlock_instructions(attributes={})
134
- lockable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
135
+ lockable = find_or_initialize_with_errors(authentication_keys, attributes, :not_found)
135
136
  lockable.resend_unlock_token if lockable.persisted?
136
137
  lockable
137
138
  end