devise 1.1.pre4 → 1.1.rc0
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.
- data/CHANGELOG.rdoc +31 -2
- data/Gemfile +15 -6
- data/README.rdoc +12 -16
- data/Rakefile +2 -2
- data/TODO +2 -1
- data/app/controllers/devise/confirmations_controller.rb +1 -1
- data/app/controllers/devise/passwords_controller.rb +2 -3
- data/app/controllers/devise/registrations_controller.rb +5 -5
- data/app/controllers/devise/sessions_controller.rb +5 -27
- data/app/controllers/devise/unlocks_controller.rb +9 -1
- data/app/models/devise/mailer.rb +17 -11
- data/app/views/devise/confirmations/new.html.erb +1 -1
- data/app/views/devise/passwords/edit.html.erb +1 -1
- data/app/views/devise/passwords/new.html.erb +1 -1
- data/app/views/devise/registrations/edit.html.erb +2 -2
- data/app/views/devise/registrations/new.html.erb +2 -2
- data/app/views/devise/sessions/new.html.erb +2 -2
- data/app/views/devise/shared/_links.erb +5 -5
- data/app/views/devise/unlocks/new.html.erb +1 -1
- data/config/locales/en.yml +4 -9
- data/lib/devise.rb +83 -42
- data/lib/devise/controllers/helpers.rb +6 -18
- data/lib/devise/controllers/internal_helpers.rb +11 -12
- data/lib/devise/controllers/scoped_views.rb +2 -2
- data/lib/devise/controllers/url_helpers.rb +1 -1
- data/lib/devise/failure_app.rb +56 -16
- data/lib/devise/hooks/activatable.rb +18 -6
- data/lib/devise/hooks/rememberable.rb +36 -27
- data/lib/devise/hooks/timeoutable.rb +1 -1
- data/lib/devise/hooks/trackable.rb +4 -2
- data/lib/devise/mapping.rb +19 -14
- data/lib/devise/models.rb +12 -3
- data/lib/devise/models/authenticatable.rb +19 -95
- data/lib/devise/models/confirmable.rb +14 -20
- data/lib/devise/models/database_authenticatable.rb +99 -0
- data/lib/devise/models/lockable.rb +53 -39
- data/lib/devise/models/recoverable.rb +3 -3
- data/lib/devise/models/rememberable.rb +5 -10
- data/lib/devise/models/token_authenticatable.rb +18 -25
- data/lib/devise/models/validatable.rb +14 -9
- data/lib/devise/modules.rb +7 -8
- data/lib/devise/orm/active_record.rb +1 -1
- data/lib/devise/orm/data_mapper.rb +20 -7
- data/lib/devise/orm/mongoid.rb +40 -0
- data/lib/devise/rails.rb +26 -3
- data/lib/devise/rails/routes.rb +18 -16
- data/lib/devise/rails/warden_compat.rb +2 -2
- data/lib/devise/schema.rb +45 -18
- data/lib/devise/strategies/authenticatable.rb +92 -21
- data/lib/devise/strategies/base.rb +6 -3
- data/lib/devise/strategies/database_authenticatable.rb +20 -0
- data/lib/devise/strategies/rememberable.rb +10 -6
- data/lib/devise/strategies/token_authenticatable.rb +28 -19
- data/lib/devise/test_helpers.rb +5 -1
- data/lib/devise/version.rb +1 -1
- data/lib/generators/devise/devise_generator.rb +15 -5
- data/lib/generators/devise/templates/migration.rb +2 -2
- data/lib/generators/devise_install/templates/devise.rb +37 -16
- data/lib/generators/devise_views/devise_views_generator.rb +51 -4
- data/test/controllers/helpers_test.rb +16 -8
- data/test/controllers/internal_helpers_test.rb +6 -1
- data/test/controllers/url_helpers_test.rb +10 -10
- data/test/devise_test.rb +13 -17
- data/test/encryptors_test.rb +2 -0
- data/test/failure_app_test.rb +72 -23
- data/test/integration/confirmable_test.rb +4 -4
- data/test/integration/{authenticatable_test.rb → database_authenticatable_test.rb} +35 -17
- data/test/integration/http_authenticatable_test.rb +3 -3
- data/test/integration/lockable_test.rb +28 -8
- data/test/integration/recoverable_test.rb +3 -3
- data/test/integration/registerable_test.rb +6 -4
- data/test/integration/rememberable_test.rb +11 -4
- data/test/integration/timeoutable_test.rb +4 -4
- data/test/integration/token_authenticatable_test.rb +46 -10
- data/test/integration/trackable_test.rb +2 -2
- data/test/mailers/confirmation_instructions_test.rb +5 -5
- data/test/mailers/reset_password_instructions_test.rb +5 -5
- data/test/mailers/unlock_instructions_test.rb +5 -5
- data/test/mapping_test.rb +15 -14
- data/test/models/confirmable_test.rb +9 -32
- data/test/models/{authenticatable_test.rb → database_authenticatable_test.rb} +2 -34
- data/test/models/lockable_test.rb +48 -66
- data/test/models/recoverable_test.rb +8 -8
- data/test/models/rememberable_test.rb +6 -28
- data/test/models/timeoutable_test.rb +1 -1
- data/test/models/token_authenticatable_test.rb +1 -8
- data/test/models/trackable_test.rb +1 -1
- data/test/models/validatable_test.rb +2 -2
- data/test/models_test.rb +16 -2
- data/test/orm/active_record.rb +1 -22
- data/test/orm/data_mapper.rb +1 -0
- data/test/orm/mongoid.rb +10 -0
- data/test/rails_app/app/active_record/admin.rb +1 -5
- data/test/rails_app/app/controllers/application_controller.rb +2 -0
- data/test/rails_app/app/controllers/sessions_controller.rb +1 -1
- data/test/rails_app/app/data_mapper/admin.rb +13 -0
- data/test/rails_app/app/data_mapper/user.rb +24 -0
- data/test/rails_app/app/mongoid/admin.rb +15 -0
- data/test/rails_app/app/mongoid/user.rb +21 -0
- data/test/rails_app/config/application.rb +10 -5
- data/test/rails_app/config/boot.rb +5 -1
- data/test/rails_app/config/initializers/devise.rb +1 -1
- data/test/rails_app/config/routes.rb +4 -1
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +27 -0
- data/test/rails_app/db/schema.rb +86 -0
- data/test/routes_test.rb +3 -3
- data/test/support/assertions.rb +2 -0
- data/test/support/helpers.rb +2 -0
- data/test/support/integration.rb +4 -7
- data/test/support/webrat/integrations/rails.rb +2 -1
- data/test/test_helper.rb +5 -2
- data/test/test_helpers_test.rb +4 -4
- metadata +36 -21
- data/lib/devise/models/http_authenticatable.rb +0 -19
- data/lib/devise/orm/mongo_mapper.rb +0 -49
- data/lib/devise/strategies/http_authenticatable.rb +0 -47
- data/test/models/http_authenticatable_test.rb +0 -19
- data/test/orm/mongo_mapper.rb +0 -12
- data/test/rails_app/app/mongo_mapper/admin.rb +0 -10
- data/test/rails_app/app/mongo_mapper/user.rb +0 -11
- data/test/rails_app/config/initializers/cookie_verification_secret.rb +0 -7
- data/test/rails_app/config/initializers/session_store.rb +0 -15
@@ -3,13 +3,25 @@ Warden::Manager.after_set_user do |record, warden, options|
|
|
3
3
|
if record && record.respond_to?(:active?) && !record.active?
|
4
4
|
scope = options[:scope]
|
5
5
|
warden.logout(scope)
|
6
|
+
throw :warden, :scope => scope, :message => record.inactive_message
|
7
|
+
end
|
8
|
+
end
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
if
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
module Devise
|
11
|
+
module Hooks
|
12
|
+
# Overwrite Devise base strategy to only authenticate an user if it's active.
|
13
|
+
# If you have an strategy that does not use Devise::Strategy::Base, don't worry
|
14
|
+
# because the hook above will still avoid it to authenticate.
|
15
|
+
module Activatable
|
16
|
+
def success!(resource)
|
17
|
+
if resource.respond_to?(:active?) && !resource.active?
|
18
|
+
fail!(resource.inactive_message)
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
13
23
|
end
|
14
24
|
end
|
15
25
|
end
|
26
|
+
|
27
|
+
Devise::Strategies::Base.send :include, Devise::Hooks::Activatable
|
@@ -1,32 +1,41 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
# Before logout hook to forget the user in the given scope, if it responds
|
2
|
+
# to forget_me! Also clear remember token to ensure the user won't be
|
3
|
+
# remembered again. Notice that we forget the user unless the record is frozen.
|
4
|
+
# This avoids forgetting deleted users.
|
5
|
+
Warden::Manager.before_logout do |record, warden, scope|
|
6
|
+
if record.respond_to?(:forget_me!)
|
7
|
+
record.forget_me! unless record.frozen?
|
8
|
+
warden.cookies.delete "remember_#{scope}_token"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Devise
|
13
|
+
module Hooks
|
14
|
+
# Overwrite success! in authentication strategies allowing users to be remembered.
|
15
|
+
# We choose to implement this as an strategy hook instead of a Devise hook to avoid users
|
16
|
+
# giving a remember_me access in strategies that should not create remember me tokens.
|
17
|
+
module Rememberable #:nodoc:
|
18
|
+
def success!(resource)
|
19
|
+
super
|
9
20
|
|
10
|
-
|
11
|
-
|
12
|
-
record.remember_me!
|
21
|
+
if succeeded? && resource.respond_to?(:remember_me!) && remember_me?
|
22
|
+
resource.remember_me!
|
13
23
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
24
|
+
cookies.signed["remember_#{scope}_token"] = {
|
25
|
+
:value => resource.class.serialize_into_cookie(resource),
|
26
|
+
:expires => resource.remember_expires_at,
|
27
|
+
:path => "/"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def remember_me?
|
35
|
+
valid_params? && Devise::TRUE_VALUES.include?(params_auth_hash[:remember_me])
|
36
|
+
end
|
37
|
+
end
|
19
38
|
end
|
20
39
|
end
|
21
40
|
|
22
|
-
|
23
|
-
# is activated for this scope. Also clear remember token to ensure the user
|
24
|
-
# won't be remembered again.
|
25
|
-
# Notice that we forget the user if the record is frozen. This usually means the
|
26
|
-
# user was just deleted.
|
27
|
-
Warden::Manager.before_logout do |record, warden, scope|
|
28
|
-
if record.respond_to?(:forget_me!)
|
29
|
-
record.forget_me! unless record.frozen?
|
30
|
-
warden.response.delete_cookie "remember_#{scope}_token"
|
31
|
-
end
|
32
|
-
end
|
41
|
+
Devise::Strategies::Authenticatable.send :include, Devise::Hooks::Rememberable
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Each time a record is set we check whether
|
1
|
+
# Each time a record is set we check whether its session has already timed out
|
2
2
|
# or not, based on last request time. If so, the record is logged out and
|
3
3
|
# redirected to the sign in page. Also, each time the request comes and the
|
4
4
|
# record is set, we set the last request time inside it's scoped session to
|
@@ -1,7 +1,9 @@
|
|
1
1
|
# After each sign in, update sign in time, sign in count and sign in IP.
|
2
|
+
# This is only triggered when the user is explicitly set (with set_user)
|
3
|
+
# and on authentication. Retrieving the user from session (:fetch) does
|
4
|
+
# not trigger it.
|
2
5
|
Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
|
3
|
-
|
4
|
-
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(scope)
|
6
|
+
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope])
|
5
7
|
record.update_tracked_fields!(warden.request)
|
6
8
|
end
|
7
9
|
end
|
data/lib/devise/mapping.rb
CHANGED
@@ -34,26 +34,19 @@ module Devise
|
|
34
34
|
nil
|
35
35
|
end
|
36
36
|
|
37
|
-
# Find a mapping by a given class. It takes into account single table inheritance as well.
|
38
|
-
def self.find_by_class(klass)
|
39
|
-
Devise.mappings.each_value do |mapping|
|
40
|
-
return mapping if klass <= mapping.to
|
41
|
-
end
|
42
|
-
nil
|
43
|
-
end
|
44
|
-
|
45
37
|
# Receives an object and find a scope for it. If a scope cannot be found,
|
46
38
|
# raises an error. If a symbol is given, it's considered to be the scope.
|
47
39
|
def self.find_scope!(duck)
|
48
40
|
case duck
|
49
41
|
when String, Symbol
|
50
|
-
duck
|
42
|
+
return duck
|
43
|
+
when Class
|
44
|
+
Devise.mappings.each_value { |m| return m.name if duck <= m.to }
|
51
45
|
else
|
52
|
-
|
53
|
-
mapping = Devise::Mapping.find_by_class(klass)
|
54
|
-
raise "Could not find a valid mapping for #{duck}" unless mapping
|
55
|
-
mapping.name
|
46
|
+
Devise.mappings.each_value { |m| return m.name if duck.is_a?(m.to) }
|
56
47
|
end
|
48
|
+
|
49
|
+
raise "Could not find a valid mapping for #{duck}"
|
57
50
|
end
|
58
51
|
|
59
52
|
def initialize(name, options) #:nodoc:
|
@@ -84,6 +77,14 @@ module Devise
|
|
84
77
|
klass
|
85
78
|
end
|
86
79
|
|
80
|
+
def strategies
|
81
|
+
@strategies ||= STRATEGIES.values_at(*self.modules).compact.uniq.reverse
|
82
|
+
end
|
83
|
+
|
84
|
+
def routes
|
85
|
+
@routes ||= ROUTES.values_at(*self.modules).compact.uniq
|
86
|
+
end
|
87
|
+
|
87
88
|
# Keep a list of allowed controllers for this mapping. It's useful to ensure
|
88
89
|
# that an Admin cannot access the registrations controller unless it has
|
89
90
|
# :registerable in the model.
|
@@ -104,6 +105,10 @@ module Devise
|
|
104
105
|
path_prefix + as.to_s
|
105
106
|
end
|
106
107
|
|
108
|
+
def authenticatable?
|
109
|
+
@authenticatable ||= self.modules.any? { |m| m.to_s =~ /authenticatable/ }
|
110
|
+
end
|
111
|
+
|
107
112
|
# Create magic predicates for verifying what module is activated by this map.
|
108
113
|
# Example:
|
109
114
|
#
|
@@ -111,7 +116,7 @@ module Devise
|
|
111
116
|
# self.modules.include?(:confirmable)
|
112
117
|
# end
|
113
118
|
#
|
114
|
-
def self.
|
119
|
+
def self.add_module(m)
|
115
120
|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
116
121
|
def #{m}?
|
117
122
|
self.modules.include?(:#{m})
|
data/lib/devise/models.rb
CHANGED
@@ -38,7 +38,7 @@ module Devise
|
|
38
38
|
|
39
39
|
# Include the chosen devise modules in your model:
|
40
40
|
#
|
41
|
-
# devise :
|
41
|
+
# devise :database_authenticatable, :confirmable, :recoverable
|
42
42
|
#
|
43
43
|
# You can also give any of the devise configuration values in form of a hash,
|
44
44
|
# with specific values for this model. Please check your Devise initializer
|
@@ -46,12 +46,21 @@ module Devise
|
|
46
46
|
#
|
47
47
|
def devise(*modules)
|
48
48
|
raise "You need to give at least one Devise module" if modules.empty?
|
49
|
-
|
50
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(:http_authenticatable)
|
57
|
+
ActiveSupport::Deprecation.warn ":http_authenticatable as module is deprecated and is on by default. Revert by setting :http_authenticatable => false.", caller
|
58
|
+
end
|
59
|
+
|
51
60
|
@devise_modules = Devise::ALL & modules.map(&:to_sym).uniq
|
52
61
|
|
53
62
|
devise_modules_hook! do
|
54
|
-
devise_modules.each { |m| include Devise::Models.const_get(m.to_s.classify) }
|
63
|
+
@devise_modules.each { |m| include Devise::Models.const_get(m.to_s.classify) }
|
55
64
|
options.each { |key, value| send(:"#{key}=", value) }
|
56
65
|
end
|
57
66
|
end
|
@@ -1,118 +1,42 @@
|
|
1
|
-
require 'devise/strategies/authenticatable'
|
2
|
-
|
3
1
|
module Devise
|
4
2
|
module Models
|
5
|
-
# Authenticable
|
6
|
-
# authenticity of a user while signing in.
|
3
|
+
# Authenticable module. Holds common settings for authentication.
|
7
4
|
#
|
8
5
|
# Configuration:
|
9
6
|
#
|
10
7
|
# You can overwrite configuration values by setting in globally in Devise,
|
11
8
|
# using devise method or overwriting the respective instance method.
|
12
9
|
#
|
13
|
-
#
|
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.
|
17
|
-
#
|
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
|
-
# authentication_keys: parameters used for authentication. By default [:email]
|
10
|
+
# authentication_keys: parameters used for authentication. By default [:email].
|
23
11
|
#
|
24
|
-
#
|
12
|
+
# http_authenticatable: if this model allows http authentication. By default true.
|
13
|
+
# It also accepts an array specifying the strategies that should allow http.
|
25
14
|
#
|
26
|
-
#
|
27
|
-
#
|
15
|
+
# params_authenticatable: if this model allows authentication through request params. By default true.
|
16
|
+
# It also accepts an array specifying the strategies that should allow params authentication.
|
28
17
|
#
|
29
18
|
module Authenticatable
|
30
19
|
extend ActiveSupport::Concern
|
31
20
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
# Regenerates password salt and encrypted password each time password is set,
|
38
|
-
# and then trigger any "after_changed_password"-callbacks.
|
39
|
-
def password=(new_password)
|
40
|
-
@password = new_password
|
41
|
-
|
42
|
-
if @password.present?
|
43
|
-
self.password_salt = self.class.encryptor_class.salt
|
44
|
-
self.encrypted_password = password_digest(@password)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
49
|
-
def valid_password?(incoming_password)
|
50
|
-
password_digest(incoming_password) == self.encrypted_password
|
51
|
-
end
|
52
|
-
|
53
|
-
# Verifies whether an +incoming_authentication_token+ (i.e. from single access URL)
|
54
|
-
# is the user authentication token.
|
55
|
-
def valid_authentication_token?(incoming_auth_token)
|
56
|
-
incoming_auth_token == self.authentication_token
|
57
|
-
end
|
58
|
-
|
59
|
-
# Checks if a resource is valid upon authentication.
|
60
|
-
def valid_for_authentication?(attributes)
|
61
|
-
valid_password?(attributes[:password])
|
62
|
-
end
|
63
|
-
|
64
|
-
# Set password and password confirmation to nil
|
65
|
-
def clean_up_passwords
|
66
|
-
self.password = self.password_confirmation = nil
|
21
|
+
# Yields the given block. This method is overwritten by other modules to provide
|
22
|
+
# hooks around authentication.
|
23
|
+
def valid_for_authentication?
|
24
|
+
yield
|
67
25
|
end
|
68
26
|
|
69
|
-
# Update record attributes when :current_password matches, otherwise returns
|
70
|
-
# error on :current_password. It also automatically rejects :password and
|
71
|
-
# :password_confirmation if they are blank.
|
72
|
-
def update_with_password(params={})
|
73
|
-
current_password = params.delete(:current_password)
|
74
|
-
|
75
|
-
params.delete(:password) if params[:password].blank?
|
76
|
-
params.delete(:password_confirmation) if params[:password_confirmation].blank?
|
77
|
-
|
78
|
-
result = if valid_password?(current_password)
|
79
|
-
update_attributes(params)
|
80
|
-
else
|
81
|
-
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
82
|
-
self.attributes = params
|
83
|
-
false
|
84
|
-
end
|
85
|
-
|
86
|
-
clean_up_passwords unless result
|
87
|
-
result
|
88
|
-
end
|
89
|
-
|
90
|
-
protected
|
91
|
-
|
92
|
-
# Digests the password using the configured encryptor.
|
93
|
-
def password_digest(password)
|
94
|
-
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
95
|
-
end
|
96
|
-
|
97
27
|
module ClassMethods
|
98
|
-
Devise::Models.config(self, :
|
28
|
+
Devise::Models.config(self, :authentication_keys, :http_authenticatable, :params_authenticatable)
|
99
29
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
return unless authentication_keys.all? { |k| attributes[k].present? }
|
104
|
-
conditions = attributes.slice(*authentication_keys)
|
105
|
-
resource = find_for_authentication(conditions)
|
106
|
-
resource if resource.try(:valid_for_authentication?, attributes)
|
30
|
+
def params_authenticatable?(strategy)
|
31
|
+
params_authenticatable.is_a?(Array) ?
|
32
|
+
params_authenticatable.include?(strategy) : params_authenticatable
|
107
33
|
end
|
108
34
|
|
109
|
-
|
110
|
-
|
111
|
-
|
35
|
+
def http_authenticatable?(strategy)
|
36
|
+
http_authenticatable.is_a?(Array) ?
|
37
|
+
http_authenticatable.include?(strategy) : http_authenticatable
|
112
38
|
end
|
113
39
|
|
114
|
-
protected
|
115
|
-
|
116
40
|
# Find first record based on conditions given (ie by the sign in form).
|
117
41
|
# Overwrite to add customized conditions, create a join, or maybe use a
|
118
42
|
# namedscope to filter records while authenticating.
|
@@ -120,7 +44,7 @@ module Devise
|
|
120
44
|
#
|
121
45
|
# def self.find_for_authentication(conditions={})
|
122
46
|
# conditions[:active] = true
|
123
|
-
#
|
47
|
+
# super
|
124
48
|
# end
|
125
49
|
#
|
126
50
|
def find_for_authentication(conditions)
|
@@ -129,4 +53,4 @@ module Devise
|
|
129
53
|
end
|
130
54
|
end
|
131
55
|
end
|
132
|
-
end
|
56
|
+
end
|
@@ -49,7 +49,7 @@ module Devise
|
|
49
49
|
|
50
50
|
# Verifies whether a user is confirmed or not
|
51
51
|
def confirmed?
|
52
|
-
|
52
|
+
persisted? && !confirmed_at.nil?
|
53
53
|
end
|
54
54
|
|
55
55
|
# Send confirmation instructions by email
|
@@ -57,15 +57,9 @@ module Devise
|
|
57
57
|
::Devise::Mailer.confirmation_instructions(self).deliver
|
58
58
|
end
|
59
59
|
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
def resend_confirmation!
|
64
|
-
unless_confirmed do
|
65
|
-
generate_confirmation_token
|
66
|
-
save(:validate => false)
|
67
|
-
send_confirmation_instructions
|
68
|
-
end
|
60
|
+
# Resend confirmation token. This method does not need to generate a new token.
|
61
|
+
def resend_confirmation_token
|
62
|
+
unless_confirmed { send_confirmation_instructions }
|
69
63
|
end
|
70
64
|
|
71
65
|
# Overwrites active? from Devise::Models::Activatable for confirmation
|
@@ -78,11 +72,7 @@ module Devise
|
|
78
72
|
|
79
73
|
# The message to be shown if the account is inactive.
|
80
74
|
def inactive_message
|
81
|
-
|
82
|
-
:unconfirmed
|
83
|
-
else
|
84
|
-
super
|
85
|
-
end
|
75
|
+
!confirmed? ? :unconfirmed : super
|
86
76
|
end
|
87
77
|
|
88
78
|
# If you don't want confirmation to be sent on create, neither a code
|
@@ -137,7 +127,7 @@ module Devise
|
|
137
127
|
# this token is being generated
|
138
128
|
def generate_confirmation_token
|
139
129
|
self.confirmed_at = nil
|
140
|
-
self.confirmation_token =
|
130
|
+
self.confirmation_token = self.class.confirmation_token
|
141
131
|
self.confirmation_sent_at = Time.now.utc
|
142
132
|
end
|
143
133
|
|
@@ -148,7 +138,7 @@ module Devise
|
|
148
138
|
# Options must contain the user email
|
149
139
|
def send_confirmation_instructions(attributes={})
|
150
140
|
confirmable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
151
|
-
confirmable.
|
141
|
+
confirmable.resend_confirmation_token if confirmable.persisted?
|
152
142
|
confirmable
|
153
143
|
end
|
154
144
|
|
@@ -156,12 +146,16 @@ module Devise
|
|
156
146
|
# If no user is found, returns a new user with an error.
|
157
147
|
# If the user is already confirmed, create an error for the user
|
158
148
|
# Options must have the confirmation_token
|
159
|
-
def
|
160
|
-
confirmable = find_or_initialize_with_error_by(:confirmation_token,
|
161
|
-
confirmable.confirm!
|
149
|
+
def confirm_by_token(confirmation_token)
|
150
|
+
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
|
151
|
+
confirmable.confirm! if confirmable.persisted?
|
162
152
|
confirmable
|
163
153
|
end
|
164
154
|
|
155
|
+
def confirmation_token
|
156
|
+
Devise.friendly_token
|
157
|
+
end
|
158
|
+
|
165
159
|
Devise::Models.config(self, :confirm_within)
|
166
160
|
end
|
167
161
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'devise/models/authenticatable'
|
2
|
+
require 'devise/strategies/database_authenticatable'
|
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
|
+
# Configuration:
|
10
|
+
#
|
11
|
+
# You can overwrite configuration values by setting in globally in Devise,
|
12
|
+
# using devise method or overwriting the respective instance method.
|
13
|
+
#
|
14
|
+
# pepper: encryption key used for creating encrypted password. Each time
|
15
|
+
# password changes, it's gonna be encrypted again, and this key
|
16
|
+
# is added to the password and salt to create a secure hash.
|
17
|
+
# Always use `rake secret' to generate a new key.
|
18
|
+
#
|
19
|
+
# stretches: defines how many times the password will be encrypted.
|
20
|
+
#
|
21
|
+
# encryptor: the encryptor going to be used. By default :sha1.
|
22
|
+
#
|
23
|
+
# Examples:
|
24
|
+
#
|
25
|
+
# User.find(1).valid_password?('password123') # returns true/false
|
26
|
+
#
|
27
|
+
module DatabaseAuthenticatable
|
28
|
+
extend ActiveSupport::Concern
|
29
|
+
include Devise::Models::Authenticatable
|
30
|
+
|
31
|
+
included do
|
32
|
+
attr_reader :password, :current_password
|
33
|
+
attr_accessor :password_confirmation
|
34
|
+
end
|
35
|
+
|
36
|
+
# Regenerates password salt and encrypted password each time password is set,
|
37
|
+
# and then trigger any "after_changed_password"-callbacks.
|
38
|
+
def password=(new_password)
|
39
|
+
@password = new_password
|
40
|
+
|
41
|
+
if @password.present?
|
42
|
+
self.password_salt = self.class.encryptor_class.salt
|
43
|
+
self.encrypted_password = password_digest(@password)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
48
|
+
def valid_password?(incoming_password)
|
49
|
+
password_digest(incoming_password) == self.encrypted_password
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set password and password confirmation to nil
|
53
|
+
def clean_up_passwords
|
54
|
+
self.password = self.password_confirmation = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
# Update record attributes when :current_password matches, otherwise returns
|
58
|
+
# error on :current_password. It also automatically rejects :password and
|
59
|
+
# :password_confirmation if they are blank.
|
60
|
+
def update_with_password(params={})
|
61
|
+
current_password = params.delete(:current_password)
|
62
|
+
|
63
|
+
params.delete(:password) if params[:password].blank?
|
64
|
+
params.delete(:password_confirmation) if params[:password_confirmation].blank?
|
65
|
+
|
66
|
+
result = if valid_password?(current_password)
|
67
|
+
update_attributes(params)
|
68
|
+
else
|
69
|
+
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
70
|
+
self.attributes = params
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
74
|
+
clean_up_passwords
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
# Digests the password using the configured encryptor.
|
81
|
+
def password_digest(password)
|
82
|
+
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
83
|
+
end
|
84
|
+
|
85
|
+
module ClassMethods
|
86
|
+
Devise::Models.config(self, :pepper, :stretches, :encryptor)
|
87
|
+
|
88
|
+
# Returns the class for the configured encryptor.
|
89
|
+
def encryptor_class
|
90
|
+
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
|
91
|
+
end
|
92
|
+
|
93
|
+
def find_for_database_authentication(*args)
|
94
|
+
find_for_authentication(*args)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|