devise-edge 1.2.rc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. data/CHANGELOG.rdoc +500 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +335 -0
  4. data/app/controllers/devise/confirmations_controller.rb +33 -0
  5. data/app/controllers/devise/oauth_callbacks_controller.rb +4 -0
  6. data/app/controllers/devise/passwords_controller.rb +41 -0
  7. data/app/controllers/devise/registrations_controller.rb +75 -0
  8. data/app/controllers/devise/sessions_controller.rb +23 -0
  9. data/app/controllers/devise/unlocks_controller.rb +34 -0
  10. data/app/helpers/devise_helper.rb +17 -0
  11. data/app/mailers/devise/mailer.rb +88 -0
  12. data/app/views/devise/confirmations/new.html.erb +12 -0
  13. data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
  14. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  15. data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
  16. data/app/views/devise/passwords/edit.html.erb +16 -0
  17. data/app/views/devise/passwords/new.html.erb +12 -0
  18. data/app/views/devise/registrations/edit.html.erb +25 -0
  19. data/app/views/devise/registrations/new.html.erb +18 -0
  20. data/app/views/devise/sessions/new.html.erb +17 -0
  21. data/app/views/devise/shared/_links.erb +25 -0
  22. data/app/views/devise/unlocks/new.html.erb +12 -0
  23. data/config/locales/en.yml +42 -0
  24. data/lib/devise.rb +371 -0
  25. data/lib/devise/controllers/helpers.rb +261 -0
  26. data/lib/devise/controllers/internal_helpers.rb +113 -0
  27. data/lib/devise/controllers/scoped_views.rb +33 -0
  28. data/lib/devise/controllers/url_helpers.rb +39 -0
  29. data/lib/devise/encryptors/authlogic_sha512.rb +19 -0
  30. data/lib/devise/encryptors/base.rb +20 -0
  31. data/lib/devise/encryptors/clearance_sha1.rb +17 -0
  32. data/lib/devise/encryptors/restful_authentication_sha1.rb +22 -0
  33. data/lib/devise/encryptors/sha1.rb +25 -0
  34. data/lib/devise/encryptors/sha512.rb +25 -0
  35. data/lib/devise/failure_app.rb +126 -0
  36. data/lib/devise/hooks/activatable.rb +11 -0
  37. data/lib/devise/hooks/forgetable.rb +12 -0
  38. data/lib/devise/hooks/rememberable.rb +45 -0
  39. data/lib/devise/hooks/timeoutable.rb +22 -0
  40. data/lib/devise/hooks/trackable.rb +9 -0
  41. data/lib/devise/mapping.rb +105 -0
  42. data/lib/devise/models.rb +66 -0
  43. data/lib/devise/models/authenticatable.rb +143 -0
  44. data/lib/devise/models/confirmable.rb +160 -0
  45. data/lib/devise/models/database_authenticatable.rb +94 -0
  46. data/lib/devise/models/encryptable.rb +65 -0
  47. data/lib/devise/models/lockable.rb +168 -0
  48. data/lib/devise/models/oauthable.rb +49 -0
  49. data/lib/devise/models/recoverable.rb +83 -0
  50. data/lib/devise/models/registerable.rb +21 -0
  51. data/lib/devise/models/rememberable.rb +122 -0
  52. data/lib/devise/models/timeoutable.rb +33 -0
  53. data/lib/devise/models/token_authenticatable.rb +72 -0
  54. data/lib/devise/models/trackable.rb +30 -0
  55. data/lib/devise/models/validatable.rb +60 -0
  56. data/lib/devise/modules.rb +30 -0
  57. data/lib/devise/oauth.rb +41 -0
  58. data/lib/devise/oauth/config.rb +33 -0
  59. data/lib/devise/oauth/helpers.rb +18 -0
  60. data/lib/devise/oauth/internal_helpers.rb +182 -0
  61. data/lib/devise/oauth/test_helpers.rb +29 -0
  62. data/lib/devise/oauth/url_helpers.rb +35 -0
  63. data/lib/devise/orm/active_record.rb +36 -0
  64. data/lib/devise/orm/mongo_mapper.rb +46 -0
  65. data/lib/devise/orm/mongoid.rb +29 -0
  66. data/lib/devise/path_checker.rb +18 -0
  67. data/lib/devise/rails.rb +67 -0
  68. data/lib/devise/rails/routes.rb +260 -0
  69. data/lib/devise/rails/warden_compat.rb +42 -0
  70. data/lib/devise/schema.rb +96 -0
  71. data/lib/devise/strategies/authenticatable.rb +150 -0
  72. data/lib/devise/strategies/base.rb +15 -0
  73. data/lib/devise/strategies/database_authenticatable.rb +21 -0
  74. data/lib/devise/strategies/rememberable.rb +51 -0
  75. data/lib/devise/strategies/token_authenticatable.rb +53 -0
  76. data/lib/devise/test_helpers.rb +100 -0
  77. data/lib/devise/version.rb +3 -0
  78. data/lib/generators/active_record/devise_generator.rb +28 -0
  79. data/lib/generators/active_record/templates/migration.rb +30 -0
  80. data/lib/generators/devise/devise_generator.rb +17 -0
  81. data/lib/generators/devise/install_generator.rb +24 -0
  82. data/lib/generators/devise/orm_helpers.rb +24 -0
  83. data/lib/generators/devise/views_generator.rb +63 -0
  84. data/lib/generators/mongoid/devise_generator.rb +17 -0
  85. data/lib/generators/templates/README +25 -0
  86. data/lib/generators/templates/devise.rb +168 -0
  87. data/test/controllers/helpers_test.rb +220 -0
  88. data/test/controllers/internal_helpers_test.rb +56 -0
  89. data/test/controllers/url_helpers_test.rb +59 -0
  90. data/test/devise_test.rb +65 -0
  91. data/test/encryptors_test.rb +30 -0
  92. data/test/failure_app_test.rb +148 -0
  93. data/test/integration/authenticatable_test.rb +424 -0
  94. data/test/integration/confirmable_test.rb +104 -0
  95. data/test/integration/database_authenticatable_test.rb +38 -0
  96. data/test/integration/http_authenticatable_test.rb +64 -0
  97. data/test/integration/lockable_test.rb +109 -0
  98. data/test/integration/oauthable_test.rb +258 -0
  99. data/test/integration/recoverable_test.rb +141 -0
  100. data/test/integration/registerable_test.rb +179 -0
  101. data/test/integration/rememberable_test.rb +179 -0
  102. data/test/integration/timeoutable_test.rb +80 -0
  103. data/test/integration/token_authenticatable_test.rb +99 -0
  104. data/test/integration/trackable_test.rb +64 -0
  105. data/test/mailers/confirmation_instructions_test.rb +84 -0
  106. data/test/mailers/reset_password_instructions_test.rb +72 -0
  107. data/test/mailers/unlock_instructions_test.rb +66 -0
  108. data/test/mapping_test.rb +95 -0
  109. data/test/models/confirmable_test.rb +221 -0
  110. data/test/models/database_authenticatable_test.rb +82 -0
  111. data/test/models/encryptable_test.rb +65 -0
  112. data/test/models/lockable_test.rb +204 -0
  113. data/test/models/oauthable_test.rb +21 -0
  114. data/test/models/recoverable_test.rb +155 -0
  115. data/test/models/rememberable_test.rb +271 -0
  116. data/test/models/timeoutable_test.rb +28 -0
  117. data/test/models/token_authenticatable_test.rb +37 -0
  118. data/test/models/trackable_test.rb +5 -0
  119. data/test/models/validatable_test.rb +99 -0
  120. data/test/models_test.rb +77 -0
  121. data/test/oauth/config_test.rb +44 -0
  122. data/test/oauth/url_helpers_test.rb +47 -0
  123. data/test/orm/active_record.rb +9 -0
  124. data/test/orm/mongoid.rb +10 -0
  125. data/test/rails_app/app/active_record/admin.rb +6 -0
  126. data/test/rails_app/app/active_record/shim.rb +2 -0
  127. data/test/rails_app/app/active_record/user.rb +8 -0
  128. data/test/rails_app/app/controllers/admins/sessions_controller.rb +6 -0
  129. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  130. data/test/rails_app/app/controllers/application_controller.rb +9 -0
  131. data/test/rails_app/app/controllers/home_controller.rb +12 -0
  132. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
  133. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
  134. data/test/rails_app/app/controllers/users_controller.rb +18 -0
  135. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  136. data/test/rails_app/app/mongoid/admin.rb +9 -0
  137. data/test/rails_app/app/mongoid/shim.rb +24 -0
  138. data/test/rails_app/app/mongoid/user.rb +10 -0
  139. data/test/rails_app/config/application.rb +35 -0
  140. data/test/rails_app/config/boot.rb +13 -0
  141. data/test/rails_app/config/environment.rb +5 -0
  142. data/test/rails_app/config/environments/development.rb +19 -0
  143. data/test/rails_app/config/environments/production.rb +33 -0
  144. data/test/rails_app/config/environments/test.rb +33 -0
  145. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  146. data/test/rails_app/config/initializers/devise.rb +172 -0
  147. data/test/rails_app/config/initializers/inflections.rb +2 -0
  148. data/test/rails_app/config/initializers/secret_token.rb +2 -0
  149. data/test/rails_app/config/routes.rb +54 -0
  150. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +31 -0
  151. data/test/rails_app/db/schema.rb +52 -0
  152. data/test/rails_app/lib/shared_admin.rb +9 -0
  153. data/test/rails_app/lib/shared_user.rb +48 -0
  154. data/test/routes_test.rb +189 -0
  155. data/test/support/assertions.rb +24 -0
  156. data/test/support/helpers.rb +60 -0
  157. data/test/support/integration.rb +88 -0
  158. data/test/support/webrat/integrations/rails.rb +24 -0
  159. data/test/test_helper.rb +23 -0
  160. data/test/test_helpers_test.rb +101 -0
  161. metadata +335 -0
