devise 1.0.10 → 1.1.0
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.
- data/CHANGELOG.rdoc +62 -10
- data/Gemfile +23 -0
- data/Gemfile.lock +118 -0
- data/README.rdoc +116 -77
- data/Rakefile +4 -2
- data/TODO +3 -2
- data/app/controllers/{confirmations_controller.rb → devise/confirmations_controller.rb} +1 -1
- data/app/controllers/{passwords_controller.rb → devise/passwords_controller.rb} +1 -1
- data/app/controllers/{registrations_controller.rb → devise/registrations_controller.rb} +12 -8
- data/app/controllers/devise/sessions_controller.rb +23 -0
- data/app/controllers/{unlocks_controller.rb → devise/unlocks_controller.rb} +1 -8
- data/app/helpers/devise_helper.rb +17 -0
- data/app/mailers/devise/mailer.rb +71 -0
- data/app/views/devise/confirmations/new.html.erb +12 -0
- data/app/views/devise/passwords/edit.html.erb +16 -0
- data/app/views/devise/passwords/new.html.erb +12 -0
- data/app/views/devise/registrations/edit.html.erb +25 -0
- data/app/views/devise/registrations/new.html.erb +18 -0
- data/app/views/devise/sessions/new.html.erb +17 -0
- data/app/views/devise/shared/_links.erb +19 -0
- data/app/views/devise/unlocks/new.html.erb +12 -0
- data/{lib/devise → config}/locales/en.yml +16 -12
- data/lib/devise/controllers/helpers.rb +57 -52
- data/lib/devise/controllers/internal_helpers.rb +19 -50
- data/lib/devise/controllers/scoped_views.rb +35 -0
- data/lib/devise/controllers/url_helpers.rb +1 -1
- data/lib/devise/encryptors/authlogic_sha512.rb +0 -2
- data/lib/devise/encryptors/base.rb +1 -1
- data/lib/devise/encryptors/bcrypt.rb +2 -4
- data/lib/devise/encryptors/clearance_sha1.rb +0 -2
- data/lib/devise/encryptors/sha1.rb +6 -8
- data/lib/devise/encryptors/sha512.rb +6 -8
- data/lib/devise/failure_app.rb +76 -39
- data/lib/devise/hooks/activatable.rb +6 -10
- data/lib/devise/hooks/forgetable.rb +11 -0
- data/lib/devise/hooks/rememberable.rb +40 -30
- data/lib/devise/hooks/timeoutable.rb +7 -3
- data/lib/devise/hooks/trackable.rb +5 -14
- data/lib/devise/mapping.rb +35 -62
- data/lib/devise/models/authenticatable.rb +126 -0
- data/lib/devise/models/confirmable.rb +19 -22
- data/lib/devise/models/database_authenticatable.rb +26 -60
- data/lib/devise/models/lockable.rb +43 -28
- data/lib/devise/models/recoverable.rb +11 -10
- data/lib/devise/models/rememberable.rb +56 -26
- data/lib/devise/models/timeoutable.rb +1 -3
- data/lib/devise/models/token_authenticatable.rb +14 -43
- data/lib/devise/models/trackable.rb +14 -0
- data/lib/devise/models/validatable.rb +16 -2
- data/lib/devise/models.rb +16 -53
- data/lib/devise/modules.rb +23 -0
- data/lib/devise/orm/active_record.rb +10 -15
- data/lib/devise/orm/mongoid.rb +29 -0
- data/lib/devise/path_checker.rb +18 -0
- data/lib/devise/rails/routes.rb +232 -117
- data/lib/devise/rails/warden_compat.rb +18 -39
- data/lib/devise/rails.rb +64 -9
- data/lib/devise/schema.rb +47 -23
- data/lib/devise/strategies/authenticatable.rb +123 -0
- data/lib/devise/strategies/base.rb +2 -3
- data/lib/devise/strategies/database_authenticatable.rb +7 -22
- data/lib/devise/strategies/rememberable.rb +21 -7
- data/lib/devise/strategies/token_authenticatable.rb +31 -19
- data/lib/devise/test_helpers.rb +6 -6
- data/lib/devise/version.rb +1 -1
- data/lib/devise.rb +174 -157
- data/lib/generators/active_record/devise_generator.rb +28 -0
- data/{generators/devise → lib/generators/active_record}/templates/migration.rb +9 -3
- data/lib/generators/devise/devise_generator.rb +17 -0
- data/lib/generators/devise/install_generator.rb +24 -0
- data/lib/generators/devise/orm_helpers.rb +23 -0
- data/{generators/devise_install → lib/generators/devise}/templates/README +9 -7
- data/lib/generators/devise/templates/devise.rb +142 -0
- data/lib/generators/devise/views_generator.rb +63 -0
- data/lib/generators/devise_install_generator.rb +4 -0
- data/lib/generators/devise_views_generator.rb +4 -0
- data/lib/generators/mongoid/devise_generator.rb +17 -0
- data/test/controllers/helpers_test.rb +48 -19
- data/test/controllers/internal_helpers_test.rb +12 -16
- data/test/controllers/url_helpers_test.rb +21 -10
- data/test/devise_test.rb +16 -25
- data/test/encryptors_test.rb +2 -3
- data/test/failure_app_test.rb +106 -27
- data/test/integration/authenticatable_test.rb +138 -126
- data/test/integration/confirmable_test.rb +22 -15
- data/test/integration/database_authenticatable_test.rb +38 -0
- data/test/integration/http_authenticatable_test.rb +9 -12
- data/test/integration/lockable_test.rb +22 -15
- data/test/integration/recoverable_test.rb +6 -6
- data/test/integration/registerable_test.rb +42 -33
- data/test/integration/rememberable_test.rb +84 -22
- data/test/integration/timeoutable_test.rb +16 -4
- data/test/integration/token_authenticatable_test.rb +45 -12
- data/test/integration/trackable_test.rb +1 -1
- data/test/mailers/confirmation_instructions_test.rb +11 -17
- data/test/mailers/reset_password_instructions_test.rb +7 -7
- data/test/mailers/unlock_instructions_test.rb +7 -7
- data/test/mapping_test.rb +22 -95
- data/test/models/confirmable_test.rb +12 -19
- data/test/models/{authenticatable_test.rb → database_authenticatable_test.rb} +24 -56
- data/test/models/lockable_test.rb +32 -46
- data/test/models/recoverable_test.rb +7 -7
- data/test/models/rememberable_test.rb +118 -35
- data/test/models/timeoutable_test.rb +1 -1
- data/test/models/token_authenticatable_test.rb +5 -19
- data/test/models/trackable_test.rb +1 -1
- data/test/models/validatable_test.rb +20 -27
- data/test/models_test.rb +12 -5
- data/test/orm/active_record.rb +1 -23
- data/test/orm/mongoid.rb +10 -0
- data/test/rails_app/app/active_record/admin.rb +1 -5
- data/test/rails_app/app/active_record/shim.rb +2 -0
- data/test/rails_app/app/active_record/user.rb +3 -3
- data/test/rails_app/app/controllers/application_controller.rb +2 -5
- data/test/rails_app/app/controllers/home_controller.rb +3 -0
- data/test/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
- data/test/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
- data/test/rails_app/app/controllers/sessions_controller.rb +6 -0
- data/test/rails_app/app/controllers/users_controller.rb +7 -5
- data/test/rails_app/app/mongoid/admin.rb +6 -0
- data/test/rails_app/app/mongoid/shim.rb +16 -0
- data/test/rails_app/app/mongoid/user.rb +10 -0
- data/test/rails_app/config/application.rb +35 -0
- data/test/rails_app/config/boot.rb +10 -107
- data/test/rails_app/config/environment.rb +4 -41
- data/test/rails_app/config/environments/development.rb +15 -13
- data/test/rails_app/config/environments/production.rb +25 -20
- data/test/rails_app/config/environments/test.rb +33 -28
- data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_app/config/initializers/devise.rb +95 -38
- data/test/rails_app/config/initializers/secret_token.rb +2 -0
- data/test/rails_app/config/routes.rb +47 -25
- 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 +62 -47
- data/test/support/{assertions_helper.rb → assertions.rb} +2 -15
- data/test/support/{tests_helper.rb → helpers.rb} +18 -3
- data/test/support/{integration_tests_helper.rb → integration.rb} +24 -7
- data/test/support/webrat/integrations/rails.rb +32 -0
- data/test/test_helper.rb +11 -11
- data/test/test_helpers_test.rb +30 -15
- metadata +105 -64
- data/app/controllers/sessions_controller.rb +0 -42
- data/app/models/devise_mailer.rb +0 -68
- data/app/views/confirmations/new.html.erb +0 -12
- data/app/views/passwords/edit.html.erb +0 -16
- data/app/views/passwords/new.html.erb +0 -12
- data/app/views/registrations/edit.html.erb +0 -25
- data/app/views/registrations/new.html.erb +0 -17
- data/app/views/sessions/new.html.erb +0 -17
- data/app/views/shared/_devise_links.erb +0 -19
- data/app/views/unlocks/new.html.erb +0 -12
- data/generators/devise/USAGE +0 -5
- data/generators/devise/devise_generator.rb +0 -15
- data/generators/devise/lib/route_devise.rb +0 -32
- data/generators/devise/templates/model.rb +0 -9
- data/generators/devise_install/USAGE +0 -3
- data/generators/devise_install/devise_install_generator.rb +0 -15
- data/generators/devise_install/templates/devise.rb +0 -105
- data/generators/devise_views/USAGE +0 -3
- data/generators/devise_views/devise_views_generator.rb +0 -21
- data/lib/devise/models/activatable.rb +0 -16
- data/lib/devise/models/http_authenticatable.rb +0 -23
- data/lib/devise/orm/data_mapper.rb +0 -83
- data/lib/devise/orm/mongo_mapper.rb +0 -52
- data/lib/devise/strategies/http_authenticatable.rb +0 -59
- data/rails/init.rb +0 -2
- data/test/integration/rack_middleware_test.rb +0 -47
- data/test/orm/mongo_mapper.rb +0 -20
- data/test/rails_app/app/mongo_mapper/admin.rb +0 -13
- data/test/rails_app/app/mongo_mapper/user.rb +0 -14
- data/test/rails_app/config/initializers/new_rails_defaults.rb +0 -24
- data/test/rails_app/config/initializers/session_store.rb +0 -15
- /data/app/views/{devise_mailer → devise/mailer}/confirmation_instructions.html.erb +0 -0
- /data/app/views/{devise_mailer → devise/mailer}/reset_password_instructions.html.erb +0 -0
- /data/app/views/{devise_mailer → devise/mailer}/unlock_instructions.html.erb +0 -0
data/lib/devise/mapping.rb
CHANGED
|
@@ -18,21 +18,12 @@ module Devise
|
|
|
18
18
|
# mapping.to #=> User
|
|
19
19
|
# # is the class to be loaded from routes, given in the route as :class_name.
|
|
20
20
|
#
|
|
21
|
-
# mapping.
|
|
21
|
+
# mapping.modules #=> [:authenticatable]
|
|
22
22
|
# # is the modules included in the class
|
|
23
23
|
#
|
|
24
24
|
class Mapping #:nodoc:
|
|
25
|
-
attr_reader :
|
|
26
|
-
|
|
27
|
-
# Loop through all mappings looking for a map that matches with the requested
|
|
28
|
-
# path (ie /users/sign_in). If a path prefix is given, it's taken into account.
|
|
29
|
-
def self.find_by_path(path)
|
|
30
|
-
Devise.mappings.each_value do |mapping|
|
|
31
|
-
route = path.split("/")[mapping.as_position]
|
|
32
|
-
return mapping if route && mapping.as == route.to_sym
|
|
33
|
-
end
|
|
34
|
-
nil
|
|
35
|
-
end
|
|
25
|
+
attr_reader :singular, :plural, :path, :controllers, :path_names, :class_name
|
|
26
|
+
alias :name :singular
|
|
36
27
|
|
|
37
28
|
# Receives an object and find a scope for it. If a scope cannot be found,
|
|
38
29
|
# raises an error. If a symbol is given, it's considered to be the scope.
|
|
@@ -49,82 +40,64 @@ module Devise
|
|
|
49
40
|
raise "Could not find a valid mapping for #{duck}"
|
|
50
41
|
end
|
|
51
42
|
|
|
52
|
-
# Default url options which can be used as prefix.
|
|
53
|
-
def self.default_url_options
|
|
54
|
-
{}
|
|
55
|
-
end
|
|
56
|
-
|
|
57
43
|
def initialize(name, options) #:nodoc:
|
|
58
|
-
@
|
|
59
|
-
@
|
|
60
|
-
@name = (options.delete(:scope) || name.to_s.singularize).to_sym
|
|
44
|
+
@plural = (options[:as] ? "#{options[:as]}_#{name}" : name).to_sym
|
|
45
|
+
@singular = (options[:singular] || @plural.to_s.singularize).to_sym
|
|
61
46
|
|
|
62
|
-
@
|
|
63
|
-
@
|
|
47
|
+
@class_name = (options[:class_name] || name.to_s.classify).to_s
|
|
48
|
+
@ref = ActiveSupport::Dependencies.ref(@class_name)
|
|
64
49
|
|
|
65
|
-
@
|
|
66
|
-
@
|
|
50
|
+
@path = (options[:path] || name).to_s
|
|
51
|
+
@path_prefix = options[:path_prefix]
|
|
67
52
|
|
|
68
|
-
|
|
53
|
+
mod = options[:module] || "devise"
|
|
54
|
+
@controllers = Hash.new { |h,k| h[k] = "#{mod}/#{k}" }
|
|
55
|
+
@controllers.merge!(options[:controllers] || {})
|
|
56
|
+
|
|
57
|
+
@path_names = Hash.new { |h,k| h[k] = k.to_s }
|
|
58
|
+
@path_names.merge!(:registration => "")
|
|
59
|
+
@path_names.merge!(options[:path_names] || {})
|
|
69
60
|
end
|
|
70
61
|
|
|
71
62
|
# Return modules for the mapping.
|
|
72
|
-
def
|
|
73
|
-
@
|
|
63
|
+
def modules
|
|
64
|
+
@modules ||= to.respond_to?(:devise_modules) ? to.devise_modules : []
|
|
74
65
|
end
|
|
75
66
|
|
|
76
|
-
#
|
|
67
|
+
# Gives the class the mapping points to.
|
|
77
68
|
def to
|
|
78
|
-
|
|
79
|
-
klass = @klass.constantize
|
|
80
|
-
@to = klass if Rails.configuration.cache_classes
|
|
81
|
-
klass
|
|
69
|
+
@ref.get
|
|
82
70
|
end
|
|
83
71
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
(self.for & CONTROLLERS[controller.to_sym]).present?
|
|
72
|
+
def strategies
|
|
73
|
+
@strategies ||= STRATEGIES.values_at(*self.modules).compact.uniq.reverse
|
|
87
74
|
end
|
|
88
75
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
self.path_prefix.count("/")
|
|
76
|
+
def routes
|
|
77
|
+
@routes ||= ROUTES.values_at(*self.modules).compact.uniq
|
|
92
78
|
end
|
|
93
79
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
path_prefix + as.to_s
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Returns the parsed path taking into account the relative url root and raw path.
|
|
100
|
-
def parsed_path
|
|
101
|
-
(ActionController::Base.relative_url_root.to_s + raw_path).tap do |path|
|
|
102
|
-
self.class.default_url_options.each do |key, value|
|
|
103
|
-
path.gsub!(key.inspect, value.to_param)
|
|
104
|
-
end
|
|
105
|
-
end
|
|
80
|
+
def authenticatable?
|
|
81
|
+
@authenticatable ||= self.modules.any? { |m| m.to_s =~ /authenticatable/ }
|
|
106
82
|
end
|
|
107
83
|
|
|
108
|
-
def
|
|
109
|
-
@
|
|
84
|
+
def fullpath
|
|
85
|
+
"#{@path_prefix}/#{@path}".squeeze("/")
|
|
110
86
|
end
|
|
111
87
|
|
|
112
88
|
# Create magic predicates for verifying what module is activated by this map.
|
|
113
89
|
# Example:
|
|
114
90
|
#
|
|
115
91
|
# def confirmable?
|
|
116
|
-
# self.
|
|
92
|
+
# self.modules.include?(:confirmable)
|
|
117
93
|
# end
|
|
118
94
|
#
|
|
119
|
-
def self.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
METHOD
|
|
126
|
-
end
|
|
95
|
+
def self.add_module(m)
|
|
96
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
|
97
|
+
def #{m}?
|
|
98
|
+
self.modules.include?(:#{m})
|
|
99
|
+
end
|
|
100
|
+
METHOD
|
|
127
101
|
end
|
|
128
|
-
Devise::Mapping.register *ALL
|
|
129
102
|
end
|
|
130
103
|
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require 'devise/hooks/activatable'
|
|
2
|
+
|
|
3
|
+
module Devise
|
|
4
|
+
module Models
|
|
5
|
+
# Authenticable module. Holds common settings for authentication.
|
|
6
|
+
#
|
|
7
|
+
# == Configuration:
|
|
8
|
+
#
|
|
9
|
+
# You can overwrite configuration values by setting in globally in Devise,
|
|
10
|
+
# using devise method or overwriting the respective instance method.
|
|
11
|
+
#
|
|
12
|
+
# authentication_keys: parameters used for authentication. By default [:email].
|
|
13
|
+
#
|
|
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.
|
|
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.
|
|
19
|
+
#
|
|
20
|
+
# == Active?
|
|
21
|
+
#
|
|
22
|
+
# Before authenticating an user and in each request, Devise checks if your model is active by
|
|
23
|
+
# calling model.active?. This method is overwriten by other devise modules. For instance,
|
|
24
|
+
# :confirmable overwrites .active? to only return true if your model was confirmed.
|
|
25
|
+
#
|
|
26
|
+
# You overwrite this method yourself, but if you do, don't forget to call super:
|
|
27
|
+
#
|
|
28
|
+
# def active?
|
|
29
|
+
# super && special_condition_is_valid?
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# Whenever active? returns false, Devise asks the reason why your model is inactive using
|
|
33
|
+
# the inactive_message method. You can overwrite it as well:
|
|
34
|
+
#
|
|
35
|
+
# def inactive_message
|
|
36
|
+
# special_condition_is_valid? ? super : :special_condition_is_not_valid
|
|
37
|
+
# end
|
|
38
|
+
#
|
|
39
|
+
module Authenticatable
|
|
40
|
+
extend ActiveSupport::Concern
|
|
41
|
+
|
|
42
|
+
included do
|
|
43
|
+
class_attribute :devise_modules, :instance_writer => false
|
|
44
|
+
self.devise_modules ||= []
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Check if the current object is valid for authentication. This method and
|
|
48
|
+
# find_for_authentication are the methods used in a Warden::Strategy to check
|
|
49
|
+
# if a model should be signed in or not.
|
|
50
|
+
#
|
|
51
|
+
# However, you should not overwrite this method, you should overwrite active? and
|
|
52
|
+
# inactive_message instead.
|
|
53
|
+
def valid_for_authentication?
|
|
54
|
+
if active?
|
|
55
|
+
block_given? ? yield : true
|
|
56
|
+
else
|
|
57
|
+
inactive_message
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def active?
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def inactive_message
|
|
66
|
+
:inactive
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
module ClassMethods
|
|
70
|
+
Devise::Models.config(self, :authentication_keys, :http_authenticatable, :params_authenticatable)
|
|
71
|
+
|
|
72
|
+
def params_authenticatable?(strategy)
|
|
73
|
+
params_authenticatable.is_a?(Array) ?
|
|
74
|
+
params_authenticatable.include?(strategy) : params_authenticatable
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def http_authenticatable?(strategy)
|
|
78
|
+
http_authenticatable.is_a?(Array) ?
|
|
79
|
+
http_authenticatable.include?(strategy) : http_authenticatable
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Find first record based on conditions given (ie by the sign in form).
|
|
83
|
+
# Overwrite to add customized conditions, create a join, or maybe use a
|
|
84
|
+
# namedscope to filter records while authenticating.
|
|
85
|
+
# Example:
|
|
86
|
+
#
|
|
87
|
+
# def self.find_for_authentication(conditions={})
|
|
88
|
+
# conditions[:active] = true
|
|
89
|
+
# super
|
|
90
|
+
# end
|
|
91
|
+
#
|
|
92
|
+
def find_for_authentication(conditions)
|
|
93
|
+
find(:first, :conditions => conditions)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Find an initialize a record setting an error if it can't be found.
|
|
97
|
+
def find_or_initialize_with_error_by(attribute, value, error=:invalid) #:nodoc:
|
|
98
|
+
if value.present?
|
|
99
|
+
conditions = { attribute => value }
|
|
100
|
+
record = find(:first, :conditions => conditions)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
unless record
|
|
104
|
+
record = new
|
|
105
|
+
if value.present?
|
|
106
|
+
record.send(:"#{attribute}=", value)
|
|
107
|
+
else
|
|
108
|
+
error = :blank
|
|
109
|
+
end
|
|
110
|
+
record.errors.add(attribute, error)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
record
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Generate a token by looping and ensuring does not already exist.
|
|
117
|
+
def generate_token(column)
|
|
118
|
+
loop do
|
|
119
|
+
token = Devise.friendly_token
|
|
120
|
+
break token unless find(:first, :conditions => { column => token })
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
require 'devise/models/activatable'
|
|
2
|
-
|
|
3
1
|
module Devise
|
|
4
2
|
module Models
|
|
5
|
-
|
|
6
3
|
# Confirmable is responsible to verify if an account is already confirmed to
|
|
7
4
|
# sign in, and to send emails with confirmation instructions.
|
|
8
5
|
# Confirmation instructions are sent to the user email after creating a
|
|
@@ -29,15 +26,11 @@ module Devise
|
|
|
29
26
|
# User.find(1).send_confirmation_instructions # manually send instructions
|
|
30
27
|
# User.find(1).resend_confirmation! # generates a new token and resent it
|
|
31
28
|
module Confirmable
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def self.included(base)
|
|
35
|
-
base.class_eval do
|
|
36
|
-
extend ClassMethods
|
|
29
|
+
extend ActiveSupport::Concern
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
included do
|
|
32
|
+
before_create :generate_confirmation_token, :if => :confirmation_required?
|
|
33
|
+
after_create :send_confirmation_instructions, :if => :confirmation_required?
|
|
41
34
|
end
|
|
42
35
|
|
|
43
36
|
# Confirm a user by setting it's confirmed_at to actual time. If the user
|
|
@@ -46,19 +39,19 @@ module Devise
|
|
|
46
39
|
unless_confirmed do
|
|
47
40
|
self.confirmation_token = nil
|
|
48
41
|
self.confirmed_at = Time.now
|
|
49
|
-
save(false)
|
|
42
|
+
save(:validate => false)
|
|
50
43
|
end
|
|
51
44
|
end
|
|
52
45
|
|
|
53
46
|
# Verifies whether a user is confirmed or not
|
|
54
47
|
def confirmed?
|
|
55
|
-
|
|
48
|
+
!!confirmed_at
|
|
56
49
|
end
|
|
57
50
|
|
|
58
51
|
# Send confirmation instructions by email
|
|
59
52
|
def send_confirmation_instructions
|
|
60
53
|
generate_confirmation_token! if self.confirmation_token.nil?
|
|
61
|
-
::
|
|
54
|
+
::Devise.mailer.confirmation_instructions(self).deliver
|
|
62
55
|
end
|
|
63
56
|
|
|
64
57
|
# Resend confirmation token. This method does not need to generate a new token.
|
|
@@ -82,15 +75,14 @@ module Devise
|
|
|
82
75
|
# If you don't want confirmation to be sent on create, neither a code
|
|
83
76
|
# to be generated, call skip_confirmation!
|
|
84
77
|
def skip_confirmation!
|
|
85
|
-
self.confirmed_at
|
|
86
|
-
@skip_confirmation = true
|
|
78
|
+
self.confirmed_at = Time.now
|
|
87
79
|
end
|
|
88
80
|
|
|
89
81
|
protected
|
|
90
82
|
|
|
91
83
|
# Callback to overwrite if confirmation is required or not.
|
|
92
84
|
def confirmation_required?
|
|
93
|
-
|
|
85
|
+
!confirmed?
|
|
94
86
|
end
|
|
95
87
|
|
|
96
88
|
# Checks if the confirmation for the user is within the limit time.
|
|
@@ -122,7 +114,7 @@ module Devise
|
|
|
122
114
|
unless confirmed?
|
|
123
115
|
yield
|
|
124
116
|
else
|
|
125
|
-
self.
|
|
117
|
+
self.errors.add(:email, :already_confirmed)
|
|
126
118
|
false
|
|
127
119
|
end
|
|
128
120
|
end
|
|
@@ -131,12 +123,12 @@ module Devise
|
|
|
131
123
|
# this token is being generated
|
|
132
124
|
def generate_confirmation_token
|
|
133
125
|
self.confirmed_at = nil
|
|
134
|
-
self.confirmation_token =
|
|
126
|
+
self.confirmation_token = self.class.confirmation_token
|
|
135
127
|
self.confirmation_sent_at = Time.now.utc
|
|
136
128
|
end
|
|
137
129
|
|
|
138
130
|
def generate_confirmation_token!
|
|
139
|
-
generate_confirmation_token && save(false)
|
|
131
|
+
generate_confirmation_token && save(:validate => false)
|
|
140
132
|
end
|
|
141
133
|
|
|
142
134
|
module ClassMethods
|
|
@@ -146,7 +138,7 @@ module Devise
|
|
|
146
138
|
# Options must contain the user email
|
|
147
139
|
def send_confirmation_instructions(attributes={})
|
|
148
140
|
confirmable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
|
149
|
-
confirmable.resend_confirmation_token
|
|
141
|
+
confirmable.resend_confirmation_token if confirmable.persisted?
|
|
150
142
|
confirmable
|
|
151
143
|
end
|
|
152
144
|
|
|
@@ -156,10 +148,15 @@ module Devise
|
|
|
156
148
|
# Options must have the confirmation_token
|
|
157
149
|
def confirm_by_token(confirmation_token)
|
|
158
150
|
confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
|
|
159
|
-
confirmable.confirm!
|
|
151
|
+
confirmable.confirm! if confirmable.persisted?
|
|
160
152
|
confirmable
|
|
161
153
|
end
|
|
162
154
|
|
|
155
|
+
# Generate a token checking if one does not already exist in the database.
|
|
156
|
+
def confirmation_token
|
|
157
|
+
generate_token(:confirmation_token)
|
|
158
|
+
end
|
|
159
|
+
|
|
163
160
|
Devise::Models.config(self, :confirm_within)
|
|
164
161
|
end
|
|
165
162
|
end
|
|
@@ -19,27 +19,16 @@ module Devise
|
|
|
19
19
|
#
|
|
20
20
|
# encryptor: the encryptor going to be used. By default :sha1.
|
|
21
21
|
#
|
|
22
|
-
# authentication_keys: parameters used for authentication. By default [:email]
|
|
23
|
-
#
|
|
24
22
|
# Examples:
|
|
25
23
|
#
|
|
26
|
-
# User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
|
|
27
24
|
# User.find(1).valid_password?('password123') # returns true/false
|
|
28
25
|
#
|
|
29
26
|
module DatabaseAuthenticatable
|
|
30
|
-
|
|
31
|
-
base.class_eval do
|
|
32
|
-
extend ClassMethods
|
|
33
|
-
|
|
34
|
-
attr_reader :password, :current_password
|
|
35
|
-
attr_accessor :password_confirmation
|
|
36
|
-
end
|
|
37
|
-
end
|
|
27
|
+
extend ActiveSupport::Concern
|
|
38
28
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@old_password
|
|
29
|
+
included do
|
|
30
|
+
attr_reader :password, :current_password
|
|
31
|
+
attr_accessor :password_confirmation
|
|
43
32
|
end
|
|
44
33
|
|
|
45
34
|
# Regenerates password salt and encrypted password each time password is set,
|
|
@@ -48,19 +37,14 @@ module Devise
|
|
|
48
37
|
@password = new_password
|
|
49
38
|
|
|
50
39
|
if @password.present?
|
|
51
|
-
self.password_salt = self.class.
|
|
40
|
+
self.password_salt = self.class.password_salt
|
|
52
41
|
self.encrypted_password = password_digest(@password)
|
|
53
42
|
end
|
|
54
43
|
end
|
|
55
44
|
|
|
56
45
|
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
|
57
46
|
def valid_password?(incoming_password)
|
|
58
|
-
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Checks if a resource is valid upon authentication.
|
|
62
|
-
def valid_for_authentication?(attributes)
|
|
63
|
-
valid_password?(attributes[:password])
|
|
47
|
+
password_digest(incoming_password) == self.encrypted_password
|
|
64
48
|
end
|
|
65
49
|
|
|
66
50
|
# Set password and password confirmation to nil
|
|
@@ -82,61 +66,43 @@ module Devise
|
|
|
82
66
|
result = if valid_password?(current_password)
|
|
83
67
|
update_attributes(params)
|
|
84
68
|
else
|
|
85
|
-
|
|
86
|
-
self.class.add_error_on(self, :current_password, message, false)
|
|
69
|
+
self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
|
|
87
70
|
self.attributes = params
|
|
88
71
|
false
|
|
89
72
|
end
|
|
90
73
|
|
|
91
|
-
clean_up_passwords
|
|
74
|
+
clean_up_passwords
|
|
92
75
|
result
|
|
93
76
|
end
|
|
94
77
|
|
|
95
|
-
|
|
78
|
+
def after_database_authentication
|
|
79
|
+
end
|
|
96
80
|
|
|
97
|
-
|
|
98
|
-
# Passwords are always required if it's a new record, or if the password
|
|
99
|
-
# or confirmation are being set somewhere.
|
|
100
|
-
def password_required?
|
|
101
|
-
new_record? || !password.nil? || !password_confirmation.nil?
|
|
102
|
-
end
|
|
81
|
+
protected
|
|
103
82
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
83
|
+
# Digests the password using the configured encryptor.
|
|
84
|
+
def password_digest(password)
|
|
85
|
+
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
|
86
|
+
end
|
|
108
87
|
|
|
109
88
|
module ClassMethods
|
|
110
|
-
Devise::Models.config(self, :pepper, :stretches, :encryptor
|
|
111
|
-
|
|
112
|
-
# Authenticate a user based on configured attribute keys. Returns the
|
|
113
|
-
# authenticated user if it's valid or nil.
|
|
114
|
-
def authenticate(attributes={})
|
|
115
|
-
return unless authentication_keys.all? { |k| attributes[k].present? }
|
|
116
|
-
conditions = attributes.slice(*authentication_keys)
|
|
117
|
-
resource = find_for_authentication(conditions)
|
|
118
|
-
resource if resource.try(:valid_for_authentication?, attributes)
|
|
119
|
-
end
|
|
89
|
+
Devise::Models.config(self, :pepper, :stretches, :encryptor)
|
|
120
90
|
|
|
121
91
|
# Returns the class for the configured encryptor.
|
|
122
92
|
def encryptor_class
|
|
123
93
|
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
|
|
124
94
|
end
|
|
125
95
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
# end
|
|
137
|
-
#
|
|
138
|
-
def find_for_authentication(conditions)
|
|
139
|
-
find(:first, :conditions => conditions)
|
|
96
|
+
def password_salt
|
|
97
|
+
self.encryptor_class.salt(self.stretches)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# We assume this method already gets the sanitized values from the
|
|
101
|
+
# DatabaseAuthenticatable strategy. If you are using this method on
|
|
102
|
+
# your own, be sure to sanitize the conditions hash to only include
|
|
103
|
+
# the proper fields.
|
|
104
|
+
def find_for_database_authentication(conditions)
|
|
105
|
+
find_for_authentication(conditions)
|
|
140
106
|
end
|
|
141
107
|
end
|
|
142
108
|
end
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
require 'devise/models/activatable'
|
|
2
|
-
|
|
3
1
|
module Devise
|
|
4
2
|
module Models
|
|
5
|
-
|
|
6
3
|
# Handles blocking a user access after a certain number of attempts.
|
|
7
4
|
# Lockable accepts two different strategies to unlock a user after it's
|
|
8
5
|
# blocked: email and time. The former will send an email to the user when
|
|
@@ -13,39 +10,35 @@ module Devise
|
|
|
13
10
|
# Configuration:
|
|
14
11
|
#
|
|
15
12
|
# maximum_attempts: how many attempts should be accepted before blocking the user.
|
|
16
|
-
#
|
|
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.
|
|
17
15
|
# unlock_in: the time you want to lock the user after to lock happens. Only
|
|
18
16
|
# available when unlock_strategy is :time or :both.
|
|
19
17
|
#
|
|
20
18
|
module Lockable
|
|
21
|
-
|
|
19
|
+
extend ActiveSupport::Concern
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
base.class_eval do
|
|
25
|
-
extend ClassMethods
|
|
26
|
-
end
|
|
27
|
-
end
|
|
21
|
+
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
|
|
28
22
|
|
|
29
23
|
# Lock an user setting it's locked_at to actual time.
|
|
30
24
|
def lock_access!
|
|
31
|
-
return true if access_locked?
|
|
32
25
|
self.locked_at = Time.now
|
|
33
26
|
|
|
34
|
-
if
|
|
27
|
+
if unlock_strategy_enabled?(:email)
|
|
35
28
|
generate_unlock_token
|
|
36
29
|
send_unlock_instructions
|
|
37
30
|
end
|
|
38
31
|
|
|
39
|
-
save(false)
|
|
32
|
+
save(:validate => false)
|
|
40
33
|
end
|
|
41
34
|
|
|
42
35
|
# Unlock an user by cleaning locket_at and failed_attempts.
|
|
43
36
|
def unlock_access!
|
|
44
37
|
if_access_locked do
|
|
45
38
|
self.locked_at = nil
|
|
46
|
-
self.failed_attempts = 0
|
|
47
|
-
self.unlock_token = nil
|
|
48
|
-
save(false)
|
|
39
|
+
self.failed_attempts = 0 if respond_to?(:failed_attempts=)
|
|
40
|
+
self.unlock_token = nil if respond_to?(:unlock_token=)
|
|
41
|
+
save(:validate => false)
|
|
49
42
|
end
|
|
50
43
|
end
|
|
51
44
|
|
|
@@ -56,7 +49,7 @@ module Devise
|
|
|
56
49
|
|
|
57
50
|
# Send unlock instructions by email
|
|
58
51
|
def send_unlock_instructions
|
|
59
|
-
::
|
|
52
|
+
::Devise.mailer.unlock_instructions(self).deliver
|
|
60
53
|
end
|
|
61
54
|
|
|
62
55
|
# Resend the unlock instructions if the user is locked.
|
|
@@ -79,27 +72,40 @@ module Devise
|
|
|
79
72
|
# Overwrites valid_for_authentication? from Devise::Models::Authenticatable
|
|
80
73
|
# for verifying whether an user is allowed to sign in or not. If the user
|
|
81
74
|
# is locked, it should never be allowed.
|
|
82
|
-
def valid_for_authentication?
|
|
83
|
-
|
|
75
|
+
def valid_for_authentication?
|
|
76
|
+
return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
|
|
77
|
+
|
|
78
|
+
case (result = super)
|
|
79
|
+
when Symbol
|
|
80
|
+
return result
|
|
81
|
+
when TrueClass
|
|
84
82
|
self.failed_attempts = 0
|
|
85
|
-
|
|
83
|
+
when FalseClass
|
|
86
84
|
self.failed_attempts += 1
|
|
87
|
-
|
|
85
|
+
if attempts_exceeded?
|
|
86
|
+
lock_access!
|
|
87
|
+
return :locked
|
|
88
|
+
end
|
|
88
89
|
end
|
|
89
|
-
|
|
90
|
+
|
|
91
|
+
save(:validate => false) if changed?
|
|
90
92
|
result
|
|
91
93
|
end
|
|
92
94
|
|
|
93
95
|
protected
|
|
94
96
|
|
|
97
|
+
def attempts_exceeded?
|
|
98
|
+
self.failed_attempts > self.class.maximum_attempts
|
|
99
|
+
end
|
|
100
|
+
|
|
95
101
|
# Generates unlock token
|
|
96
102
|
def generate_unlock_token
|
|
97
|
-
self.unlock_token =
|
|
103
|
+
self.unlock_token = self.class.unlock_token
|
|
98
104
|
end
|
|
99
105
|
|
|
100
106
|
# Tells if the lock is expired if :time unlock strategy is active
|
|
101
107
|
def lock_expired?
|
|
102
|
-
if
|
|
108
|
+
if unlock_strategy_enabled?(:time)
|
|
103
109
|
locked_at && locked_at < self.class.unlock_in.ago
|
|
104
110
|
else
|
|
105
111
|
false
|
|
@@ -112,7 +118,7 @@ module Devise
|
|
|
112
118
|
if access_locked?
|
|
113
119
|
yield
|
|
114
120
|
else
|
|
115
|
-
self.
|
|
121
|
+
self.errors.add(:email, :not_locked)
|
|
116
122
|
false
|
|
117
123
|
end
|
|
118
124
|
end
|
|
@@ -124,7 +130,7 @@ module Devise
|
|
|
124
130
|
# Options must contain the user email
|
|
125
131
|
def send_unlock_instructions(attributes={})
|
|
126
132
|
lockable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
|
|
127
|
-
lockable.resend_unlock_token
|
|
133
|
+
lockable.resend_unlock_token if lockable.persisted?
|
|
128
134
|
lockable
|
|
129
135
|
end
|
|
130
136
|
|
|
@@ -134,7 +140,7 @@ module Devise
|
|
|
134
140
|
# Options must have the unlock_token
|
|
135
141
|
def unlock_access_by_token(unlock_token)
|
|
136
142
|
lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
|
|
137
|
-
lockable.unlock_access!
|
|
143
|
+
lockable.unlock_access! if lockable.persisted?
|
|
138
144
|
lockable
|
|
139
145
|
end
|
|
140
146
|
|
|
@@ -143,7 +149,16 @@ module Devise
|
|
|
143
149
|
[:both, strategy].include?(self.unlock_strategy)
|
|
144
150
|
end
|
|
145
151
|
|
|
146
|
-
|
|
152
|
+
# Is the lock enabled for the given lock strategy?
|
|
153
|
+
def lock_strategy_enabled?(strategy)
|
|
154
|
+
self.lock_strategy == strategy
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def unlock_token
|
|
158
|
+
Devise.friendly_token
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in)
|
|
147
162
|
end
|
|
148
163
|
end
|
|
149
164
|
end
|