devise_token_auth 1.2.2 → 1.2.6
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.
- checksums.yaml +4 -4
- data/README.md +1 -4
- data/app/controllers/devise_token_auth/confirmations_controller.rb +1 -1
- data/app/controllers/devise_token_auth/passwords_controller.rb +2 -2
- data/app/controllers/devise_token_auth/sessions_controller.rb +1 -1
- data/app/models/devise_token_auth/concerns/active_record_support.rb +5 -1
- data/app/models/devise_token_auth/concerns/confirmable_support.rb +1 -1
- data/app/models/devise_token_auth/concerns/user.rb +20 -13
- data/config/locales/fa.yml +60 -0
- data/lib/devise_token_auth/version.rb +1 -1
- data/test/controllers/devise_token_auth/passwords_controller_test.rb +90 -29
- data/test/controllers/devise_token_auth/registrations_controller_test.rb +17 -17
- data/test/controllers/devise_token_auth/sessions_controller_test.rb +1 -1
- data/test/dummy/config/application.rb +1 -0
- data/test/dummy/config/environments/test.rb +6 -2
- data/test/dummy/tmp/generators/app/models/user.rb +10 -8
- data/test/dummy/tmp/generators/db/migrate/{20230415183419_devise_token_auth_create_users.rb → 20240519164408_devise_token_auth_create_users.rb} +1 -1
- data/test/factories/users.rb +1 -1
- data/test/models/user_test.rb +94 -0
- metadata +18 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2950da8c6b3eac0a2a3ee2b1659d5e321ca9890e5a9b0a1525dcbf11e95d67dd
|
|
4
|
+
data.tar.gz: d04830c1c12f69b3537e80fae17d5914b0b22272a52b78d7226a04be560cadea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a7e1dcce01dabc1e270926ff05b54c166d861232ef6ecf7547d88442e2d11ab7c104fef833312bf73a69dd5e3dd7df4923f050baf3e4aee877f32df6392d352
|
|
7
|
+
data.tar.gz: b44b9aa57a43fb58e86a7985957e9a5d425787ae65e898b480d7fefe02bf573433f27af356512ae2a4989c3a6d9f0b91a9cc1a1b3b2ef3f95a4b39557472ffa7
|
data/README.md
CHANGED
|
@@ -23,6 +23,7 @@ Also, it maintains a session for each client/device, so you can have as many ses
|
|
|
23
23
|
* [redux-token-auth](https://github.com/kylecorbelli/redux-token-auth) for [React with Redux](https://github.com/reactjs/react-redux)
|
|
24
24
|
* [jToker](https://github.com/lynndylanhurley/j-toker) for [jQuery](https://jquery.com/)
|
|
25
25
|
* [vanilla-token-auth](https://github.com/theblang/vanilla-token-auth) for an unopinionated client
|
|
26
|
+
* [flutter_token_auth](https://github.com/diarmuidr3d/flutter_token_auth) for Flutter
|
|
26
27
|
* Oauth2 authentication using [OmniAuth](https://github.com/intridea/omniauth).
|
|
27
28
|
* Email authentication using [Devise](https://github.com/plataformatec/devise), including:
|
|
28
29
|
* User registration, update and deletion
|
|
@@ -70,12 +71,8 @@ We have some bounties for some issues, [check them out](https://github.com/lynnd
|
|
|
70
71
|
|
|
71
72
|
## Live Demos
|
|
72
73
|
|
|
73
|
-
[Here is a demo](http://ng-token-auth-demo.herokuapp.com/) of this app running with the [ng-token-auth](https://github.com/lynndylanhurley/ng-token-auth) module and [AngularJS](https://github.com/angular/angular.js).
|
|
74
|
-
|
|
75
74
|
[Here is a demo](https://stackblitz.com/github/neroniaky/angular-token) of this app running with the [Angular-Token](https://github.com/neroniaky/angular-token) service and [Angular](https://github.com/angular/angular).
|
|
76
75
|
|
|
77
|
-
[Here is a demo](https://j-toker-demo.herokuapp.com/) of this app using the [jToker](https://github.com/lynndylanhurley/j-toker) plugin and [React](http://facebook.github.io/react/).
|
|
78
|
-
|
|
79
76
|
The fully configured api used in these demos can be found [here](https://github.com/lynndylanhurley/devise_token_auth_demo).
|
|
80
77
|
|
|
81
78
|
|
|
@@ -27,7 +27,7 @@ module DeviseTokenAuth
|
|
|
27
27
|
redirect_to(redirect_to_link, redirect_options)
|
|
28
28
|
else
|
|
29
29
|
if redirect_url
|
|
30
|
-
redirect_to DeviseTokenAuth::Url.generate(redirect_url, account_confirmation_success: false)
|
|
30
|
+
redirect_to DeviseTokenAuth::Url.generate(redirect_url, account_confirmation_success: false), redirect_options
|
|
31
31
|
else
|
|
32
32
|
raise ActionController::RoutingError, 'Not Found'
|
|
33
33
|
end
|
|
@@ -56,7 +56,7 @@ module DeviseTokenAuth
|
|
|
56
56
|
set_token_in_cookie(@resource, token)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
redirect_header_options = { reset_password: true }
|
|
59
|
+
redirect_header_options = { reset_password: true, reset_password_token: resource_params[:reset_password_token] }
|
|
60
60
|
redirect_headers = build_redirect_headers(token.token,
|
|
61
61
|
token.client,
|
|
62
62
|
redirect_header_options)
|
|
@@ -73,7 +73,7 @@ module DeviseTokenAuth
|
|
|
73
73
|
# make sure user is authorized
|
|
74
74
|
if require_client_password_reset_token? && resource_params[:reset_password_token]
|
|
75
75
|
@resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
|
|
76
|
-
return render_update_error_unauthorized unless @resource
|
|
76
|
+
return render_update_error_unauthorized unless @resource && @resource.reset_password_period_valid?
|
|
77
77
|
|
|
78
78
|
@token = @resource.create_token
|
|
79
79
|
else
|
|
@@ -131,7 +131,7 @@ module DeviseTokenAuth
|
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
def create_and_assign_token
|
|
134
|
-
if @resource.respond_to?(:with_lock)
|
|
134
|
+
if @resource.respond_to?(:with_lock) && !@resource.changed?
|
|
135
135
|
@resource.with_lock do
|
|
136
136
|
@token = @resource.create_token
|
|
137
137
|
@resource.save!
|
|
@@ -2,7 +2,11 @@ module DeviseTokenAuth::Concerns::ActiveRecordSupport
|
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
4
|
included do
|
|
5
|
-
|
|
5
|
+
if Rails.gem_version >= Gem::Version.new("7.1.0.a")
|
|
6
|
+
serialize :tokens, coder: DeviseTokenAuth::Concerns::TokensSerialization
|
|
7
|
+
else
|
|
8
|
+
serialize :tokens, DeviseTokenAuth::Concerns::TokensSerialization
|
|
9
|
+
end
|
|
6
10
|
end
|
|
7
11
|
|
|
8
12
|
class_methods do
|
|
@@ -3,7 +3,7 @@ module DeviseTokenAuth::Concerns::ConfirmableSupport
|
|
|
3
3
|
|
|
4
4
|
included do
|
|
5
5
|
# Override standard devise `postpone_email_change?` method
|
|
6
|
-
# for not to use `
|
|
6
|
+
# for not to use `devise_will_save_change_to_email?` methods.
|
|
7
7
|
def postpone_email_change?
|
|
8
8
|
postpone = self.class.reconfirmable &&
|
|
9
9
|
email_value_in_database != email &&
|
|
@@ -41,8 +41,7 @@ module DeviseTokenAuth::Concerns::User
|
|
|
41
41
|
|
|
42
42
|
# don't use default devise email validation
|
|
43
43
|
def email_required?; false; end
|
|
44
|
-
def
|
|
45
|
-
def will_save_change_to_email?; false; end
|
|
44
|
+
def devise_will_save_change_to_email?; false; end
|
|
46
45
|
|
|
47
46
|
if DeviseTokenAuth.send_confirmation_email && devise_modules.include?(:confirmable)
|
|
48
47
|
include DeviseTokenAuth::Concerns::ConfirmableSupport
|
|
@@ -259,17 +258,25 @@ module DeviseTokenAuth::Concerns::User
|
|
|
259
258
|
end
|
|
260
259
|
|
|
261
260
|
def clean_old_tokens
|
|
262
|
-
if tokens.
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
# Since the tokens are sorted by expiry, shift the oldest client token
|
|
271
|
-
# off the Hash until it no longer exceeds the maximum number of clients
|
|
272
|
-
tokens.shift while max_client_tokens_exceeded?
|
|
261
|
+
return if tokens.blank? || !max_client_tokens_exceeded?
|
|
262
|
+
|
|
263
|
+
# First, remove any tokens with expiry greater than current max allowed lifespan
|
|
264
|
+
# this handles the case where token lifespan was reduced and old tokens exist
|
|
265
|
+
max_lifespan_expiry = Time.now.to_i + DeviseTokenAuth.token_lifespan.to_i
|
|
266
|
+
tokens_to_keep = tokens.select do |_cid, v|
|
|
267
|
+
expiry = (v[:expiry] || v['expiry']).to_i
|
|
268
|
+
expiry <= max_lifespan_expiry
|
|
273
269
|
end
|
|
270
|
+
|
|
271
|
+
# Using Enumerable#sort_by on a Hash will typecast it into an associative
|
|
272
|
+
# Array (i.e. an Array of key-value Array pairs). However, since Hashes
|
|
273
|
+
# have an internal order in Ruby 1.9+, the resulting sorted associative
|
|
274
|
+
# Array can be converted back into a Hash, while maintaining the sorted
|
|
275
|
+
# order.
|
|
276
|
+
self.tokens = tokens_to_keep.sort_by { |_cid, v| v[:expiry] || v['expiry'] }.to_h
|
|
277
|
+
|
|
278
|
+
# Since the tokens are sorted by expiry, shift the oldest client token
|
|
279
|
+
# off the Hash until it no longer exceeds the maximum number of clients
|
|
280
|
+
tokens.shift while max_client_tokens_exceeded?
|
|
274
281
|
end
|
|
275
282
|
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
fa:
|
|
2
|
+
devise_token_auth:
|
|
3
|
+
sessions:
|
|
4
|
+
not_confirmed: "یک ایمیل تأیید به حساب شما در '%{email}' ارسال شده است. شما باید دستورالعملهای موجود در ایمیل را دنبال کنید تا حساب شما فعال شود."
|
|
5
|
+
bad_credentials: "اطلاعات ورود نامعتبر است. لطفاً دوباره تلاش کنید."
|
|
6
|
+
not_supported: "برای ورود از POST /sign_in استفاده کنید. GET پشتیبانی نمیشود."
|
|
7
|
+
user_not_found: "کاربر پیدا نشد یا وارد نشده است."
|
|
8
|
+
token_validations:
|
|
9
|
+
invalid: "اطلاعات ورود نامعتبر است."
|
|
10
|
+
registrations:
|
|
11
|
+
missing_confirm_success_url: "پارامتر 'confirm_success_url' موجود نیست."
|
|
12
|
+
redirect_url_not_allowed: "انتقال به '%{redirect_url}' مجاز نیست."
|
|
13
|
+
email_already_exists: "یک حساب برای '%{email}' قبلاً وجود دارد."
|
|
14
|
+
account_with_uid_destroyed: "حساب با UID '%{uid}' حذف شده است."
|
|
15
|
+
account_to_destroy_not_found: "نمیتوان حساب را برای حذف پیدا کرد."
|
|
16
|
+
user_not_found: "کاربر پیدا نشد."
|
|
17
|
+
omniauth:
|
|
18
|
+
not_allowed_redirect_url: "انتقال به '%{redirect_url}' مجاز نیست."
|
|
19
|
+
passwords:
|
|
20
|
+
missing_email: "شما باید یک آدرس ایمیل ارائه دهید."
|
|
21
|
+
missing_redirect_url: "آدرس انتقال موجود نیست."
|
|
22
|
+
not_allowed_redirect_url: "انتقال به '%{redirect_url}' مجاز نیست."
|
|
23
|
+
sended: "یک ایمیل به '%{email}' ارسال شده است که شامل دستورالعملهای بازنشانی رمز عبور شما است."
|
|
24
|
+
sended_paranoid: "اگر آدرس ایمیل شما در پایگاه داده ما وجود داشته باشد، در چند دقیقه یک لینک بازیابی رمز عبور به آدرس ایمیل شما ارسال خواهد شد."
|
|
25
|
+
user_not_found: "نمیتوان کاربری با ایمیل '%{email}' پیدا کرد."
|
|
26
|
+
password_not_required: "این حساب نیازی به رمز عبور ندارد. به جای آن با حساب '%{provider}' خود وارد شوید."
|
|
27
|
+
missing_passwords: "شما باید فیلدهای 'رمز عبور' و 'تأیید رمز عبور' را پر کنید."
|
|
28
|
+
successfully_updated: "رمز عبور شما با موفقیت بهروزرسانی شد."
|
|
29
|
+
unlocks:
|
|
30
|
+
missing_email: "شما باید یک آدرس ایمیل ارائه دهید."
|
|
31
|
+
sended: "یک ایمیل به '%{email}' ارسال شده است که شامل دستورالعملهای باز کردن حساب شما است."
|
|
32
|
+
sended_paranoid: "اگر حساب شما وجود داشته باشد، در چند دقیقه یک ایمیل با دستورالعملهای باز کردن حساب شما ارسال خواهد شد."
|
|
33
|
+
user_not_found: "نمیتوان کاربری با ایمیل '%{email}' پیدا کرد."
|
|
34
|
+
confirmations:
|
|
35
|
+
sended: "یک ایمیل به '%{email}' ارسال شده است که شامل دستورالعملهای تأیید حساب شما است."
|
|
36
|
+
sended_paranoid: "اگر آدرس ایمیل شما در پایگاه داده ما وجود داشته باشد، در چند دقیقه یک ایمیل با دستورالعملهای تأیید آدرس ایمیل شما ارسال خواهد شد."
|
|
37
|
+
user_not_found: "نمیتوان کاربری با ایمیل '%{email}' پیدا کرد."
|
|
38
|
+
missing_email: "شما باید یک آدرس ایمیل ارائه دهید."
|
|
39
|
+
|
|
40
|
+
errors:
|
|
41
|
+
messages:
|
|
42
|
+
validate_sign_up_params: "لطفاً دادههای صحیح ثبت نام را در بدنه درخواست ارسال کنید."
|
|
43
|
+
validate_account_update_params: "لطفاً دادههای صحیح بهروزرسانی حساب را در بدنه درخواست ارسال کنید."
|
|
44
|
+
not_email: "یک ایمیل نیست"
|
|
45
|
+
devise:
|
|
46
|
+
mailer:
|
|
47
|
+
confirmation_instructions:
|
|
48
|
+
confirm_link_msg: "شما میتوانید ایمیل حساب خود را از طریق لینک زیر تأیید کنید:"
|
|
49
|
+
confirm_account_link: "تأیید حساب من"
|
|
50
|
+
reset_password_instructions:
|
|
51
|
+
request_reset_link_msg: "شخصی درخواست یک لینک برای تغییر رمز عبور شما کرده است. شما میتوانید این کار را از طریق لینک زیر انجام دهید."
|
|
52
|
+
password_change_link: "تغییر رمز عبور من"
|
|
53
|
+
ignore_mail_msg: "اگر شما این درخواست را نکردهاید، لطفاً این ایمیل را نادیده بگیرید."
|
|
54
|
+
no_changes_msg: "رمز عبور شما تغییر نخواهد کرد تا زمانی که به لینک بالا دسترسی پیدا کنید و یک رمز عبور جدید ایجاد کنید."
|
|
55
|
+
unlock_instructions:
|
|
56
|
+
account_lock_msg: "حساب شما به دلیل تعداد زیادی تلاش ناموفق برای ورود قفل شده است."
|
|
57
|
+
unlock_link_msg: "برای باز کردن حساب خود، روی لینک زیر کلیک کنید:"
|
|
58
|
+
unlock_link: "باز کردن حساب من"
|
|
59
|
+
hello: "سلام"
|
|
60
|
+
welcome: "خوش آمدید"
|
|
@@ -229,42 +229,73 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase
|
|
|
229
229
|
end
|
|
230
230
|
|
|
231
231
|
describe 'password reset link success' do
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
describe 'with require_client_password_reset_token is enabled' do
|
|
233
|
+
before do
|
|
234
|
+
DeviseTokenAuth.require_client_password_reset_token = true
|
|
235
|
+
get :edit,
|
|
236
|
+
params: { reset_password_token: @mail_reset_token,
|
|
237
|
+
redirect_url: @mail_redirect_url }
|
|
236
238
|
|
|
237
|
-
|
|
239
|
+
@resource.reload
|
|
238
240
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
+
raw_qs = response.location.split('?')[1]
|
|
242
|
+
@qs = Rack::Utils.parse_nested_query(raw_qs)
|
|
241
243
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
@client = @qs['client']
|
|
245
|
-
@expiry = @qs['expiry']
|
|
246
|
-
@reset_password = @qs['reset_password']
|
|
247
|
-
@token = @qs['token']
|
|
248
|
-
@uid = @qs['uid']
|
|
249
|
-
end
|
|
244
|
+
@reset_password_token = @qs['reset_password_token']
|
|
245
|
+
end
|
|
250
246
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
247
|
+
test 'response should have success redirect status' do
|
|
248
|
+
assert_equal 302, response.status
|
|
249
|
+
end
|
|
254
250
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
assert @client_id
|
|
259
|
-
assert @expiry
|
|
260
|
-
assert @reset_password
|
|
261
|
-
assert @token
|
|
262
|
-
assert @uid
|
|
251
|
+
test 'response should contain reset_password_token param' do
|
|
252
|
+
assert_equal @mail_reset_token, @qs['reset_password_token']
|
|
253
|
+
end
|
|
263
254
|
end
|
|
264
255
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
256
|
+
describe 'require_client_password_reset_token is disabled' do
|
|
257
|
+
before do
|
|
258
|
+
DeviseTokenAuth.require_client_password_reset_token = false
|
|
259
|
+
get :edit,
|
|
260
|
+
params: { reset_password_token: @mail_reset_token,
|
|
261
|
+
redirect_url: @mail_redirect_url }
|
|
262
|
+
|
|
263
|
+
@resource.reload
|
|
264
|
+
|
|
265
|
+
raw_qs = response.location.split('?')[1]
|
|
266
|
+
@qs = Rack::Utils.parse_nested_query(raw_qs)
|
|
267
|
+
|
|
268
|
+
@access_token = @qs['access-token']
|
|
269
|
+
@client_id = @qs['client_id']
|
|
270
|
+
@client = @qs['client']
|
|
271
|
+
@expiry = @qs['expiry']
|
|
272
|
+
@reset_password = @qs['reset_password']
|
|
273
|
+
@token = @qs['token']
|
|
274
|
+
@uid = @qs['uid']
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
test 'response should have success redirect status' do
|
|
278
|
+
assert_equal 302, response.status
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
test 'response should contain auth params' do
|
|
282
|
+
assert @access_token
|
|
283
|
+
assert @client
|
|
284
|
+
assert @client_id
|
|
285
|
+
assert @expiry
|
|
286
|
+
assert @reset_password
|
|
287
|
+
assert @token
|
|
288
|
+
assert @uid
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
test 'response auth params should be valid' do
|
|
292
|
+
assert @resource.valid_token?(@token, @client_id)
|
|
293
|
+
assert @resource.valid_token?(@access_token, @client)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
test 'response should contain reset_password_token param' do
|
|
297
|
+
assert_equal @mail_reset_token, @qs['reset_password_token']
|
|
298
|
+
end
|
|
268
299
|
end
|
|
269
300
|
end
|
|
270
301
|
end
|
|
@@ -715,6 +746,36 @@ class DeviseTokenAuth::PasswordsControllerTest < ActionController::TestCase
|
|
|
715
746
|
end
|
|
716
747
|
end
|
|
717
748
|
|
|
749
|
+
describe 'with expired reset password token' do
|
|
750
|
+
before do
|
|
751
|
+
DeviseTokenAuth.require_client_password_reset_token = true
|
|
752
|
+
reset_password_token = @resource.send_reset_password_instructions
|
|
753
|
+
@resource.update! reset_password_sent_at: 2.days.ago
|
|
754
|
+
|
|
755
|
+
@new_password = Faker::Internet.password
|
|
756
|
+
@params = { password: @new_password,
|
|
757
|
+
password_confirmation: @new_password,
|
|
758
|
+
reset_password_token: reset_password_token }
|
|
759
|
+
|
|
760
|
+
put :update, params: @params
|
|
761
|
+
|
|
762
|
+
@data = JSON.parse(response.body)
|
|
763
|
+
@resource.reload
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
test 'request should fail' do
|
|
767
|
+
assert_equal 401, response.status
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
test 'new password should not authenticate user' do
|
|
771
|
+
assert !@resource.valid_password?(@new_password)
|
|
772
|
+
end
|
|
773
|
+
|
|
774
|
+
teardown do
|
|
775
|
+
DeviseTokenAuth.require_client_password_reset_token = false
|
|
776
|
+
end
|
|
777
|
+
end
|
|
778
|
+
|
|
718
779
|
describe 'with invalid reset password token' do
|
|
719
780
|
before do
|
|
720
781
|
DeviseTokenAuth.require_client_password_reset_token = true
|
|
@@ -13,7 +13,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
13
13
|
|
|
14
14
|
def mock_registration_params
|
|
15
15
|
{
|
|
16
|
-
email: Faker::Internet.email,
|
|
16
|
+
email: Faker::Internet.unique.email,
|
|
17
17
|
password: 'secret123',
|
|
18
18
|
password_confirmation: 'secret123',
|
|
19
19
|
confirm_success_url: Faker::Internet.url,
|
|
@@ -152,7 +152,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
152
152
|
|
|
153
153
|
test 'request to whitelisted redirect should be successful' do
|
|
154
154
|
post '/auth',
|
|
155
|
-
params: { email: Faker::Internet.email,
|
|
155
|
+
params: { email: Faker::Internet.unique.email,
|
|
156
156
|
password: 'secret123',
|
|
157
157
|
password_confirmation: 'secret123',
|
|
158
158
|
confirm_success_url: @good_redirect_url,
|
|
@@ -163,7 +163,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
163
163
|
|
|
164
164
|
test 'request to non-whitelisted redirect should fail' do
|
|
165
165
|
post '/auth',
|
|
166
|
-
params: { email: Faker::Internet.email,
|
|
166
|
+
params: { email: Faker::Internet.unique.email,
|
|
167
167
|
password: 'secret123',
|
|
168
168
|
password_confirmation: 'secret123',
|
|
169
169
|
confirm_success_url: @bad_redirect_url,
|
|
@@ -181,7 +181,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
181
181
|
describe 'failure if not redirecturl' do
|
|
182
182
|
test 'request should fail if not redirect_url' do
|
|
183
183
|
post '/auth',
|
|
184
|
-
params: { email: Faker::Internet.email,
|
|
184
|
+
params: { email: Faker::Internet.unique.email,
|
|
185
185
|
password: 'secret123',
|
|
186
186
|
password_confirmation: 'secret123',
|
|
187
187
|
unpermitted_param: '(x_x)' }
|
|
@@ -191,7 +191,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
191
191
|
|
|
192
192
|
test 'request to non-whitelisted redirect should fail' do
|
|
193
193
|
post '/auth',
|
|
194
|
-
params: { email: Faker::Internet.email,
|
|
194
|
+
params: { email: Faker::Internet.unique.email,
|
|
195
195
|
password: 'secret123',
|
|
196
196
|
password_confirmation: 'secret123',
|
|
197
197
|
unpermitted_param: '(x_x)' }
|
|
@@ -210,7 +210,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
210
210
|
DeviseTokenAuth.default_confirm_success_url = @redirect_url
|
|
211
211
|
|
|
212
212
|
assert_difference 'ActionMailer::Base.deliveries.size', 1 do
|
|
213
|
-
post '/auth', params: { email: Faker::Internet.email,
|
|
213
|
+
post '/auth', params: { email: Faker::Internet.unique.email,
|
|
214
214
|
password: 'secret123',
|
|
215
215
|
password_confirmation: 'secret123',
|
|
216
216
|
unpermitted_param: '(x_x)' }
|
|
@@ -240,7 +240,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
240
240
|
@mails_sent = ActionMailer::Base.deliveries.count
|
|
241
241
|
|
|
242
242
|
post '/api/v1/auth', params: {
|
|
243
|
-
email: Faker::Internet.email,
|
|
243
|
+
email: Faker::Internet.unique.email,
|
|
244
244
|
password: 'secret123',
|
|
245
245
|
password_confirmation: 'secret123',
|
|
246
246
|
confirm_success_url: Faker::Internet.url,
|
|
@@ -295,7 +295,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
295
295
|
@operating_thetan = 2
|
|
296
296
|
|
|
297
297
|
post '/auth',
|
|
298
|
-
params: { email: Faker::Internet.email,
|
|
298
|
+
params: { email: Faker::Internet.unique.email,
|
|
299
299
|
password: 'secret123',
|
|
300
300
|
password_confirmation: 'secret123',
|
|
301
301
|
confirm_success_url: @redirect_url,
|
|
@@ -388,7 +388,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
388
388
|
describe 'Mismatched passwords' do
|
|
389
389
|
before do
|
|
390
390
|
post '/auth',
|
|
391
|
-
params: { email: Faker::Internet.email,
|
|
391
|
+
params: { email: Faker::Internet.unique.email,
|
|
392
392
|
password: 'secret123',
|
|
393
393
|
password_confirmation: 'bogus',
|
|
394
394
|
confirm_success_url: Faker::Internet.url }
|
|
@@ -505,7 +505,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
505
505
|
# test valid update param
|
|
506
506
|
@resource_class = User
|
|
507
507
|
@new_operating_thetan = 1_000_000
|
|
508
|
-
@email = Faker::Internet.
|
|
508
|
+
@email = Faker::Internet.unique.email
|
|
509
509
|
@request_params = {
|
|
510
510
|
operating_thetan: @new_operating_thetan,
|
|
511
511
|
email: @email
|
|
@@ -612,7 +612,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
612
612
|
# test valid update param
|
|
613
613
|
@resource_class = User
|
|
614
614
|
@new_operating_thetan = 1_000_000
|
|
615
|
-
@email = Faker::Internet.
|
|
615
|
+
@email = Faker::Internet.unique.email
|
|
616
616
|
@request_params = {
|
|
617
617
|
operating_thetan: @new_operating_thetan,
|
|
618
618
|
email: @email
|
|
@@ -663,7 +663,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
663
663
|
before do
|
|
664
664
|
DeviseTokenAuth.check_current_password_before_update = :password
|
|
665
665
|
@new_operating_thetan = 1_000_000
|
|
666
|
-
@email = Faker::Internet.
|
|
666
|
+
@email = Faker::Internet.unique.email
|
|
667
667
|
end
|
|
668
668
|
|
|
669
669
|
after do
|
|
@@ -773,7 +773,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
773
773
|
describe 'Alternate user class' do
|
|
774
774
|
before do
|
|
775
775
|
post '/mangs',
|
|
776
|
-
params: { email: Faker::Internet.email,
|
|
776
|
+
params: { email: Faker::Internet.unique.email,
|
|
777
777
|
password: 'secret123',
|
|
778
778
|
password_confirmation: 'secret123',
|
|
779
779
|
confirm_success_url: Faker::Internet.url }
|
|
@@ -814,7 +814,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
814
814
|
@config_name = 'altUser'
|
|
815
815
|
|
|
816
816
|
post '/mangs',
|
|
817
|
-
params: { email: Faker::Internet.email,
|
|
817
|
+
params: { email: Faker::Internet.unique.email,
|
|
818
818
|
password: 'secret123',
|
|
819
819
|
password_confirmation: 'secret123',
|
|
820
820
|
confirm_success_url: Faker::Internet.url,
|
|
@@ -840,7 +840,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
840
840
|
test 'UnregisterableUser should not be able to access registration routes' do
|
|
841
841
|
assert_raises(ActionController::RoutingError) do
|
|
842
842
|
post '/unregisterable_user_auth',
|
|
843
|
-
params: { email: Faker::Internet.email,
|
|
843
|
+
params: { email: Faker::Internet.unique.email,
|
|
844
844
|
password: 'secret123',
|
|
845
845
|
password_confirmation: 'secret123',
|
|
846
846
|
confirm_success_url: Faker::Internet.url }
|
|
@@ -853,7 +853,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
853
853
|
User.set_callback(:create, :before, :skip_confirmation!)
|
|
854
854
|
|
|
855
855
|
post '/auth',
|
|
856
|
-
params: { email: Faker::Internet.email,
|
|
856
|
+
params: { email: Faker::Internet.unique.email,
|
|
857
857
|
password: 'secret123',
|
|
858
858
|
password_confirmation: 'secret123',
|
|
859
859
|
confirm_success_url: Faker::Internet.url }
|
|
@@ -893,7 +893,7 @@ class DeviseTokenAuth::RegistrationsControllerTest < ActionDispatch::Integration
|
|
|
893
893
|
@mails_sent = ActionMailer::Base.deliveries.count
|
|
894
894
|
|
|
895
895
|
post '/only_email_auth',
|
|
896
|
-
params: { email: Faker::Internet.email,
|
|
896
|
+
params: { email: Faker::Internet.unique.email,
|
|
897
897
|
password: 'secret123',
|
|
898
898
|
password_confirmation: 'secret123',
|
|
899
899
|
confirm_success_url: Faker::Internet.url,
|
|
@@ -420,7 +420,7 @@ class DeviseTokenAuth::SessionsControllerTest < ActionController::TestCase
|
|
|
420
420
|
describe 'With paranoid mode' do
|
|
421
421
|
before do
|
|
422
422
|
mock_hash = '$2a$04$MUWADkfA6MHXDdWHoep6QOvX1o0Y56pNqt3NMWQ9zCRwKSp1HZJba'
|
|
423
|
-
@bcrypt_mock =
|
|
423
|
+
@bcrypt_mock = Minitest::Mock.new
|
|
424
424
|
@bcrypt_mock.expect(:call, mock_hash, [Object, String])
|
|
425
425
|
|
|
426
426
|
swap Devise, paranoid: true do
|
|
@@ -23,7 +23,7 @@ Rails.application.configure do
|
|
|
23
23
|
(config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }) :
|
|
24
24
|
(config.static_cache_control = 'public, max-age=3600')
|
|
25
25
|
|
|
26
|
-
if Rails::VERSION::MAJOR
|
|
26
|
+
if Rails::VERSION::MAJOR < 7 && ENV['DEVISE_TOKEN_AUTH_ORM'] != 'mongoid'
|
|
27
27
|
config.active_record.legacy_connection_handling = false
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -32,7 +32,11 @@ Rails.application.configure do
|
|
|
32
32
|
config.action_controller.perform_caching = false
|
|
33
33
|
|
|
34
34
|
# Raise exceptions instead of rendering exception templates.
|
|
35
|
-
|
|
35
|
+
if Rails::VERSION::MAJOR >= 7 && Rails::VERSION::MINOR > 0
|
|
36
|
+
config.action_dispatch.show_exceptions = :none
|
|
37
|
+
else
|
|
38
|
+
config.action_dispatch.show_exceptions = false
|
|
39
|
+
end
|
|
36
40
|
|
|
37
41
|
# Disable request forgery protection in test environment.
|
|
38
42
|
config.action_controller.allow_forgery_protection = false
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
class User < ApplicationRecord
|
|
2
|
+
# Include default devise modules.
|
|
3
|
+
devise :database_authenticatable, :registerable,
|
|
4
|
+
:recoverable, :rememberable, :trackable, :validatable,
|
|
5
|
+
:confirmable, :omniauthable
|
|
6
|
+
include DeviseTokenAuth::Concerns::User
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
:recoverable, :rememberable, :validatable
|
|
8
|
-
include DeviseTokenAuth::Concerns::User
|
|
9
|
-
end
|
|
8
|
+
def whatever
|
|
9
|
+
puts 'whatever'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[7.0]
|
|
2
2
|
def change
|
|
3
3
|
|
|
4
|
-
create_table(:users
|
|
4
|
+
create_table(:users) do |t|
|
|
5
5
|
## Required
|
|
6
6
|
t.string :provider, :null => false, :default => "email"
|
|
7
7
|
t.string :uid, :null => false, :default => ""
|
data/test/factories/users.rb
CHANGED
data/test/models/user_test.rb
CHANGED
|
@@ -127,4 +127,98 @@ class UserTest < ActiveSupport::TestCase
|
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
129
|
end
|
|
130
|
+
|
|
131
|
+
describe 'clean_old_tokens' do
|
|
132
|
+
before do
|
|
133
|
+
@resource = create(:user, :confirmed)
|
|
134
|
+
@token_lifespan = DeviseTokenAuth.token_lifespan
|
|
135
|
+
@max_client_count = DeviseTokenAuth.max_number_of_devices
|
|
136
|
+
DeviseTokenAuth.max_number_of_devices = 2
|
|
137
|
+
DeviseTokenAuth.token_lifespan = 1.week
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
after do
|
|
141
|
+
DeviseTokenAuth.token_lifespan = @token_lifespan
|
|
142
|
+
DeviseTokenAuth.max_number_of_devices = @max_client_count
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
test 'removes tokens with expiry beyond the maximum lifespan' do
|
|
146
|
+
# Create tokens with different expiry times
|
|
147
|
+
current_time = Time.now.to_i
|
|
148
|
+
|
|
149
|
+
max_lifespan = current_time + DeviseTokenAuth.token_lifespan.to_i
|
|
150
|
+
|
|
151
|
+
# Valid token within lifespan
|
|
152
|
+
@resource.tokens['valid_client'] = {
|
|
153
|
+
'token' => 'valid_token',
|
|
154
|
+
'expiry' => current_time + 1.day.to_i
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Token exactly at max lifespan (should be kept)
|
|
158
|
+
@resource.tokens['edge_client'] = {
|
|
159
|
+
'token' => 'edge_token',
|
|
160
|
+
'expiry' => max_lifespan
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
# Token beyond max lifespan (should be removed)
|
|
164
|
+
@resource.tokens['expired_client'] = {
|
|
165
|
+
'token' => 'expired_token',
|
|
166
|
+
'expiry' => max_lifespan + 1.day.to_i
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
# Call the method under test
|
|
170
|
+
@resource.send(:clean_old_tokens)
|
|
171
|
+
|
|
172
|
+
# Assert that tokens beyond lifespan were removed
|
|
173
|
+
assert @resource.tokens.key?('valid_client'), 'Valid token should be kept'
|
|
174
|
+
assert @resource.tokens.key?('edge_client'), 'Edge case token at max lifespan should be kept'
|
|
175
|
+
refute @resource.tokens.key?('expired_client'), 'Token beyond max lifespan should be removed'
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
test 'handles token lifespan reduction when creating token' do
|
|
179
|
+
# Setup: Create the maximum allowed number of tokens with a longer lifespan
|
|
180
|
+
DeviseTokenAuth.token_lifespan = 2.weeks
|
|
181
|
+
DeviseTokenAuth.max_number_of_devices = 3
|
|
182
|
+
|
|
183
|
+
# Create tokens at different times but all within the initial long lifespan
|
|
184
|
+
@resource.tokens = {}
|
|
185
|
+
@resource.tokens['client_1'] = {
|
|
186
|
+
'token' => 'token_1',
|
|
187
|
+
'expiry' => Time.now.to_i + 12.days.to_i
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@resource.tokens['client_2'] = {
|
|
191
|
+
'token' => 'token_2',
|
|
192
|
+
'expiry' => Time.now.to_i + 10.days.to_i
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@resource.tokens['client_3'] = {
|
|
196
|
+
'token' => 'token_3',
|
|
197
|
+
'expiry' => Time.now.to_i + 5.days.to_i
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# We've reached the maximum number of devices/tokens
|
|
201
|
+
assert_equal 3, @resource.tokens.length
|
|
202
|
+
|
|
203
|
+
# Now reduce token lifespan - simulating a config change
|
|
204
|
+
DeviseTokenAuth.token_lifespan = 1.week
|
|
205
|
+
|
|
206
|
+
# Create a new token which should trigger clean_old_tokens
|
|
207
|
+
new_auth_headers = @resource.create_new_auth_token
|
|
208
|
+
new_client = new_auth_headers['client']
|
|
209
|
+
|
|
210
|
+
# The new token should exist
|
|
211
|
+
assert @resource.tokens.key?(new_client), 'New token should exist'
|
|
212
|
+
|
|
213
|
+
# Tokens exceeding the new reduced lifespan should be removed
|
|
214
|
+
refute @resource.tokens.key?('client_1'), 'Token with expiry > new lifespan should be removed'
|
|
215
|
+
refute @resource.tokens.key?('client_2'), 'Token with expiry > new lifespan should be removed'
|
|
216
|
+
|
|
217
|
+
# Token within new lifespan should be kept
|
|
218
|
+
assert @resource.tokens.key?('client_3'), 'Token within new reduced lifespan should be kept'
|
|
219
|
+
|
|
220
|
+
# We should have exactly 2 tokens: the new one and client_3
|
|
221
|
+
assert_equal 2, @resource.tokens.length
|
|
222
|
+
end
|
|
223
|
+
end
|
|
130
224
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: devise_token_auth
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lynn Hurley
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-11-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -19,7 +19,7 @@ dependencies:
|
|
|
19
19
|
version: 4.2.0
|
|
20
20
|
- - "<"
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: '
|
|
22
|
+
version: '8.2'
|
|
23
23
|
type: :runtime
|
|
24
24
|
prerelease: false
|
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -29,7 +29,7 @@ dependencies:
|
|
|
29
29
|
version: 4.2.0
|
|
30
30
|
- - "<"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '
|
|
32
|
+
version: '8.2'
|
|
33
33
|
- !ruby/object:Gem::Dependency
|
|
34
34
|
name: devise
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -144,16 +144,22 @@ dependencies:
|
|
|
144
144
|
name: mongoid-locker
|
|
145
145
|
requirement: !ruby/object:Gem::Requirement
|
|
146
146
|
requirements:
|
|
147
|
-
- - "
|
|
147
|
+
- - ">="
|
|
148
148
|
- !ruby/object:Gem::Version
|
|
149
|
-
version: '
|
|
149
|
+
version: '1.0'
|
|
150
|
+
- - "<"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '3.0'
|
|
150
153
|
type: :development
|
|
151
154
|
prerelease: false
|
|
152
155
|
version_requirements: !ruby/object:Gem::Requirement
|
|
153
156
|
requirements:
|
|
154
|
-
- - "
|
|
157
|
+
- - ">="
|
|
155
158
|
- !ruby/object:Gem::Version
|
|
156
|
-
version: '
|
|
159
|
+
version: '1.0'
|
|
160
|
+
- - "<"
|
|
161
|
+
- !ruby/object:Gem::Version
|
|
162
|
+
version: '3.0'
|
|
157
163
|
description: For use with client side single page apps such as the venerable https://github.com/lynndylanhurley/ng-token-auth.
|
|
158
164
|
email:
|
|
159
165
|
- lynn.dylan.hurley@gmail.com
|
|
@@ -189,6 +195,7 @@ files:
|
|
|
189
195
|
- config/locales/de.yml
|
|
190
196
|
- config/locales/en.yml
|
|
191
197
|
- config/locales/es.yml
|
|
198
|
+
- config/locales/fa.yml
|
|
192
199
|
- config/locales/fr.yml
|
|
193
200
|
- config/locales/he.yml
|
|
194
201
|
- config/locales/it.yml
|
|
@@ -321,7 +328,7 @@ files:
|
|
|
321
328
|
- test/dummy/lib/migration_database_helper.rb
|
|
322
329
|
- test/dummy/tmp/generators/app/models/user.rb
|
|
323
330
|
- test/dummy/tmp/generators/config/initializers/devise_token_auth.rb
|
|
324
|
-
- test/dummy/tmp/generators/db/migrate/
|
|
331
|
+
- test/dummy/tmp/generators/db/migrate/20240519164408_devise_token_auth_create_users.rb
|
|
325
332
|
- test/factories/users.rb
|
|
326
333
|
- test/lib/devise_token_auth/blacklist_test.rb
|
|
327
334
|
- test/lib/devise_token_auth/rails/custom_routes_test.rb
|
|
@@ -357,7 +364,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
357
364
|
- !ruby/object:Gem::Version
|
|
358
365
|
version: '0'
|
|
359
366
|
requirements: []
|
|
360
|
-
rubygems_version: 3.
|
|
367
|
+
rubygems_version: 3.4.19
|
|
361
368
|
signing_key:
|
|
362
369
|
specification_version: 4
|
|
363
370
|
summary: Token based authentication for rails. Uses Devise + OmniAuth.
|
|
@@ -456,7 +463,7 @@ test_files:
|
|
|
456
463
|
- test/dummy/lib/migration_database_helper.rb
|
|
457
464
|
- test/dummy/tmp/generators/app/models/user.rb
|
|
458
465
|
- test/dummy/tmp/generators/config/initializers/devise_token_auth.rb
|
|
459
|
-
- test/dummy/tmp/generators/db/migrate/
|
|
466
|
+
- test/dummy/tmp/generators/db/migrate/20240519164408_devise_token_auth_create_users.rb
|
|
460
467
|
- test/factories/users.rb
|
|
461
468
|
- test/lib/devise_token_auth/blacklist_test.rb
|
|
462
469
|
- test/lib/devise_token_auth/rails/custom_routes_test.rb
|