@@ -0,0 +1,66 @@
1
+ module Devise
2
+ module Models
3
+ # Creates configuration values for Devise and for the given module.
4
+ #
5
+ # Devise::Models.config(Devise::Authenticable, :stretches, 10)
6
+ #
7
+ # The line above creates:
8
+ #
9
+ # 1) An accessor called Devise.stretches, which value is used by default;
10
+ #
11
+ # 2) Some class methods for your model Model.stretches and Model.stretches=
12
+ # which have higher priority than Devise.stretches;
13
+ #
14
+ # 3) And an instance method stretches.
15
+ #
16
+ # To add the class methods you need to have a module ClassMethods defined
17
+ # inside the given class.
18
+ #
19
+ def self.config(mod, *accessors) #:nodoc:
20
+ accessors.each do |accessor|
21
+ mod.class_eval <<-METHOD, __FILE__, __LINE__ + 1
22
+ def #{accessor}
23
+ if defined?(@#{accessor})
24
+ @#{accessor}
25
+ elsif superclass.respond_to?(:#{accessor})
26
+ superclass.#{accessor}
27
+ else
28
+ Devise.#{accessor}
29
+ end
30
+ end
31
+
32
+ def #{accessor}=(value)
33
+ @#{accessor} = value
34
+ end
35
+ METHOD
36
+ end
37
+ end
38
+
39
+ # Include the chosen devise modules in your model:
40
+ #
41
+ # devise :database_authenticatable, :confirmable, :recoverable
42
+ #
43
+ # You can also give any of the devise configuration values in form of a hash,
44
+ # with specific values for this model. Please check your Devise initializer
45
+ # for a complete description on those values.
46
+ #
47
+ def devise(*modules)
48
+ include Devise::Models::Authenticatable
49
+ options = modules.extract_options!
50
+ self.devise_modules += Devise::ALL & modules.map(&:to_sym).uniq
51
+
52
+ devise_modules_hook! do
53
+ devise_modules.each { |m| include Devise::Models.const_get(m.to_s.classify) }
54
+ options.each { |key, value| send(:"#{key}=", value) }
55
+ end
56
+ end
57
+
58
+ # The hook which is called inside devise. So your ORM can include devise
59
+ # compatibility stuff.
60
+ def devise_modules_hook!
61
+ yield
62
+ end
63
+ end
64
+ end
65
+
66
+ require 'devise/models/authenticatable'
@@ -0,0 +1,143 @@
1
+ require 'devise/hooks/activatable'
2
+
3
+ module Devise
4
+ module Models
5
+ # Authenticable module. Holds common settings for authentication.
6
+ #
7
+ # == Options
8
+ #
9
+ # Authenticatable adds the following options to devise_for:
10
+ #
11
+ # * +authentication_keys+: parameters used for authentication. By default [:email].
12
+ #
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
+ #
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.
26
+ #
27
+ # == Active?
28
+ #
29
+ # Before authenticating an user and in each request, Devise checks if your model is active by
30
+ # calling model.active?. This method is overwriten by other devise modules. For instance,
31
+ # :confirmable overwrites .active? to only return true if your model was confirmed.
32
+ #
33
+ # You overwrite this method yourself, but if you do, don't forget to call super:
34
+ #
35
+ # def active?
36
+ # super && special_condition_is_valid?
37
+ # end
38
+ #
39
+ # Whenever active? returns false, Devise asks the reason why your model is inactive using
40
+ # the inactive_message method. You can overwrite it as well:
41
+ #
42
+ # def inactive_message
43
+ # special_condition_is_valid? ? super : :special_condition_is_not_valid
44
+ # end
45
+ #
46
+ module Authenticatable
47
+ extend ActiveSupport::Concern
48
+
49
+ included do
50
+ class_attribute :devise_modules, :instance_writer => false
51
+ self.devise_modules ||= []
52
+ end
53
+
54
+ # Check if the current object is valid for authentication. This method and
55
+ # find_for_authentication are the methods used in a Warden::Strategy to check
56
+ # if a model should be signed in or not.
57
+ #
58
+ # However, you should not overwrite this method, you should overwrite active? and
59
+ # inactive_message instead.
60
+ def valid_for_authentication?
61
+ if active?
62
+ block_given? ? yield : true
63
+ else
64
+ inactive_message
65
+ end
66
+ end
67
+
68
+ def active?
69
+ true
70
+ end
71
+
72
+ def inactive_message
73
+ :inactive
74
+ end
75
+
76
+ def authenticatable_salt
77
+ end
78
+
79
+ module ClassMethods
80
+ Devise::Models.config(self, :authentication_keys, :request_keys, :http_authenticatable, :params_authenticatable)
81
+
82
+ def params_authenticatable?(strategy)
83
+ params_authenticatable.is_a?(Array) ?
84
+ params_authenticatable.include?(strategy) : params_authenticatable
85
+ end
86
+
87
+ def http_authenticatable?(strategy)
88
+ http_authenticatable.is_a?(Array) ?
89
+ http_authenticatable.include?(strategy) : http_authenticatable
90
+ end
91
+
92
+ # Find first record based on conditions given (ie by the sign in form).
93
+ # Overwrite to add customized conditions, create a join, or maybe use a
94
+ # namedscope to filter records while authenticating.
95
+ # Example:
96
+ #
97
+ # def self.find_for_authentication(conditions={})
98
+ # conditions[:active] = true
99
+ # super
100
+ # end
101
+ #
102
+ def find_for_authentication(conditions)
103
+ find(:first, :conditions => conditions)
104
+ end
105
+
106
+ # Find an initialize a record setting an error if it can't be found.
107
+ def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
108
+ find_or_initialize_with_errors([attribute], { attribute => value }, error)
109
+ end
110
+
111
+ # Find an initialize a group of attributes based on a list of required attributes.
112
+ def find_or_initialize_with_errors(required_attributes, attributes, error=:invalid) #:nodoc:
113
+ attributes = attributes.slice(*required_attributes)
114
+ attributes.delete_if { |key, value| value.blank? }
115
+
116
+ if attributes.size == required_attributes.size
117
+ record = find(:first, :conditions => attributes)
118
+ end
119
+
120
+ unless record
121
+ record = new
122
+
123
+ required_attributes.each do |key|
124
+ value = attributes[key]
125
+ record.send("#{key}=", value)
126
+ record.errors.add(key, value.present? ? error : :blank)
127
+ end
128
+ end
129
+
130
+ record
131
+ end
132
+
133
+ # Generate a token by looping and ensuring does not already exist.
134
+ def generate_token(column)
135
+ loop do
136
+ token = Devise.friendly_token
137
+ break token unless find(:first, :conditions => { column => token })
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,160 @@
1
+ module Devise
2
+ module Models
3
+ # Confirmable is responsible to verify if an account is already confirmed to
4
+ # sign in, and to send emails with confirmation instructions.
5
+ # Confirmation instructions are sent to the user email after creating a
6
+ # record and when manually requested by a new confirmation instruction request.
7
+ #
8
+ # == Options
9
+ #
10
+ # Confirmable adds the following options to devise_for:
11
+ #
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
19
+ #
20
+ # User.find(1).confirm! # returns true unless it's already confirmed
21
+ # User.find(1).confirmed? # true/false
22
+ # User.find(1).send_confirmation_instructions # manually send instructions
23
+ #
24
+ module Confirmable
25
+ extend ActiveSupport::Concern
26
+
27
+ included do
28
+ before_create :generate_confirmation_token, :if => :confirmation_required?
29
+ after_create :send_confirmation_instructions, :if => :confirmation_required?
30
+ end
31
+
32
+ # Confirm a user by setting it's confirmed_at to actual time. If the user
33
+ # is already confirmed, add en error to email field
34
+ def confirm!
35
+ unless_confirmed do
36
+ self.confirmation_token = nil
37
+ self.confirmed_at = Time.now
38
+ save(:validate => false)
39
+ end
40
+ end
41
+
42
+ # Verifies whether a user is confirmed or not
43
+ def confirmed?
44
+ !!confirmed_at
45
+ end
46
+
47
+ # Send confirmation instructions by email
48
+ def send_confirmation_instructions
49
+ generate_confirmation_token! if self.confirmation_token.nil?
50
+ ::Devise.mailer.confirmation_instructions(self).deliver
51
+ end
52
+
53
+ # Resend confirmation token. This method does not need to generate a new token.
54
+ def resend_confirmation_token
55
+ unless_confirmed { send_confirmation_instructions }
56
+ end
57
+
58
+ # Overwrites active? from Devise::Models::Activatable for confirmation
59
+ # by verifying whether an user is active to sign in or not. If the user
60
+ # is already confirmed, it should never be blocked. Otherwise we need to
61
+ # calculate if the confirm time has not expired for this user.
62
+ def active?
63
+ super && (!confirmation_required? || confirmed? || confirmation_period_valid?)
64
+ end
65
+
66
+ # The message to be shown if the account is inactive.
67
+ def inactive_message
68
+ !confirmed? ? :unconfirmed : super
69
+ end
70
+
71
+ # If you don't want confirmation to be sent on create, neither a code
72
+ # to be generated, call skip_confirmation!
73
+ def skip_confirmation!
74
+ self.confirmed_at = Time.now
75
+ end
76
+
77
+ protected
78
+
79
+ # Callback to overwrite if confirmation is required or not.
80
+ def confirmation_required?
81
+ !confirmed?
82
+ end
83
+
84
+ # Checks if the confirmation for the user is within the limit time.
85
+ # We do this by calculating if the difference between today and the
86
+ # confirmation sent date does not exceed the confirm in time configured.
87
+ # Confirm_in is a model configuration, must always be an integer value.
88
+ #
89
+ # Example:
90
+ #
91
+ # # confirm_within = 1.day and confirmation_sent_at = today
92
+ # confirmation_period_valid? # returns true
93
+ #
94
+ # # confirm_within = 5.days and confirmation_sent_at = 4.days.ago
95
+ # confirmation_period_valid? # returns true
96
+ #
97
+ # # confirm_within = 5.days and confirmation_sent_at = 5.days.ago
98
+ # confirmation_period_valid? # returns false
99
+ #
100
+ # # confirm_within = 0.days
101
+ # confirmation_period_valid? # will always return false
102
+ #
103
+ def confirmation_period_valid?
104
+ confirmation_sent_at && confirmation_sent_at.utc >= self.class.confirm_within.ago
105
+ end
106
+
107
+ # Checks whether the record is confirmed or not, yielding to the block
108
+ # if it's already confirmed, otherwise adds an error to email.
109
+ def unless_confirmed
110
+ unless confirmed?
111
+ yield
112
+ else
113
+ self.errors.add(:email, :already_confirmed)
114
+ false
115
+ end
116
+ end
117
+
118
+ # Generates a new random token for confirmation, and stores the time
119
+ # this token is being generated
120
+ def generate_confirmation_token
121
+ self.confirmed_at = nil
122
+ self.confirmation_token = self.class.confirmation_token
123
+ self.confirmation_sent_at = Time.now.utc
124
+ end
125
+
126
+ def generate_confirmation_token!
127
+ generate_confirmation_token && save(:validate => false)
128
+ end
129
+
130
+ module ClassMethods
131
+ # Attempt to find a user by it's email. If a record is found, send new
132
+ # confirmation instructions to it. If not user is found, returns a new user
133
+ # with an email not found error.
134
+ # Options must contain the user email
135
+ def send_confirmation_instructions(attributes={})
136
+ confirmable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
137
+ confirmable.resend_confirmation_token if confirmable.persisted?
138
+ confirmable
139
+ end
140
+
141
+ # Find a user by it's confirmation token and try to confirm it.
142
+ # If no user is found, returns a new user with an error.
143
+ # If the user is already confirmed, create an error for the user
144
+ # Options must have the confirmation_token
145
+ def confirm_by_token(confirmation_token)
146
+ confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
147
+ confirmable.confirm! if confirmable.persisted?
148
+ confirmable
149
+ end
150
+
151
+ # Generate a token checking if one does not already exist in the database.
152
+ def confirmation_token
153
+ generate_token(:confirmation_token)
154
+ end
155
+
156
+ Devise::Models.config(self, :confirm_within)
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,94 @@
1
+ require 'devise/strategies/database_authenticatable'
2
+ require 'bcrypt'
3
+
4
+ module Devise
5
+ module Models
6
+ # Authenticable Module, responsible for encrypting password and validating
7
+ # authenticity of a user while signing in.
8
+ #
9
+ # == Options
10
+ #
11
+ # DatabaseAuthenticable adds the following options to devise_for:
12
+ #
13
+ # * +stretches+: the cost given to bcrypt.
14
+ #
15
+ # == Examples
16
+ #
17
+ # User.find(1).valid_password?('password123') # returns true/false
18
+ #
19
+ module DatabaseAuthenticatable
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 encryption based on the given value.
28
+ def password=(new_password)
29
+ @password = new_password
30
+ self.encrypted_password = password_digest(@password) if @password.present?
31
+ end
32
+
33
+ # Verifies whether an incoming_password (ie from sign in) is the user password.
34
+ def valid_password?(incoming_password)
35
+ ::BCrypt::Password.new(self.encrypted_password) == incoming_password
36
+ end
37
+
38
+ # Set password and password confirmation to nil
39
+ def clean_up_passwords
40
+ self.password = self.password_confirmation = nil
41
+ end
42
+
43
+ # Update record attributes when :current_password matches, otherwise returns
44
+ # error on :current_password. It also automatically rejects :password and
45
+ # :password_confirmation if they are blank.
46
+ def update_with_password(params={})
47
+ current_password = params.delete(:current_password)
48
+
49
+ if params[:password].blank?
50
+ params.delete(:password)
51
+ params.delete(:password_confirmation) if params[:password_confirmation].blank?
52
+ end
53
+
54
+ result = if valid_password?(current_password)
55
+ update_attributes(params)
56
+ else
57
+ self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
58
+ self.attributes = params
59
+ false
60
+ end
61
+
62
+ clean_up_passwords
63
+ result
64
+ end
65
+
66
+ def after_database_authentication
67
+ end
68
+
69
+ # A reliable way to expose the salt regardless of the implementation.
70
+ def authenticatable_salt
71
+ self.encrypted_password[0,29]
72
+ end
73
+
74
+ protected
75
+
76
+ # Digests the password using bcrypt.
77
+ def password_digest(password)
78
+ ::BCrypt::Password.create(password, :cost => self.class.stretches).to_s
79
+ end
80
+
81
+ module ClassMethods
82
+ Devise::Models.config(self, :stretches)
83
+
84
+ # We assume this method already gets the sanitized values from the
85
+ # DatabaseAuthenticatable strategy. If you are using this method on
86
+ # your own, be sure to sanitize the conditions hash to only include
87
+ # the proper fields.
88
+ def find_for_database_authentication(conditions)
89
+ find_for_authentication(conditions)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end