devise-security 0.14.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +124 -60
- data/app/controllers/devise/password_expired_controller.rb +11 -6
- data/app/views/devise/paranoid_verification_code/show.html.erb +3 -3
- data/app/views/devise/password_expired/show.html.erb +5 -5
- data/config/locales/by.yml +49 -0
- data/config/locales/cs.yml +41 -0
- data/config/locales/de.yml +13 -2
- data/config/locales/en.yml +13 -1
- data/config/locales/es.yml +10 -9
- data/config/locales/fa.yml +41 -0
- data/config/locales/fr.yml +1 -0
- data/config/locales/hi.yml +42 -0
- data/config/locales/it.yml +35 -4
- data/config/locales/ja.yml +2 -1
- data/config/locales/nl.yml +41 -0
- data/config/locales/pt.yml +41 -0
- data/config/locales/ru.yml +49 -0
- data/config/locales/tr.yml +1 -0
- data/config/locales/uk.yml +49 -0
- data/config/locales/zh_CN.yml +41 -0
- data/config/locales/zh_TW.yml +41 -0
- data/lib/devise-security.rb +7 -3
- data/lib/devise-security/controllers/helpers.rb +59 -50
- data/lib/devise-security/hooks/password_expirable.rb +2 -0
- data/lib/devise-security/hooks/session_limitable.rb +29 -14
- data/lib/devise-security/models/compatibility.rb +2 -2
- data/lib/devise-security/models/compatibility/{active_record.rb → active_record_patch.rb} +12 -1
- data/lib/devise-security/models/compatibility/{mongoid.rb → mongoid_patch.rb} +11 -1
- data/lib/devise-security/models/password_expirable.rb +5 -1
- data/lib/devise-security/models/secure_validatable.rb +15 -1
- data/lib/devise-security/models/session_limitable.rb +17 -2
- data/lib/devise-security/validators/password_complexity_validator.rb +4 -2
- data/lib/devise-security/version.rb +1 -1
- data/lib/generators/devise_security/install_generator.rb +3 -3
- data/lib/generators/templates/devise_security.rb +47 -0
- data/test/{test_captcha_controller.rb → controllers/test_captcha_controller.rb} +0 -0
- data/test/controllers/test_password_expired_controller.rb +110 -0
- data/test/{test_security_question_controller.rb → controllers/test_security_question_controller.rb} +16 -40
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/controllers/widgets_controller.rb +6 -0
- data/test/dummy/app/models/user.rb +8 -0
- data/test/dummy/config/application.rb +1 -0
- data/test/dummy/config/environments/test.rb +3 -13
- data/test/dummy/config/initializers/migration_class.rb +1 -8
- data/test/dummy/config/mongoid.yml +1 -1
- data/test/dummy/config/routes.rb +4 -3
- data/test/dummy/db/migrate/20120508165529_create_tables.rb +10 -1
- data/test/dummy/log/development.log +883 -0
- data/test/dummy/log/test.log +21689 -0
- data/test/integration/test_password_expirable_workflow.rb +53 -0
- data/test/integration/test_session_limitable_workflow.rb +67 -0
- data/test/orm/active_record.rb +4 -1
- data/test/orm/mongoid.rb +2 -1
- data/test/support/integration_helpers.rb +29 -0
- data/test/support/mongoid.yml +1 -1
- data/test/test_compatibility.rb +13 -0
- data/test/test_complexity_validator.rb +12 -0
- data/test/test_helper.rb +21 -6
- data/test/test_install_generator.rb +11 -1
- data/test/test_secure_validatable.rb +76 -0
- data/test/test_session_limitable.rb +57 -0
- data/{lib/generators/templates → test/tmp/config/initializers}/devise-security.rb +3 -0
- data/test/tmp/config/locales/devise.security_extension.by.yml +49 -0
- data/test/tmp/config/locales/devise.security_extension.cs.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.de.yml +39 -0
- data/test/tmp/config/locales/devise.security_extension.en.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.es.yml +30 -0
- data/test/tmp/config/locales/devise.security_extension.fa.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.fr.yml +30 -0
- data/test/tmp/config/locales/devise.security_extension.hi.yml +42 -0
- data/test/tmp/config/locales/devise.security_extension.it.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.ja.yml +30 -0
- data/test/tmp/config/locales/devise.security_extension.nl.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.pt.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.ru.yml +49 -0
- data/test/tmp/config/locales/devise.security_extension.tr.yml +18 -0
- data/test/tmp/config/locales/devise.security_extension.uk.yml +49 -0
- data/test/tmp/config/locales/devise.security_extension.zh_CN.yml +41 -0
- data/test/tmp/config/locales/devise.security_extension.zh_TW.yml +41 -0
- metadata +156 -133
- data/.codeclimate.yml +0 -63
- data/.document +0 -5
- data/.gitignore +0 -43
- data/.mdlrc +0 -1
- data/.rubocop.yml +0 -64
- data/.ruby-version +0 -1
- data/.travis.yml +0 -41
- data/Appraisals +0 -35
- data/Gemfile +0 -10
- data/Rakefile +0 -27
- data/devise-security.gemspec +0 -50
- data/gemfiles/rails_4.2_stable.gemfile +0 -16
- data/gemfiles/rails_5.0_stable.gemfile +0 -15
- data/gemfiles/rails_5.1_stable.gemfile +0 -15
- data/gemfiles/rails_5.2_stable.gemfile +0 -15
- data/gemfiles/rails_6.0_beta.gemfile +0 -15
- data/lib/devise-security/orm/active_record.rb +0 -20
- data/lib/devise-security/schema.rb +0 -66
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/test_password_expired_controller.rb +0 -46
data/config/locales/tr.yml
CHANGED
@@ -3,6 +3,7 @@ tr:
|
|
3
3
|
messages:
|
4
4
|
taken_in_past: "daha önce kullanıldı."
|
5
5
|
equal_to_current_password: "mevcut paroladan farklı olmalı."
|
6
|
+
equal_to_email: "e-postadan farklı olmalı."
|
6
7
|
password_format: "büyük, küçük harfler ve sayılar içermeli."
|
7
8
|
devise:
|
8
9
|
invalid_captcha: "Captcha hatalı."
|
@@ -0,0 +1,49 @@
|
|
1
|
+
uk:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
taken_in_past: 'раніше використовувався.'
|
5
|
+
equal_to_current_password: 'має відрізнятися від поточного паролю.'
|
6
|
+
equal_to_email: 'має відрізнятися від електронної пошти.'
|
7
|
+
password_complexity:
|
8
|
+
digit:
|
9
|
+
one: 'повинен включати хоча б одну цифру'
|
10
|
+
few: 'повинен включати хоча б %{count} цифри'
|
11
|
+
many: 'повинен включати хоча б %{count} цифр'
|
12
|
+
other: 'повинен включати хоча б %{count} цифри'
|
13
|
+
lower:
|
14
|
+
one: 'повинен включати хоча б одну малу букву'
|
15
|
+
few: 'повинен включати хоча б %{count} малі букви'
|
16
|
+
many: 'повинен включати хоча б %{count} малих букв'
|
17
|
+
other: 'повинен включати хоча б %{count} малі букви'
|
18
|
+
symbol:
|
19
|
+
one: 'повинен включати хоча б один розділовий знак або символ'
|
20
|
+
few: 'повинен включати хоча б %{count} розділові знаки або символи'
|
21
|
+
many: 'повинен включати хоча б %{count} розділових знаків або символів'
|
22
|
+
other: 'повинен включати хоча б %{count} розділові знаки або символи'
|
23
|
+
upper:
|
24
|
+
one: 'повинен включати хоча б одну прописну букву'
|
25
|
+
few: 'повинен включати хоча б %{count} прописні букви'
|
26
|
+
many: 'повинен включати хоча б %{count} прописних букв'
|
27
|
+
other: 'повинен включати хоча б %{count} прописні букви'
|
28
|
+
devise:
|
29
|
+
invalid_captcha: 'Введення капчі недійсне.'
|
30
|
+
invalid_security_question: 'Неправильна відповідь на секретне питання.'
|
31
|
+
paranoid_verify:
|
32
|
+
code_required: 'Введіть, будь ласка, код від нашої команди підтримки'
|
33
|
+
paranoid_verification_code:
|
34
|
+
show:
|
35
|
+
submit_verification_code: Відправити код підтвердження
|
36
|
+
verification_code: Код підтвердження
|
37
|
+
submit: Відправити
|
38
|
+
password_expired:
|
39
|
+
updated: 'Ваш новий пароль збережено.'
|
40
|
+
change_required: 'Ваш пароль застарілий. Будь ласка, оновіть пароль.'
|
41
|
+
show:
|
42
|
+
renew_your_password: Оновити свій пароль
|
43
|
+
current_password: Теперішній пароль
|
44
|
+
new_password: Новий пароль
|
45
|
+
new_password_confirmation: Підтвердити новий пароль
|
46
|
+
change_my_password: Змінити пароль
|
47
|
+
failure:
|
48
|
+
session_limited: 'Ваші облікові дані були використані в іншому браузері. Будь ласка, авторизуйтесь знову щоб продовжити в цьому браузері.'
|
49
|
+
expired: "Ваш аккаунт застарів через неактивність. Будь ласка, зв'яжіться з адміністратором."
|
@@ -0,0 +1,41 @@
|
|
1
|
+
zh_CN:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
taken_in_past: '曾被使用过。'
|
5
|
+
equal_to_current_password: '必须与当前密码不同。'
|
6
|
+
equal_to_email: '必须与电子邮件地址不同。'
|
7
|
+
password_complexity:
|
8
|
+
digit:
|
9
|
+
one: 必须包含至少1个数字
|
10
|
+
other: 必须包含至少%{count}个数字
|
11
|
+
lower:
|
12
|
+
one: 必须包含至少1个小写字母
|
13
|
+
other: 必须包含至少%{count}个小写字母
|
14
|
+
symbol:
|
15
|
+
one: 必须包含至少1个特殊符号(!"#$%&'()*+,-./:;<=>?@[\]^_‘{|}~)
|
16
|
+
other: 必须包含至少%{count}个特殊符号(!"#$%&'()*+,-./:;<=>?@[\]^_‘{|}~)
|
17
|
+
upper:
|
18
|
+
one: 必须包含至少1个大写字母
|
19
|
+
other: 必须包含至少%{count}个大写字母
|
20
|
+
devise:
|
21
|
+
invalid_captcha: '验证码无效。'
|
22
|
+
invalid_security_question: '安全问题答案无效。'
|
23
|
+
paranoid_verify:
|
24
|
+
code_required: '请输入我们支持团队提供的代码'
|
25
|
+
paranoid_verification_code:
|
26
|
+
show:
|
27
|
+
submit_verification_code: 提交验证码
|
28
|
+
verification_code: 验证码
|
29
|
+
submit: 提交
|
30
|
+
password_expired:
|
31
|
+
updated: '你的新密码已保存。'
|
32
|
+
change_required: '你的密码已过期,请更新密码。'
|
33
|
+
show:
|
34
|
+
renew_your_password: 更新你的密码
|
35
|
+
current_password: 当前密码
|
36
|
+
new_password: 新密码
|
37
|
+
new_password_confirmation: 确认新密码
|
38
|
+
change_my_password: 更改密码
|
39
|
+
failure:
|
40
|
+
session_limited: '你的登录凭据已在另一个浏览器上被使用。请重新登录以在此浏览器继续。'
|
41
|
+
expired: '由于不活跃,你的账户已过期。请联系站点管理员。'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
zh_TW:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
taken_in_past: '曾被使用過。'
|
5
|
+
equal_to_current_password: '必須與目前密碼不同。'
|
6
|
+
equal_to_email: '必須與電子郵件地址不同。'
|
7
|
+
password_complexity:
|
8
|
+
digit:
|
9
|
+
one: 必須包含至少一個數字
|
10
|
+
other: 必須包含至少 %{count} 個數字
|
11
|
+
lower:
|
12
|
+
one: 必須包含至少一個小寫字母
|
13
|
+
other: 必須包含至少 %{count} 個小寫字母
|
14
|
+
symbol:
|
15
|
+
one: 必須包含至少一個特殊符號
|
16
|
+
other: 必須包含至少 %{count} 個特殊符號
|
17
|
+
upper:
|
18
|
+
one: 必須包含至少一個大寫字母
|
19
|
+
other: 必須包含至少 %{count} 個大寫字母
|
20
|
+
devise:
|
21
|
+
invalid_captcha: '輸入的驗證碼無效。'
|
22
|
+
invalid_security_question: '安全問題答案無效。'
|
23
|
+
paranoid_verify:
|
24
|
+
code_required: '請輸入由我們客服團隊提供的代碼'
|
25
|
+
paranoid_verification_code:
|
26
|
+
show:
|
27
|
+
submit_verification_code: 送出驗證碼
|
28
|
+
verification_code: 驗證碼
|
29
|
+
submit: 送出
|
30
|
+
password_expired:
|
31
|
+
updated: '你的新密碼已儲存'
|
32
|
+
change_required: '你的密碼已經過期,請更新密碼。'
|
33
|
+
show:
|
34
|
+
renew_your_password: 更新你的密碼
|
35
|
+
current_password: 目前密碼
|
36
|
+
new_password: 新密碼
|
37
|
+
new_password_confirmation: 確認新密碼
|
38
|
+
change_my_password: 更改我的密碼
|
39
|
+
failure:
|
40
|
+
session_limited: '你的登入憑證已在另一個瀏覽器上被使用,請重新登入以在此瀏覽器繼續使用。'
|
41
|
+
expired: '你的帳號因過久沒使用而已經過期,請洽網站管理員。'
|
data/lib/devise-security.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
DEVISE_ORM = ENV.fetch('DEVISE_ORM', 'active_record').to_sym unless defined?(DEVISE_ORM)
|
2
3
|
|
3
4
|
require DEVISE_ORM.to_s if DEVISE_ORM.in? [:active_record, :mongoid]
|
4
5
|
require 'active_support/core_ext/integer'
|
@@ -78,11 +79,14 @@ module Devise
|
|
78
79
|
# paranoid_verification will regenerate verifacation code after faild attempt
|
79
80
|
mattr_accessor :paranoid_code_regenerate_after_attempt
|
80
81
|
@@paranoid_code_regenerate_after_attempt = 10
|
82
|
+
|
83
|
+
# Whether to allow passwords that are equal (case insensitive) to the email
|
84
|
+
mattr_accessor :allow_passwords_equal_to_email
|
85
|
+
@@allow_passwords_equal_to_email = false
|
81
86
|
end
|
82
87
|
|
83
|
-
#
|
88
|
+
# a security extension for devise
|
84
89
|
module DeviseSecurity
|
85
|
-
autoload :Schema, 'devise-security/schema'
|
86
90
|
autoload :Patches, 'devise-security/patches'
|
87
91
|
|
88
92
|
module Controllers
|
@@ -103,6 +107,6 @@ Devise.add_module :paranoid_verification, controller: :paranoid_verification_cod
|
|
103
107
|
# requires
|
104
108
|
require 'devise-security/routes'
|
105
109
|
require 'devise-security/rails'
|
106
|
-
require "devise-security/orm/#{DEVISE_ORM}"
|
110
|
+
require "devise-security/orm/#{DEVISE_ORM}" if DEVISE_ORM == :mongoid
|
107
111
|
require 'devise-security/models/database_authenticatable_patch'
|
108
112
|
require 'devise-security/models/paranoid_verification'
|
@@ -40,71 +40,80 @@ module DeviseSecurity
|
|
40
40
|
|
41
41
|
# controller instance methods
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
43
|
+
private
|
44
|
+
|
45
|
+
# Called as a `before_action` on all actions on any controller that uses
|
46
|
+
# this helper. If the user's session is marked as having an expired
|
47
|
+
# password we double check in case it has been changed by another process,
|
48
|
+
# then redirect to the password change url.
|
49
|
+
#
|
50
|
+
# @note `Warden::Manager.after_authentication` is run AFTER this method
|
51
|
+
#
|
52
|
+
# @note Once the warden session has `'password_expired'` set to `false`,
|
53
|
+
# it will **never** be checked again until the user re-logs in.
|
54
|
+
def handle_password_change
|
55
|
+
return if warden.nil?
|
56
|
+
|
57
|
+
if !devise_controller? &&
|
58
|
+
!ignore_password_expire? &&
|
59
|
+
!request.format.nil? &&
|
60
|
+
request.format.html?
|
61
|
+
Devise.mappings.keys.flatten.any? do |scope|
|
62
|
+
if signed_in?(scope) && warden.session(scope)['password_expired'] == true
|
63
|
+
if send(:"current_#{scope}").try(:need_change_password?)
|
64
|
+
store_location_for(scope, request.original_fullpath) if request.get?
|
65
|
+
redirect_for_password_change(scope)
|
66
|
+
else
|
67
|
+
warden.session(scope)['password_expired'] = false
|
60
68
|
end
|
61
69
|
end
|
62
70
|
end
|
63
71
|
end
|
72
|
+
end
|
64
73
|
|
65
|
-
|
66
|
-
|
67
|
-
|
74
|
+
# lookup if extra (paranoid) code verification is needed
|
75
|
+
def handle_paranoid_verification
|
76
|
+
return if warden.nil?
|
68
77
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
78
|
+
if !devise_controller? && !request.format.nil? && request.format.html?
|
79
|
+
Devise.mappings.keys.flatten.any? do |scope|
|
80
|
+
if signed_in?(scope) && warden.session(scope)['paranoid_verify']
|
81
|
+
store_location_for(scope, request.original_fullpath) if request.get?
|
82
|
+
redirect_for_paranoid_verification scope
|
83
|
+
return
|
76
84
|
end
|
77
85
|
end
|
78
86
|
end
|
87
|
+
end
|
79
88
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
89
|
+
# redirect for password update with alert message
|
90
|
+
def redirect_for_password_change(scope)
|
91
|
+
redirect_to change_password_required_path_for(scope), alert: I18n.t('change_required', scope: 'devise.password_expired')
|
92
|
+
end
|
84
93
|
|
85
|
-
|
86
|
-
|
87
|
-
|
94
|
+
def redirect_for_paranoid_verification(scope)
|
95
|
+
redirect_to paranoid_verification_code_path_for(scope), alert: I18n.t('code_required', scope: 'devise.paranoid_verify')
|
96
|
+
end
|
88
97
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
98
|
+
# path for change password
|
99
|
+
def change_password_required_path_for(resource_or_scope = nil)
|
100
|
+
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
101
|
+
change_path = "#{scope}_password_expired_path"
|
102
|
+
send(change_path)
|
103
|
+
end
|
95
104
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
105
|
+
def paranoid_verification_code_path_for(resource_or_scope = nil)
|
106
|
+
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
107
|
+
change_path = "#{scope}_paranoid_verification_code_path"
|
108
|
+
send(change_path)
|
109
|
+
end
|
101
110
|
|
102
|
-
|
111
|
+
protected
|
103
112
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
113
|
+
# allow to overwrite for some special handlings
|
114
|
+
def ignore_password_expire?
|
115
|
+
false
|
116
|
+
end
|
108
117
|
end
|
109
118
|
end
|
110
119
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# @note This happens after
|
4
|
+
# {DeviseSecurity::Controller::Helpers#handle_password_change}
|
3
5
|
Warden::Manager.after_authentication do |record, warden, options|
|
4
6
|
if record.respond_to?(:need_change_password?)
|
5
7
|
warden.session(options[:scope])['password_expired'] = record.need_change_password?
|
@@ -1,26 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# After each sign in, update unique_session_id.
|
4
|
-
#
|
5
|
-
#
|
6
|
-
# not trigger it.
|
3
|
+
# After each sign in, update unique_session_id. This is only triggered when the
|
4
|
+
# user is explicitly set (with set_user) and on authentication. Retrieving the
|
5
|
+
# user from session (:fetch) does not trigger it.
|
7
6
|
Warden::Manager.after_set_user except: :fetch do |record, warden, options|
|
8
|
-
if record.
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
if record.devise_modules.include?(:session_limitable) &&
|
8
|
+
warden.authenticated?(options[:scope]) &&
|
9
|
+
!record.skip_session_limitable?
|
10
|
+
|
11
|
+
if !options[:skip_session_limitable]
|
12
|
+
unique_session_id = Devise.friendly_token
|
13
|
+
warden.session(options[:scope])['unique_session_id'] = unique_session_id
|
14
|
+
record.update_unique_session_id!(unique_session_id)
|
15
|
+
else
|
16
|
+
warden.session(options[:scope])['devise.skip_session_limitable'] = true
|
17
|
+
end
|
12
18
|
end
|
13
19
|
end
|
14
20
|
|
15
|
-
# Each time a record is fetched from session we check if a new session from
|
16
|
-
# browser was opened for the record or not, based on a unique session
|
17
|
-
# If so, the old account is logged out and redirected to the sign in
|
21
|
+
# Each time a record is fetched from session we check if a new session from
|
22
|
+
# another browser was opened for the record or not, based on a unique session
|
23
|
+
# identifier. If so, the old account is logged out and redirected to the sign in
|
24
|
+
# page on the next request.
|
18
25
|
Warden::Manager.after_set_user only: :fetch do |record, warden, options|
|
19
26
|
scope = options[:scope]
|
20
|
-
env = warden.request.env
|
21
27
|
|
22
|
-
if record.
|
23
|
-
|
28
|
+
if record.devise_modules.include?(:session_limitable) &&
|
29
|
+
warden.authenticated?(scope) &&
|
30
|
+
options[:store] != false
|
31
|
+
if record.unique_session_id != warden.session(scope)['unique_session_id'] &&
|
32
|
+
!record.skip_session_limitable? &&
|
33
|
+
!warden.session(scope)['devise.skip_session_limitable']
|
34
|
+
Rails.logger.warn do
|
35
|
+
'[devise-security][session_limitable] session id mismatch: '\
|
36
|
+
"expected=#{record.unique_session_id.inspect} "\
|
37
|
+
"actual=#{warden.session(scope)['unique_session_id'].inspect}"
|
38
|
+
end
|
24
39
|
warden.raw_session.clear
|
25
40
|
warden.logout(scope)
|
26
41
|
throw :warden, scope: scope, message: :session_limited
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "compatibility/#{DEVISE_ORM}"
|
3
|
+
require_relative "compatibility/#{DEVISE_ORM}_patch"
|
4
4
|
|
5
5
|
module Devise
|
6
6
|
module Models
|
@@ -9,7 +9,7 @@ module Devise
|
|
9
9
|
# and/or older versions of ORMs.
|
10
10
|
module Compatibility
|
11
11
|
extend ActiveSupport::Concern
|
12
|
-
include "Devise::Models::Compatibility::#{DEVISE_ORM.to_s.classify}".constantize
|
12
|
+
include "Devise::Models::Compatibility::#{DEVISE_ORM.to_s.classify}Patch".constantize
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module Devise
|
2
2
|
module Models
|
3
3
|
module Compatibility
|
4
|
-
|
4
|
+
|
5
|
+
class NotPersistedError < ActiveRecord::ActiveRecordError; end
|
6
|
+
|
7
|
+
module ActiveRecordPatch
|
5
8
|
extend ActiveSupport::Concern
|
6
9
|
unless Devise.activerecord51?
|
7
10
|
# When the record was saved, was the +encrypted_password+ changed?
|
@@ -23,6 +26,14 @@ module Devise
|
|
23
26
|
changed_attributes['encrypted_password'].present?
|
24
27
|
end
|
25
28
|
end
|
29
|
+
|
30
|
+
# Updates the record with the value and does not trigger validations or callbacks
|
31
|
+
# @param name [Symbol] attribute to update
|
32
|
+
# @param value [String] value to set
|
33
|
+
def update_attribute_without_validatons_or_callbacks(name, value)
|
34
|
+
update_column(name, value)
|
35
|
+
end
|
36
|
+
|
26
37
|
end
|
27
38
|
end
|
28
39
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module Devise
|
2
2
|
module Models
|
3
3
|
module Compatibility
|
4
|
-
|
4
|
+
|
5
|
+
class NotPersistedError < Mongoid::Errors::MongoidError; end
|
6
|
+
|
7
|
+
module MongoidPatch
|
5
8
|
extend ActiveSupport::Concern
|
6
9
|
|
7
10
|
# Will saving this record change the +email+ attribute?
|
@@ -15,6 +18,13 @@ module Devise
|
|
15
18
|
def will_save_change_to_encrypted_password?
|
16
19
|
changed.include? 'encrypted_password'
|
17
20
|
end
|
21
|
+
|
22
|
+
# Updates the document with the value and does not trigger validations or callbacks
|
23
|
+
# @param name [Symbol] attribute to update
|
24
|
+
# @param value [String] value to set
|
25
|
+
def update_attribute_without_validatons_or_callbacks(name, value)
|
26
|
+
set(Hash[*[name, value]])
|
27
|
+
end
|
18
28
|
end
|
19
29
|
end
|
20
30
|
end
|
@@ -92,7 +92,11 @@ module Devise::Models
|
|
92
92
|
# Update +password_changed_at+ for new records and changed passwords.
|
93
93
|
# @note called as a +before_save+ hook
|
94
94
|
def update_password_changed
|
95
|
-
|
95
|
+
if defined?(will_save_change_to_attribute?)
|
96
|
+
return unless (new_record? || will_save_change_to_encrypted_password?) && !will_save_change_to_password_changed_at?
|
97
|
+
else
|
98
|
+
return unless (new_record? || encrypted_password_changed?) && !password_changed_at_changed?
|
99
|
+
end
|
96
100
|
|
97
101
|
self.password_changed_at = Time.zone.now
|
98
102
|
end
|