devise 3.2.0 → 3.3.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.
Potentially problematic release.
This version of devise might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.travis.yml +18 -3
- data/CHANGELOG.md +82 -9
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +7 -9
- data/Gemfile.lock +102 -96
- data/MIT-LICENSE +1 -1
- data/README.md +94 -42
- data/Rakefile +1 -1
- data/app/controllers/devise/confirmations_controller.rb +5 -3
- data/app/controllers/devise/omniauth_callbacks_controller.rb +2 -2
- data/app/controllers/devise/passwords_controller.rb +5 -3
- data/app/controllers/devise/registrations_controller.rb +26 -10
- data/app/controllers/devise/sessions_controller.rb +39 -14
- data/app/controllers/devise/unlocks_controller.rb +4 -2
- data/app/controllers/devise_controller.rb +6 -6
- data/app/helpers/devise_helper.rb +2 -2
- data/app/views/devise/confirmations/new.html.erb +2 -2
- data/app/views/devise/mailer/confirmation_instructions.html.erb +1 -1
- data/app/views/devise/mailer/reset_password_instructions.html.erb +1 -1
- data/app/views/devise/mailer/unlock_instructions.html.erb +1 -1
- data/app/views/devise/passwords/edit.html.erb +3 -3
- data/app/views/devise/passwords/new.html.erb +2 -2
- data/app/views/devise/registrations/edit.html.erb +6 -6
- data/app/views/devise/registrations/new.html.erb +5 -5
- data/app/views/devise/sessions/new.html.erb +5 -5
- data/app/views/devise/shared/_links.erb +1 -1
- data/app/views/devise/unlocks/new.html.erb +2 -2
- data/config/locales/en.yml +17 -16
- data/devise.gemspec +2 -2
- data/gemfiles/{Gemfile.rails-3.2.x → Gemfile.rails-3.2-stable} +8 -10
- data/gemfiles/Gemfile.rails-3.2-stable.lock +166 -0
- data/gemfiles/Gemfile.rails-4.0-stable +29 -0
- data/gemfiles/Gemfile.rails-4.0-stable.lock +162 -0
- data/gemfiles/Gemfile.rails-head +32 -0
- data/gemfiles/Gemfile.rails-head.lock +190 -0
- data/lib/devise/controllers/helpers.rb +84 -29
- data/lib/devise/controllers/rememberable.rb +3 -3
- data/lib/devise/controllers/scoped_views.rb +1 -1
- data/lib/devise/controllers/sign_in_out.rb +9 -10
- data/lib/devise/controllers/store_location.rb +56 -0
- data/lib/devise/controllers/url_helpers.rb +3 -1
- data/lib/devise/failure_app.rb +12 -10
- data/lib/devise/hooks/activatable.rb +5 -6
- data/lib/devise/hooks/csrf_cleaner.rb +3 -1
- data/lib/devise/hooks/lockable.rb +1 -1
- data/lib/devise/hooks/proxy.rb +2 -2
- data/lib/devise/hooks/rememberable.rb +2 -2
- data/lib/devise/hooks/timeoutable.rb +10 -3
- data/lib/devise/hooks/trackable.rb +1 -1
- data/lib/devise/mailers/helpers.rb +8 -8
- data/lib/devise/mapping.rb +4 -1
- data/lib/devise/models/authenticatable.rb +5 -5
- data/lib/devise/models/confirmable.rb +14 -14
- data/lib/devise/models/database_authenticatable.rb +18 -5
- data/lib/devise/models/lockable.rb +14 -11
- data/lib/devise/models/omniauthable.rb +1 -1
- data/lib/devise/models/recoverable.rb +23 -7
- data/lib/devise/models/rememberable.rb +6 -6
- data/lib/devise/models/timeoutable.rb +2 -2
- data/lib/devise/models/trackable.rb +5 -2
- data/lib/devise/models/validatable.rb +6 -6
- data/lib/devise/modules.rb +10 -10
- data/lib/devise/omniauth/url_helpers.rb +2 -2
- data/lib/devise/orm/active_record.rb +1 -1
- data/lib/devise/orm/mongoid.rb +1 -1
- data/lib/devise/rails/routes.rb +107 -78
- data/lib/devise/rails.rb +7 -1
- data/lib/devise/strategies/authenticatable.rb +11 -4
- data/lib/devise/strategies/base.rb +1 -1
- data/lib/devise/strategies/database_authenticatable.rb +7 -4
- data/lib/devise/test_helpers.rb +2 -2
- data/lib/devise/time_inflector.rb +2 -2
- data/lib/devise/version.rb +1 -1
- data/lib/devise.rb +15 -10
- data/lib/generators/active_record/devise_generator.rb +27 -10
- data/lib/generators/active_record/templates/migration.rb +4 -4
- data/lib/generators/active_record/templates/migration_existing.rb +4 -4
- data/lib/generators/devise/devise_generator.rb +5 -3
- data/lib/generators/devise/install_generator.rb +5 -0
- data/lib/generators/devise/views_generator.rb +31 -18
- data/lib/generators/mongoid/devise_generator.rb +20 -19
- data/lib/generators/templates/README +4 -4
- data/lib/generators/templates/devise.rb +20 -11
- data/lib/generators/templates/markerb/confirmation_instructions.markerb +1 -1
- data/lib/generators/templates/markerb/reset_password_instructions.markerb +1 -1
- data/lib/generators/templates/markerb/unlock_instructions.markerb +1 -1
- data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +2 -2
- data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +4 -4
- data/lib/generators/templates/simple_form_for/passwords/new.html.erb +2 -2
- data/lib/generators/templates/simple_form_for/registrations/edit.html.erb +6 -6
- data/lib/generators/templates/simple_form_for/registrations/new.html.erb +4 -4
- data/lib/generators/templates/simple_form_for/sessions/new.html.erb +4 -4
- data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +2 -2
- data/script/cached-bundle +49 -0
- data/script/s3-put +71 -0
- data/test/controllers/custom_registrations_controller_test.rb +35 -0
- data/test/controllers/helpers_test.rb +89 -31
- data/test/controllers/internal_helpers_test.rb +11 -8
- data/test/controllers/passwords_controller_test.rb +1 -1
- data/test/controllers/sessions_controller_test.rb +29 -25
- data/test/controllers/url_helpers_test.rb +4 -4
- data/test/delegator_test.rb +1 -1
- data/test/devise_test.rb +21 -8
- data/test/failure_app_test.rb +61 -25
- data/test/generators/active_record_generator_test.rb +10 -4
- data/test/generators/devise_generator_test.rb +2 -2
- data/test/generators/mongoid_generator_test.rb +3 -3
- data/test/generators/views_generator_test.rb +30 -1
- data/test/helpers/devise_helper_test.rb +14 -13
- data/test/integration/authenticatable_test.rb +61 -45
- data/test/integration/confirmable_test.rb +95 -55
- data/test/integration/database_authenticatable_test.rb +16 -16
- data/test/integration/http_authenticatable_test.rb +12 -12
- data/test/integration/lockable_test.rb +43 -43
- data/test/integration/omniauthable_test.rb +3 -3
- data/test/integration/recoverable_test.rb +53 -53
- data/test/integration/registerable_test.rb +90 -80
- data/test/integration/rememberable_test.rb +15 -15
- data/test/integration/timeoutable_test.rb +27 -16
- data/test/integration/trackable_test.rb +4 -4
- data/test/mailers/confirmation_instructions_test.rb +7 -7
- data/test/mailers/reset_password_instructions_test.rb +6 -6
- data/test/mailers/unlock_instructions_test.rb +5 -5
- data/test/mapping_test.rb +3 -3
- data/test/models/authenticatable_test.rb +3 -3
- data/test/models/confirmable_test.rb +32 -32
- data/test/models/database_authenticatable_test.rb +32 -27
- data/test/models/lockable_test.rb +57 -33
- data/test/models/recoverable_test.rb +34 -22
- data/test/models/rememberable_test.rb +29 -14
- data/test/models/serializable_test.rb +8 -8
- data/test/models/timeoutable_test.rb +1 -1
- data/test/models/trackable_test.rb +28 -0
- data/test/models/validatable_test.rb +13 -13
- data/test/omniauth/config_test.rb +4 -4
- data/test/omniauth/url_helpers_test.rb +3 -3
- data/test/orm/mongoid.rb +1 -1
- data/test/parameter_sanitizer_test.rb +1 -1
- data/test/rails_app/app/active_record/shim.rb +1 -1
- data/test/rails_app/app/active_record/user_on_engine.rb +7 -0
- data/test/rails_app/app/active_record/user_on_main_app.rb +7 -0
- data/test/rails_app/app/controllers/admins/sessions_controller.rb +1 -1
- data/test/rails_app/app/controllers/admins_controller.rb +1 -1
- data/test/rails_app/app/controllers/application_controller.rb +5 -2
- data/test/rails_app/app/controllers/application_with_fake_engine.rb +30 -0
- data/test/rails_app/app/controllers/custom/registrations_controller.rb +21 -0
- data/test/rails_app/app/controllers/home_controller.rb +1 -1
- data/test/rails_app/app/controllers/publisher/registrations_controller.rb +1 -1
- data/test/rails_app/app/controllers/publisher/sessions_controller.rb +1 -1
- data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +4 -4
- data/test/rails_app/app/controllers/users_controller.rb +6 -6
- data/test/rails_app/app/mailers/users/mailer.rb +4 -4
- data/test/rails_app/app/mongoid/admin.rb +11 -11
- data/test/rails_app/app/mongoid/shim.rb +2 -2
- data/test/rails_app/app/mongoid/user.rb +19 -19
- data/test/rails_app/app/mongoid/user_on_engine.rb +39 -0
- data/test/rails_app/app/mongoid/user_on_main_app.rb +39 -0
- data/test/rails_app/app/views/admins/sessions/new.html.erb +1 -1
- data/test/rails_app/app/views/home/admin_dashboard.html.erb +1 -1
- data/test/rails_app/app/views/home/index.html.erb +1 -1
- data/test/rails_app/app/views/home/join.html.erb +1 -1
- data/test/rails_app/app/views/home/user_dashboard.html.erb +1 -1
- data/test/rails_app/app/views/layouts/application.html.erb +1 -1
- data/test/rails_app/config/application.rb +2 -2
- data/test/rails_app/config/boot.rb +7 -1
- data/test/rails_app/config/environments/development.rb +0 -4
- data/test/rails_app/config/environments/production.rb +0 -4
- data/test/rails_app/config/initializers/devise.rb +7 -5
- data/test/rails_app/config/initializers/secret_token.rb +1 -1
- data/test/rails_app/config/routes.rb +60 -42
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +7 -7
- data/test/rails_app/db/schema.rb +21 -17
- data/test/rails_app/lib/shared_admin.rb +4 -4
- data/test/rails_app/lib/shared_user.rb +1 -1
- data/test/rails_app/lib/shared_user_without_omniauth.rb +13 -0
- data/test/routes_test.rb +72 -58
- data/test/support/action_controller/record_identifier.rb +10 -0
- data/test/support/assertions.rb +2 -3
- data/test/support/helpers.rb +4 -4
- data/test/support/integration.rb +14 -14
- data/test/support/mongoid.yml +6 -0
- data/test/test_helper.rb +2 -7
- data/test/test_helpers_test.rb +25 -35
- data/test/test_models.rb +12 -5
- metadata +53 -38
- data/gemfiles/Gemfile.rails-3.2.x.lock +0 -159
@@ -47,7 +47,9 @@ module Devise
|
|
47
47
|
class_eval <<-URL_HELPERS, __FILE__, __LINE__ + 1
|
48
48
|
def #{method}(resource_or_scope, *args)
|
49
49
|
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
50
|
-
|
50
|
+
router_name = Devise.mappings[scope].router_name
|
51
|
+
context = router_name ? send(router_name) : _devise_route_context
|
52
|
+
context.send("#{action}\#{scope}_#{module_name}_#{path_or_url}", *args)
|
51
53
|
end
|
52
54
|
URL_HELPERS
|
53
55
|
end
|
data/lib/devise/failure_app.rb
CHANGED
@@ -13,7 +13,9 @@ module Devise
|
|
13
13
|
include Rails.application.routes.url_helpers
|
14
14
|
include Rails.application.routes.mounted_helpers
|
15
15
|
|
16
|
-
|
16
|
+
include Devise::Controllers::StoreLocation
|
17
|
+
|
18
|
+
delegate :flash, to: :request
|
17
19
|
|
18
20
|
def self.call(env)
|
19
21
|
@respond ||= action(:respond)
|
@@ -94,15 +96,15 @@ module Devise
|
|
94
96
|
request.referrer
|
95
97
|
end
|
96
98
|
|
97
|
-
path ||
|
99
|
+
path || scope_url
|
98
100
|
else
|
99
|
-
|
101
|
+
scope_url
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
103
|
-
def
|
105
|
+
def scope_url
|
104
106
|
opts = {}
|
105
|
-
route = :"new_#{scope}
|
107
|
+
route = :"new_#{scope}_session_url"
|
106
108
|
opts[:format] = request_format unless skip_format?
|
107
109
|
|
108
110
|
config = Rails.application.config
|
@@ -112,8 +114,8 @@ module Devise
|
|
112
114
|
|
113
115
|
if context.respond_to?(route)
|
114
116
|
context.send(route, opts)
|
115
|
-
elsif respond_to?(:
|
116
|
-
|
117
|
+
elsif respond_to?(:root_url)
|
118
|
+
root_url(opts)
|
117
119
|
else
|
118
120
|
"/"
|
119
121
|
end
|
@@ -149,9 +151,9 @@ module Devise
|
|
149
151
|
return i18n_message unless request_format
|
150
152
|
method = "to_#{request_format}"
|
151
153
|
if method == "to_xml"
|
152
|
-
{ :
|
154
|
+
{ error: i18n_message }.to_xml(root: "errors")
|
153
155
|
elsif {}.respond_to?(method)
|
154
|
-
{ :
|
156
|
+
{ error: i18n_message }.send(method)
|
155
157
|
else
|
156
158
|
i18n_message
|
157
159
|
end
|
@@ -189,7 +191,7 @@ module Devise
|
|
189
191
|
# yet, but we still need to store the uri based on scope, so different scopes
|
190
192
|
# would never use the same uri to redirect.
|
191
193
|
def store_location!
|
192
|
-
|
194
|
+
store_location_for(scope, attempted_path) if request.get? && !http_auth?
|
193
195
|
end
|
194
196
|
|
195
197
|
def is_navigational_format?
|
@@ -1,11 +1,10 @@
|
|
1
|
-
# Deny user access whenever
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# in each request and in case the user is using other strategies beside Devise ones.
|
1
|
+
# Deny user access whenever their account is not active yet.
|
2
|
+
# We need this as hook to validate the user activity on each request
|
3
|
+
# and in case the user is using other strategies beside Devise ones.
|
5
4
|
Warden::Manager.after_set_user do |record, warden, options|
|
6
5
|
if record && record.respond_to?(:active_for_authentication?) && !record.active_for_authentication?
|
7
6
|
scope = options[:scope]
|
8
7
|
warden.logout(scope)
|
9
|
-
throw :warden, :
|
8
|
+
throw :warden, scope: scope, message: record.inactive_message
|
10
9
|
end
|
11
|
-
end
|
10
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
Warden::Manager.after_authentication do |record, warden, options|
|
2
|
-
|
2
|
+
clean_up_for_winning_strategy = !warden.winning_strategy.respond_to?(:clean_up_csrf?) ||
|
3
|
+
warden.winning_strategy.clean_up_csrf?
|
4
|
+
if Devise.clean_up_csrf_token_on_authentication && clean_up_for_winning_strategy
|
3
5
|
warden.request.session.try(:delete, :_csrf_token)
|
4
6
|
end
|
5
7
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# After each sign in, if resource responds to failed_attempts, sets it to 0
|
2
2
|
# This is only triggered when the user is explicitly set (with set_user)
|
3
|
-
Warden::Manager.after_set_user :
|
3
|
+
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
4
4
|
if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope])
|
5
5
|
record.update_attribute(:failed_attempts, 0) unless record.failed_attempts.to_i.zero?
|
6
6
|
end
|
data/lib/devise/hooks/proxy.rb
CHANGED
@@ -7,7 +7,7 @@ module Devise
|
|
7
7
|
include Devise::Controllers::SignInOut
|
8
8
|
|
9
9
|
attr_reader :warden
|
10
|
-
delegate :cookies, :env, :
|
10
|
+
delegate :cookies, :env, to: :warden
|
11
11
|
|
12
12
|
def initialize(warden)
|
13
13
|
@warden = warden
|
@@ -18,4 +18,4 @@ module Devise
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
Warden::Manager.after_set_user :
|
1
|
+
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
2
2
|
scope = options[:scope]
|
3
3
|
if record.respond_to?(:remember_me) && options[:store] != false &&
|
4
4
|
record.remember_me && warden.authenticated?(scope)
|
5
5
|
Devise::Hooks::Proxy.new(warden).remember_me(record)
|
6
6
|
end
|
7
|
-
end
|
7
|
+
end
|
@@ -9,20 +9,27 @@ Warden::Manager.after_set_user do |record, warden, options|
|
|
9
9
|
|
10
10
|
if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) && options[:store] != false
|
11
11
|
last_request_at = warden.session(scope)['last_request_at']
|
12
|
+
|
13
|
+
if last_request_at.is_a? Integer
|
14
|
+
last_request_at = Time.at(last_request_at).utc
|
15
|
+
elsif last_request_at.is_a? String
|
16
|
+
last_request_at = Time.parse(last_request_at)
|
17
|
+
end
|
18
|
+
|
12
19
|
proxy = Devise::Hooks::Proxy.new(warden)
|
13
20
|
|
14
21
|
if record.timedout?(last_request_at) && !env['devise.skip_timeout']
|
15
|
-
Devise.sign_out_all_scopes ? proxy.sign_out : sign_out(scope)
|
22
|
+
Devise.sign_out_all_scopes ? proxy.sign_out : proxy.sign_out(scope)
|
16
23
|
|
17
24
|
if record.respond_to?(:expire_auth_token_on_timeout) && record.expire_auth_token_on_timeout
|
18
25
|
record.reset_authentication_token!
|
19
26
|
end
|
20
27
|
|
21
|
-
throw :warden, :
|
28
|
+
throw :warden, scope: scope, message: :timeout
|
22
29
|
end
|
23
30
|
|
24
31
|
unless env['devise.skip_trackable']
|
25
|
-
warden.session(scope)['last_request_at'] = Time.now.utc
|
32
|
+
warden.session(scope)['last_request_at'] = Time.now.utc.to_i
|
26
33
|
end
|
27
34
|
end
|
28
35
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# This is only triggered when the user is explicitly set (with set_user)
|
3
3
|
# and on authentication. Retrieving the user from session (:fetch) does
|
4
4
|
# not trigger it.
|
5
|
-
Warden::Manager.after_set_user :
|
5
|
+
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
6
6
|
if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable']
|
7
7
|
record.update_tracked_fields!(warden.request)
|
8
8
|
end
|
@@ -27,12 +27,12 @@ module Devise
|
|
27
27
|
|
28
28
|
def headers_for(action, opts)
|
29
29
|
headers = {
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
30
|
+
subject: subject_for(action),
|
31
|
+
to: resource.email,
|
32
|
+
from: mailer_sender(devise_mapping),
|
33
|
+
reply_to: mailer_reply_to(devise_mapping),
|
34
|
+
template_path: template_paths,
|
35
|
+
template_name: action
|
36
36
|
}.merge(opts)
|
37
37
|
|
38
38
|
@email = headers[:to]
|
@@ -82,8 +82,8 @@ module Devise
|
|
82
82
|
# subject: '...'
|
83
83
|
#
|
84
84
|
def subject_for(key)
|
85
|
-
I18n.t(:"#{devise_mapping.name}_subject", :
|
86
|
-
:
|
85
|
+
I18n.t(:"#{devise_mapping.name}_subject", scope: [:devise, :mailer, key],
|
86
|
+
default: [:subject, key.to_s.humanize])
|
87
87
|
end
|
88
88
|
end
|
89
89
|
end
|
data/lib/devise/mapping.rb
CHANGED
@@ -23,7 +23,8 @@ module Devise
|
|
23
23
|
#
|
24
24
|
class Mapping #:nodoc:
|
25
25
|
attr_reader :singular, :scoped_path, :path, :controllers, :path_names,
|
26
|
-
:class_name, :sign_out_via, :format, :used_routes, :used_helpers,
|
26
|
+
:class_name, :sign_out_via, :format, :used_routes, :used_helpers,
|
27
|
+
:failure_app, :router_name
|
27
28
|
|
28
29
|
alias :name :singular
|
29
30
|
|
@@ -60,6 +61,8 @@ module Devise
|
|
60
61
|
@sign_out_via = options[:sign_out_via] || Devise.sign_out_via
|
61
62
|
@format = options[:format]
|
62
63
|
|
64
|
+
@router_name = options[:router_name]
|
65
|
+
|
63
66
|
default_failure_app(options)
|
64
67
|
default_controllers(options)
|
65
68
|
default_path_names(options)
|
@@ -29,7 +29,7 @@ module Devise
|
|
29
29
|
# It also accepts an array specifying the strategies that should allow params authentication.
|
30
30
|
#
|
31
31
|
# * +skip_session_storage+: By default Devise will store the user in session.
|
32
|
-
# By default is set to :
|
32
|
+
# By default is set to skip_session_storage: [:http_auth].
|
33
33
|
#
|
34
34
|
# == active_for_authentication?
|
35
35
|
#
|
@@ -56,10 +56,10 @@ module Devise
|
|
56
56
|
BLACKLIST_FOR_SERIALIZATION = [:encrypted_password, :reset_password_token, :reset_password_sent_at,
|
57
57
|
:remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
|
58
58
|
:last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
|
59
|
-
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at
|
59
|
+
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]
|
60
60
|
|
61
61
|
included do
|
62
|
-
class_attribute :devise_modules, :
|
62
|
+
class_attribute :devise_modules, instance_writer: false
|
63
63
|
self.devise_modules ||= []
|
64
64
|
|
65
65
|
before_validation :downcase_keys
|
@@ -127,7 +127,7 @@ module Devise
|
|
127
127
|
end
|
128
128
|
|
129
129
|
# This is an internal method called every time Devise needs
|
130
|
-
# to send a notification/mail. This can be
|
130
|
+
# to send a notification/mail. This can be overridden if you
|
131
131
|
# need to customize the e-mail delivery logic. For instance,
|
132
132
|
# if you are using a queue to deliver e-mails (delayed job,
|
133
133
|
# sidekiq, resque, etc), you must add the delivery to the queue
|
@@ -231,7 +231,7 @@ module Devise
|
|
231
231
|
# Example:
|
232
232
|
#
|
233
233
|
# def self.find_for_authentication(tainted_conditions)
|
234
|
-
# find_first_by_auth_conditions(tainted_conditions, :
|
234
|
+
# find_first_by_auth_conditions(tainted_conditions, active: true)
|
235
235
|
# end
|
236
236
|
#
|
237
237
|
# Finally, notice that Devise also queries for users in other scenarios
|
@@ -9,7 +9,7 @@ module Devise
|
|
9
9
|
#
|
10
10
|
# Confirmable adds the following options to +devise+:
|
11
11
|
#
|
12
|
-
# * +allow_unconfirmed_access_for+: the time you want to allow the user to access
|
12
|
+
# * +allow_unconfirmed_access_for+: the time you want to allow the user to access their account
|
13
13
|
# before confirming it. After this period, the user access is denied. You can
|
14
14
|
# use this to let your user access some features of your application without
|
15
15
|
# confirming the account, but blocking it after a certain period (ie 7 days).
|
@@ -33,10 +33,10 @@ module Devise
|
|
33
33
|
include ActionView::Helpers::DateHelper
|
34
34
|
|
35
35
|
included do
|
36
|
-
before_create :generate_confirmation_token, :
|
37
|
-
after_create :send_on_create_confirmation_instructions, :
|
38
|
-
before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, :
|
39
|
-
after_update :send_reconfirmation_instructions, :
|
36
|
+
before_create :generate_confirmation_token, if: :confirmation_required?
|
37
|
+
after_create :send_on_create_confirmation_instructions, if: :send_confirmation_notification?
|
38
|
+
before_update :postpone_email_change_until_confirmation_and_regenerate_confirmation_token, if: :postpone_email_change?
|
39
|
+
after_update :send_reconfirmation_instructions, if: :reconfirmation_required?
|
40
40
|
end
|
41
41
|
|
42
42
|
def initialize(*args, &block)
|
@@ -60,7 +60,7 @@ module Devise
|
|
60
60
|
pending_any_confirmation do
|
61
61
|
if confirmation_period_expired?
|
62
62
|
self.errors.add(:email, :confirmation_period_expired,
|
63
|
-
:
|
63
|
+
period: Devise::TimeInflector.time_ago_in_words(self.class.confirm_within.ago))
|
64
64
|
return false
|
65
65
|
end
|
66
66
|
|
@@ -73,9 +73,9 @@ module Devise
|
|
73
73
|
self.unconfirmed_email = nil
|
74
74
|
|
75
75
|
# We need to validate in such cases to enforce e-mail uniqueness
|
76
|
-
save(:
|
76
|
+
save(validate: true)
|
77
77
|
else
|
78
|
-
save(:
|
78
|
+
save(validate: false)
|
79
79
|
end
|
80
80
|
|
81
81
|
after_confirmation if saved
|
@@ -98,7 +98,7 @@ module Devise
|
|
98
98
|
generate_confirmation_token!
|
99
99
|
end
|
100
100
|
|
101
|
-
opts = pending_reconfirmation? ? { :
|
101
|
+
opts = pending_reconfirmation? ? { to: unconfirmed_email } : { }
|
102
102
|
send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
|
103
103
|
end
|
104
104
|
|
@@ -152,7 +152,7 @@ module Devise
|
|
152
152
|
protected
|
153
153
|
|
154
154
|
# A callback method used to deliver confirmation
|
155
|
-
# instructions on creation. This can be
|
155
|
+
# instructions on creation. This can be overridden
|
156
156
|
# in models to map to a nice sign up e-mail.
|
157
157
|
def send_on_create_confirmation_instructions
|
158
158
|
send_confirmation_instructions
|
@@ -225,7 +225,7 @@ module Devise
|
|
225
225
|
end
|
226
226
|
|
227
227
|
def generate_confirmation_token!
|
228
|
-
generate_confirmation_token && save(:
|
228
|
+
generate_confirmation_token && save(validate: false)
|
229
229
|
end
|
230
230
|
|
231
231
|
def postpone_email_change_until_confirmation_and_regenerate_confirmation_token
|
@@ -236,17 +236,17 @@ module Devise
|
|
236
236
|
end
|
237
237
|
|
238
238
|
def postpone_email_change?
|
239
|
-
postpone = self.class.reconfirmable && email_changed? && !@bypass_confirmation_postpone &&
|
239
|
+
postpone = self.class.reconfirmable && email_changed? && !@bypass_confirmation_postpone && self.email.present?
|
240
240
|
@bypass_confirmation_postpone = false
|
241
241
|
postpone
|
242
242
|
end
|
243
243
|
|
244
244
|
def reconfirmation_required?
|
245
|
-
self.class.reconfirmable && @reconfirmation_required &&
|
245
|
+
self.class.reconfirmable && @reconfirmation_required && self.email.present?
|
246
246
|
end
|
247
247
|
|
248
248
|
def send_confirmation_notification?
|
249
|
-
confirmation_required? && !@skip_confirmation_notification &&
|
249
|
+
confirmation_required? && !@skip_confirmation_notification && self.email.present?
|
250
250
|
end
|
251
251
|
|
252
252
|
def after_confirmation
|
@@ -4,7 +4,7 @@ require 'bcrypt'
|
|
4
4
|
module Devise
|
5
5
|
# Digests the password using bcrypt.
|
6
6
|
def self.bcrypt(klass, password)
|
7
|
-
::BCrypt::Password.create("#{password}#{klass.pepper}", :
|
7
|
+
::BCrypt::Password.create("#{password}#{klass.pepper}", cost: klass.stretches).to_s
|
8
8
|
end
|
9
9
|
|
10
10
|
module Models
|
@@ -39,7 +39,7 @@ module Devise
|
|
39
39
|
# Generates password encryption based on the given value.
|
40
40
|
def password=(new_password)
|
41
41
|
@password = new_password
|
42
|
-
self.encrypted_password =
|
42
|
+
self.encrypted_password = password_digest(@password) if @password.present?
|
43
43
|
end
|
44
44
|
|
45
45
|
# Verifies whether an password (ie from sign in) is the user password.
|
@@ -55,9 +55,13 @@ module Devise
|
|
55
55
|
self.password = self.password_confirmation = nil
|
56
56
|
end
|
57
57
|
|
58
|
-
# Update record attributes when :current_password matches, otherwise
|
59
|
-
# error on :current_password.
|
60
|
-
#
|
58
|
+
# Update record attributes when :current_password matches, otherwise
|
59
|
+
# returns error on :current_password.
|
60
|
+
#
|
61
|
+
# This method also rejects the password field if it is blank (allowing
|
62
|
+
# users to change relevant information like the e-mail without changing
|
63
|
+
# their password). In case the password field is rejected, the confirmation
|
64
|
+
# is also rejected as long as it is also blank.
|
61
65
|
def update_with_password(params, *options)
|
62
66
|
current_password = params.delete(:current_password)
|
63
67
|
|
@@ -135,6 +139,15 @@ module Devise
|
|
135
139
|
|
136
140
|
protected
|
137
141
|
|
142
|
+
# Digests the password using bcrypt. Custom encryption should override
|
143
|
+
# this method to apply their own algorithm.
|
144
|
+
#
|
145
|
+
# See https://github.com/plataformatec/devise-encryptable for examples
|
146
|
+
# of other encryption engines.
|
147
|
+
def password_digest(password)
|
148
|
+
Devise.bcrypt(self.class, password)
|
149
|
+
end
|
150
|
+
|
138
151
|
module ClassMethods
|
139
152
|
Devise::Models.config(self, :pepper, :stretches)
|
140
153
|
|
@@ -22,7 +22,7 @@ module Devise
|
|
22
22
|
module Lockable
|
23
23
|
extend ActiveSupport::Concern
|
24
24
|
|
25
|
-
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :
|
25
|
+
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, to: "self.class"
|
26
26
|
|
27
27
|
def self.required_fields(klass)
|
28
28
|
attributes = []
|
@@ -34,13 +34,16 @@ module Devise
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Lock a user setting its locked_at to actual time.
|
37
|
-
|
37
|
+
# * +opts+: Hash options if you don't want to send email
|
38
|
+
# when you lock access, you could pass the next hash
|
39
|
+
# `{ send_instructions: false } as option`.
|
40
|
+
def lock_access!(opts = { })
|
38
41
|
self.locked_at = Time.now.utc
|
39
42
|
|
40
|
-
if unlock_strategy_enabled?(:email)
|
43
|
+
if unlock_strategy_enabled?(:email) && opts.fetch(:send_instructions, true)
|
41
44
|
send_unlock_instructions
|
42
45
|
else
|
43
|
-
save(:
|
46
|
+
save(validate: false)
|
44
47
|
end
|
45
48
|
end
|
46
49
|
|
@@ -49,7 +52,7 @@ module Devise
|
|
49
52
|
self.locked_at = nil
|
50
53
|
self.failed_attempts = 0 if respond_to?(:failed_attempts=)
|
51
54
|
self.unlock_token = nil if respond_to?(:unlock_token=)
|
52
|
-
save(:
|
55
|
+
save(validate: false)
|
53
56
|
end
|
54
57
|
|
55
58
|
# Verifies whether a user is locked or not.
|
@@ -61,7 +64,7 @@ module Devise
|
|
61
64
|
def send_unlock_instructions
|
62
65
|
raw, enc = Devise.token_generator.generate(self.class, :unlock_token)
|
63
66
|
self.unlock_token = enc
|
64
|
-
self.save(:
|
67
|
+
self.save(validate: false)
|
65
68
|
send_devise_notification(:unlock_instructions, raw, {})
|
66
69
|
raw
|
67
70
|
end
|
@@ -101,7 +104,7 @@ module Devise
|
|
101
104
|
if attempts_exceeded?
|
102
105
|
lock_access! unless access_locked?
|
103
106
|
else
|
104
|
-
save(:
|
107
|
+
save(validate: false)
|
105
108
|
end
|
106
109
|
false
|
107
110
|
end
|
@@ -112,10 +115,10 @@ module Devise
|
|
112
115
|
# leaks the existence of an account.
|
113
116
|
if Devise.paranoid
|
114
117
|
super
|
118
|
+
elsif access_locked? || (lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?)
|
119
|
+
:locked
|
115
120
|
elsif lock_strategy_enabled?(:failed_attempts) && last_attempt?
|
116
121
|
:last_attempt
|
117
|
-
elsif lock_strategy_enabled?(:failed_attempts) && attempts_exceeded?
|
118
|
-
:locked
|
119
122
|
else
|
120
123
|
super
|
121
124
|
end
|
@@ -124,11 +127,11 @@ module Devise
|
|
124
127
|
protected
|
125
128
|
|
126
129
|
def attempts_exceeded?
|
127
|
-
self.failed_attempts
|
130
|
+
self.failed_attempts >= self.class.maximum_attempts
|
128
131
|
end
|
129
132
|
|
130
133
|
def last_attempt?
|
131
|
-
self.failed_attempts == self.class.maximum_attempts
|
134
|
+
self.failed_attempts == self.class.maximum_attempts - 1
|
132
135
|
end
|
133
136
|
|
134
137
|
# Tells if the lock is expired if :time unlock strategy is active
|
@@ -10,7 +10,7 @@ module Devise
|
|
10
10
|
#
|
11
11
|
# * +omniauth_providers+: Which providers are available to this model. It expects an array:
|
12
12
|
#
|
13
|
-
# devise_for :database_authenticatable, :omniauthable, :
|
13
|
+
# devise_for :database_authenticatable, :omniauthable, omniauth_providers: [:twitter]
|
14
14
|
#
|
15
15
|
module Omniauthable
|
16
16
|
extend ActiveSupport::Concern
|
@@ -45,14 +45,10 @@ module Devise
|
|
45
45
|
# Resets reset password token and send reset password instructions by email.
|
46
46
|
# Returns the token sent in the e-mail.
|
47
47
|
def send_reset_password_instructions
|
48
|
-
|
48
|
+
token = set_reset_password_token
|
49
|
+
send_reset_password_instructions_notification(token)
|
49
50
|
|
50
|
-
|
51
|
-
self.reset_password_sent_at = Time.now.utc
|
52
|
-
self.save(:validate => false)
|
53
|
-
|
54
|
-
send_devise_notification(:reset_password_instructions, raw, {})
|
55
|
-
raw
|
51
|
+
token
|
56
52
|
end
|
57
53
|
|
58
54
|
# Checks if the reset password token sent is within the limit time.
|
@@ -90,7 +86,27 @@ module Devise
|
|
90
86
|
def after_password_reset
|
91
87
|
end
|
92
88
|
|
89
|
+
def set_reset_password_token
|
90
|
+
raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
|
91
|
+
|
92
|
+
self.reset_password_token = enc
|
93
|
+
self.reset_password_sent_at = Time.now.utc
|
94
|
+
self.save(validate: false)
|
95
|
+
raw
|
96
|
+
end
|
97
|
+
|
98
|
+
def send_reset_password_instructions_notification(token)
|
99
|
+
send_devise_notification(:reset_password_instructions, token, {})
|
100
|
+
end
|
101
|
+
|
93
102
|
module ClassMethods
|
103
|
+
# Attempt to find a user by password reset token. If a user is found, return it
|
104
|
+
# If a user is not found, return nil
|
105
|
+
def with_reset_password_token(token)
|
106
|
+
reset_password_token = Devise.token_generator.digest(self, :reset_password_token, token)
|
107
|
+
to_adapter.find_first(reset_password_token: reset_password_token)
|
108
|
+
end
|
109
|
+
|
94
110
|
# Attempt to find a user by its email. If a record is found, send new
|
95
111
|
# password instructions to it. If user is not found, returns a new user
|
96
112
|
# with an email not found error.
|
@@ -17,7 +17,7 @@ module Devise
|
|
17
17
|
#
|
18
18
|
# * +remember_for+: the time you want the user will be remembered without
|
19
19
|
# asking for credentials. After this time the user will be blocked and
|
20
|
-
# will have to enter
|
20
|
+
# will have to enter their credentials again. This configuration is also
|
21
21
|
# used to calculate the expires time for the cookie created to remember
|
22
22
|
# the user. By default remember_for is 2.weeks.
|
23
23
|
#
|
@@ -50,7 +50,7 @@ module Devise
|
|
50
50
|
def remember_me!(extend_period=false)
|
51
51
|
self.remember_token = self.class.remember_token if generate_remember_token?
|
52
52
|
self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
|
53
|
-
save(:
|
53
|
+
save(validate: false) if self.changed?
|
54
54
|
end
|
55
55
|
|
56
56
|
# If the record is persisted, remove the remember token (but only if
|
@@ -58,8 +58,8 @@ module Devise
|
|
58
58
|
def forget_me!
|
59
59
|
return unless persisted?
|
60
60
|
self.remember_token = nil if respond_to?(:remember_token=)
|
61
|
-
self.remember_created_at = nil
|
62
|
-
save(:
|
61
|
+
self.remember_created_at = nil if self.class.expire_all_remember_me_on_sign_out
|
62
|
+
save(validate: false)
|
63
63
|
end
|
64
64
|
|
65
65
|
# Remember token should be expired if expiration time not overpass now.
|
@@ -118,11 +118,11 @@ module Devise
|
|
118
118
|
def remember_token #:nodoc:
|
119
119
|
loop do
|
120
120
|
token = Devise.friendly_token
|
121
|
-
break token unless to_adapter.find_first({ :
|
121
|
+
break token unless to_adapter.find_first({ remember_token: token })
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
Devise::Models.config(self, :remember_for, :extend_remember_period, :rememberable_options)
|
125
|
+
Devise::Models.config(self, :remember_for, :extend_remember_period, :rememberable_options, :expire_all_remember_me_on_sign_out)
|
126
126
|
end
|
127
127
|
end
|
128
128
|
end
|
@@ -2,9 +2,9 @@ require 'devise/hooks/timeoutable'
|
|
2
2
|
|
3
3
|
module Devise
|
4
4
|
module Models
|
5
|
-
# Timeoutable takes care of
|
5
|
+
# Timeoutable takes care of verifying whether a user session has already
|
6
6
|
# expired or not. When a session expires after the configured time, the user
|
7
|
-
# will be asked for credentials again, it means,
|
7
|
+
# will be asked for credentials again, it means, they will be redirected
|
8
8
|
# to the sign in page.
|
9
9
|
#
|
10
10
|
# == Options
|
@@ -15,7 +15,7 @@ module Devise
|
|
15
15
|
[:current_sign_in_at, :current_sign_in_ip, :last_sign_in_at, :last_sign_in_ip, :sign_in_count]
|
16
16
|
end
|
17
17
|
|
18
|
-
def update_tracked_fields
|
18
|
+
def update_tracked_fields(request)
|
19
19
|
old_current, new_current = self.current_sign_in_at, Time.now.utc
|
20
20
|
self.last_sign_in_at = old_current || new_current
|
21
21
|
self.current_sign_in_at = new_current
|
@@ -26,8 +26,11 @@ module Devise
|
|
26
26
|
|
27
27
|
self.sign_in_count ||= 0
|
28
28
|
self.sign_in_count += 1
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
+
def update_tracked_fields!(request)
|
32
|
+
update_tracked_fields(request)
|
33
|
+
save(validate: false) or raise "Devise trackable could not save #{inspect}." \
|
31
34
|
"Please make sure a model using trackable can be saved at sign in."
|
32
35
|
end
|
33
36
|
end
|
@@ -26,13 +26,13 @@ module Devise
|
|
26
26
|
assert_validations_api!(base)
|
27
27
|
|
28
28
|
base.class_eval do
|
29
|
-
validates_presence_of :email, :
|
30
|
-
validates_uniqueness_of :email, :
|
31
|
-
validates_format_of :email, :
|
29
|
+
validates_presence_of :email, if: :email_required?
|
30
|
+
validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
|
31
|
+
validates_format_of :email, with: email_regexp, allow_blank: true, if: :email_changed?
|
32
32
|
|
33
|
-
validates_presence_of :password, :
|
34
|
-
validates_confirmation_of :password, :
|
35
|
-
validates_length_of :password, :
|
33
|
+
validates_presence_of :password, if: :password_required?
|
34
|
+
validates_confirmation_of :password, if: :password_required?
|
35
|
+
validates_length_of :password, within: password_length, allow_blank: true
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|