devise_token_auth 1.1.0 → 1.1.1
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_token_auth might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +26 -29
- data/app/controllers/devise_token_auth/confirmations_controller.rb +54 -7
- data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +7 -7
- data/app/controllers/devise_token_auth/passwords_controller.rb +4 -4
- data/app/controllers/devise_token_auth/registrations_controller.rb +2 -2
- data/app/controllers/devise_token_auth/sessions_controller.rb +5 -5
- data/app/controllers/devise_token_auth/unlocks_controller.rb +3 -3
- data/app/models/devise_token_auth/concerns/active_record_support.rb +3 -21
- data/app/models/devise_token_auth/concerns/tokens_serialization.rb +19 -0
- data/app/models/devise_token_auth/concerns/user.rb +36 -45
- data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +1 -1
- data/app/validators/{devise_token_auth/email_validator.rb → devise_token_auth_email_validator.rb} +1 -1
- data/config/locales/en.yml +5 -0
- data/lib/devise_token_auth.rb +1 -0
- data/lib/devise_token_auth/engine.rb +2 -0
- data/lib/devise_token_auth/rails/routes.rb +1 -1
- data/lib/devise_token_auth/token_factory.rb +126 -0
- data/lib/devise_token_auth/version.rb +1 -1
- data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +5 -0
- data/test/controllers/demo_user_controller_test.rb +2 -2
- data/test/controllers/devise_token_auth/confirmations_controller_test.rb +39 -0
- data/test/dummy/app/controllers/overrides/confirmations_controller.rb +3 -3
- data/test/dummy/app/controllers/overrides/passwords_controller.rb +3 -3
- data/test/dummy/app/controllers/overrides/registrations_controller.rb +1 -1
- data/test/dummy/app/controllers/overrides/sessions_controller.rb +1 -1
- data/test/dummy/config/initializers/devise.rb +275 -2
- data/test/dummy/config/initializers/devise_token_auth.rb +35 -4
- data/test/dummy/tmp/generators/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/test/dummy/tmp/generators/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/test/factories/users.rb +1 -1
- data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
- data/test/models/concerns/tokens_serialization_test.rb +70 -0
- data/test/models/user_test.rb +0 -32
- metadata +29 -13
- data/test/dummy/tmp/generators/app/models/azpire/v1/human_resource/user.rb +0 -9
- data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +0 -50
- data/test/dummy/tmp/generators/config/routes.rb +0 -4
- data/test/dummy/tmp/generators/db/migrate/20190112150327_devise_token_auth_create_azpire_v1_human_resource_users.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25a0c261827b5f9e1f7dccc40b782a5321d34c50a730fac7bdf9f2c281c397d9
|
4
|
+
data.tar.gz: dfee96bd1789d025ea52a83573d90d0ae784e4c63723d2ea864d17eea8fdbaf3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e68ff8599b70eebdfb2eceab3f76fce22a5cac1976234f485a58363c3821815e541982523f8ff08cd35677e794b507a10c5239c718dd033dc799f5594de0877a
|
7
|
+
data.tar.gz: d48ee0ebfa6a9117f1dbcb96180c4a6d06436ba3b555b75899da653115332fa2e69090cdb11ae8d1df3617f799a3e04547ac12bb45e0d148a49a52ac63b6c072
|
data/README.md
CHANGED
@@ -65,6 +65,8 @@ Please read the [issue template](https://github.com/lynndylanhurley/devise_token
|
|
65
65
|
|
66
66
|
See our [Contribution Guidelines](https://github.com/lynndylanhurley/devise_token_auth/blob/master/.github/CONTRIBUTING.md). Feel free to submit pull requests, review pull requests, or review open issues. If you'd like to get in contact, [Zach Feldman](https://github.com/zachfeldman) has been wrangling this effort, you can reach him with his name @gmail. Further discussion of this in [this issue](https://github.com/lynndylanhurley/devise_token_auth/issues/969).
|
67
67
|
|
68
|
+
We have some bounties for some issues, [check them out](https://github.com/lynndylanhurley/devise_token_auth/issues?q=is%3Aopen+is%3Aissue+label%3Abounty)!
|
69
|
+
|
68
70
|
## Live Demos
|
69
71
|
|
70
72
|
[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).
|
@@ -17,9 +17,8 @@ module DeviseTokenAuth::Concerns::SetUserByToken
|
|
17
17
|
@used_auth_by_token = true
|
18
18
|
|
19
19
|
# initialize instance variables
|
20
|
-
@
|
20
|
+
@token = DeviseTokenAuth::TokenFactory.new
|
21
21
|
@resource ||= nil
|
22
|
-
@token ||= nil
|
23
22
|
@is_batch_request ||= nil
|
24
23
|
end
|
25
24
|
|
@@ -37,17 +36,18 @@ module DeviseTokenAuth::Concerns::SetUserByToken
|
|
37
36
|
client_name = DeviseTokenAuth.headers_names[:'client']
|
38
37
|
|
39
38
|
# parse header for values necessary for authentication
|
40
|
-
uid
|
41
|
-
@token
|
42
|
-
@
|
39
|
+
uid = request.headers[uid_name] || params[uid_name]
|
40
|
+
@token = DeviseTokenAuth::TokenFactory.new unless @token
|
41
|
+
@token.token ||= request.headers[access_token_name] || params[access_token_name]
|
42
|
+
@token.client ||= request.headers[client_name] || params[client_name]
|
43
43
|
|
44
|
-
#
|
45
|
-
@
|
44
|
+
# client isn't required, set to 'default' if absent
|
45
|
+
@token.client ||= 'default'
|
46
46
|
|
47
47
|
# check for an existing user, authenticated via warden/devise, if enabled
|
48
48
|
if DeviseTokenAuth.enable_standard_devise_support
|
49
49
|
devise_warden_user = warden.user(rc.to_s.underscore.to_sym)
|
50
|
-
if devise_warden_user && devise_warden_user.tokens[@
|
50
|
+
if devise_warden_user && devise_warden_user.tokens[@token.client].nil?
|
51
51
|
@used_auth_by_token = false
|
52
52
|
@resource = devise_warden_user
|
53
53
|
# REVIEW: The following line _should_ be safe to remove;
|
@@ -59,19 +59,17 @@ module DeviseTokenAuth::Concerns::SetUserByToken
|
|
59
59
|
# user has already been found and authenticated
|
60
60
|
return @resource if @resource && @resource.is_a?(rc)
|
61
61
|
|
62
|
-
# ensure we clear the
|
63
|
-
unless @token
|
64
|
-
@
|
62
|
+
# ensure we clear the client
|
63
|
+
unless @token.present?
|
64
|
+
@token.client = nil
|
65
65
|
return
|
66
66
|
end
|
67
67
|
|
68
|
-
return false unless @token
|
69
|
-
|
70
68
|
# mitigate timing attacks by finding by uid instead of auth token
|
71
69
|
user = uid && rc.dta_find_by(uid: uid)
|
72
70
|
scope = rc.to_s.underscore.to_sym
|
73
71
|
|
74
|
-
if user && user.valid_token?(@token, @
|
72
|
+
if user && user.valid_token?(@token.token, @token.client)
|
75
73
|
# sign_in with bypass: true will be deprecated in the next version of Devise
|
76
74
|
if respond_to?(:bypass_sign_in) && DeviseTokenAuth.bypass_sign_in
|
77
75
|
bypass_sign_in(user, scope: scope)
|
@@ -81,25 +79,24 @@ module DeviseTokenAuth::Concerns::SetUserByToken
|
|
81
79
|
return @resource = user
|
82
80
|
else
|
83
81
|
# zero all values previously set values
|
84
|
-
@
|
82
|
+
@token.client = nil
|
85
83
|
return @resource = nil
|
86
84
|
end
|
87
85
|
end
|
88
86
|
|
89
87
|
def update_auth_header
|
90
88
|
# cannot save object if model has invalid params
|
89
|
+
return unless @resource && @token.client
|
91
90
|
|
92
|
-
|
93
|
-
|
94
|
-
# Generate new client_id with existing authentication
|
95
|
-
@client_id = nil unless @used_auth_by_token
|
91
|
+
# Generate new client with existing authentication
|
92
|
+
@token.client = nil unless @used_auth_by_token
|
96
93
|
|
97
94
|
if @used_auth_by_token && !DeviseTokenAuth.change_headers_on_each_request
|
98
95
|
# should not append auth header if @resource related token was
|
99
96
|
# cleared by sign out in the meantime
|
100
|
-
return if @resource.reload.tokens[@
|
97
|
+
return if @resource.reload.tokens[@token.client].nil?
|
101
98
|
|
102
|
-
auth_header = @resource.build_auth_header(@token, @
|
99
|
+
auth_header = @resource.build_auth_header(@token.token, @token.client)
|
103
100
|
|
104
101
|
# update the response header
|
105
102
|
response.headers.merge!(auth_header)
|
@@ -124,30 +121,30 @@ module DeviseTokenAuth::Concerns::SetUserByToken
|
|
124
121
|
@resource.with_lock do
|
125
122
|
# should not append auth header if @resource related token was
|
126
123
|
# cleared by sign out in the meantime
|
127
|
-
return if @used_auth_by_token && @resource.tokens[@
|
124
|
+
return if @used_auth_by_token && @resource.tokens[@token.client].nil?
|
128
125
|
|
129
126
|
# update the response header
|
130
127
|
response.headers.merge!(auth_header_from_batch_request)
|
131
128
|
end # end lock
|
132
129
|
end
|
133
130
|
|
134
|
-
def is_batch_request?(user,
|
131
|
+
def is_batch_request?(user, client)
|
135
132
|
!params[:unbatch] &&
|
136
|
-
user.tokens[
|
137
|
-
user.tokens[
|
138
|
-
user.tokens[
|
133
|
+
user.tokens[client] &&
|
134
|
+
user.tokens[client]['updated_at'] &&
|
135
|
+
user.tokens[client]['updated_at'].to_time > @request_started_at - DeviseTokenAuth.batch_request_buffer_throttle
|
139
136
|
end
|
140
137
|
|
141
138
|
def auth_header_from_batch_request
|
142
139
|
# determine batch request status after request processing, in case
|
143
140
|
# another processes has updated it during that processing
|
144
|
-
@is_batch_request = is_batch_request?(@resource, @
|
141
|
+
@is_batch_request = is_batch_request?(@resource, @token.client)
|
145
142
|
|
146
143
|
auth_header = {}
|
147
144
|
# extend expiration of batch buffer to account for the duration of
|
148
145
|
# this request
|
149
146
|
if @is_batch_request
|
150
|
-
auth_header = @resource.extend_batch_buffer(@token, @
|
147
|
+
auth_header = @resource.extend_batch_buffer(@token.token, @token.client)
|
151
148
|
|
152
149
|
# Do not return token for batch requests to avoid invalidated
|
153
150
|
# tokens returned to the client in case of race conditions.
|
@@ -158,7 +155,7 @@ module DeviseTokenAuth::Concerns::SetUserByToken
|
|
158
155
|
auth_header[DeviseTokenAuth.headers_names[:"expiry"]] = ' '
|
159
156
|
else
|
160
157
|
# update Authorization response header with new token
|
161
|
-
auth_header = @resource.create_new_auth_token(@
|
158
|
+
auth_header = @resource.create_new_auth_token(@token.client)
|
162
159
|
end
|
163
160
|
auth_header
|
164
161
|
end
|
@@ -2,22 +2,20 @@
|
|
2
2
|
|
3
3
|
module DeviseTokenAuth
|
4
4
|
class ConfirmationsController < DeviseTokenAuth::ApplicationController
|
5
|
+
|
5
6
|
def show
|
6
|
-
@resource = resource_class.confirm_by_token(
|
7
|
+
@resource = resource_class.confirm_by_token(resource_params[:confirmation_token])
|
7
8
|
|
8
9
|
if @resource.errors.empty?
|
9
10
|
yield @resource if block_given?
|
10
11
|
|
11
12
|
redirect_header_options = { account_confirmation_success: true }
|
12
13
|
|
13
|
-
# give redirect value from params priority or fall back to default value if provided
|
14
|
-
redirect_url = params[:redirect_url] || DeviseTokenAuth.default_confirm_success_url
|
15
|
-
|
16
14
|
if signed_in?(resource_name)
|
17
|
-
|
15
|
+
token = signed_in_resource.create_token
|
18
16
|
|
19
|
-
redirect_headers = build_redirect_headers(token,
|
20
|
-
|
17
|
+
redirect_headers = build_redirect_headers(token.token,
|
18
|
+
token.client,
|
21
19
|
redirect_header_options)
|
22
20
|
|
23
21
|
redirect_to_link = signed_in_resource.build_auth_url(redirect_url, redirect_headers)
|
@@ -30,5 +28,54 @@ module DeviseTokenAuth
|
|
30
28
|
raise ActionController::RoutingError, 'Not Found'
|
31
29
|
end
|
32
30
|
end
|
31
|
+
|
32
|
+
def create
|
33
|
+
return render_create_error_missing_email if resource_params[:email].blank?
|
34
|
+
|
35
|
+
@email = get_case_insensitive_field_from_resource_params(:email)
|
36
|
+
|
37
|
+
@resource = resource_class.dta_find_by(uid: @email, provider: provider)
|
38
|
+
|
39
|
+
return render_not_found_error unless @resource
|
40
|
+
|
41
|
+
@resource.send_confirmation_instructions({
|
42
|
+
redirect_url: redirect_url,
|
43
|
+
client_config: resource_params[:config_name]
|
44
|
+
})
|
45
|
+
|
46
|
+
return render_create_success
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def render_create_error_missing_email
|
52
|
+
render_error(401, I18n.t('devise_token_auth.confirmations.missing_email'))
|
53
|
+
end
|
54
|
+
|
55
|
+
def render_create_success
|
56
|
+
render json: {
|
57
|
+
success: true,
|
58
|
+
message: I18n.t('devise_token_auth.confirmations.sended', email: @email)
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def render_not_found_error
|
63
|
+
render_error(404, I18n.t('devise_token_auth.confirmations.user_not_found', email: @email))
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def resource_params
|
69
|
+
params.permit(:email, :confirmation_token, :config_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
# give redirect value from params priority or fall back to default value if provided
|
73
|
+
def redirect_url
|
74
|
+
params.fetch(
|
75
|
+
:redirect_url,
|
76
|
+
DeviseTokenAuth.default_confirm_success_url
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
33
80
|
end
|
34
81
|
end
|
@@ -62,7 +62,7 @@ module DeviseTokenAuth
|
|
62
62
|
end
|
63
63
|
|
64
64
|
sign_in(:user, @resource, store: false, bypass: false)
|
65
|
-
|
65
|
+
|
66
66
|
@resource.save!
|
67
67
|
|
68
68
|
yield @resource if block_given?
|
@@ -171,11 +171,11 @@ module DeviseTokenAuth
|
|
171
171
|
|
172
172
|
def create_auth_params
|
173
173
|
@auth_params = {
|
174
|
-
auth_token:
|
175
|
-
client_id:
|
176
|
-
uid:
|
177
|
-
expiry:
|
178
|
-
config:
|
174
|
+
auth_token: @token.token,
|
175
|
+
client_id: @token.client,
|
176
|
+
uid: @resource.uid,
|
177
|
+
expiry: @token.expiry,
|
178
|
+
config: @config
|
179
179
|
}
|
180
180
|
@auth_params.merge!(oauth_registration: true) if @oauth_registration
|
181
181
|
@auth_params
|
@@ -183,7 +183,7 @@ module DeviseTokenAuth
|
|
183
183
|
|
184
184
|
def set_token_on_resource
|
185
185
|
@config = omniauth_params['config_name']
|
186
|
-
@
|
186
|
+
@token = @resource.create_token
|
187
187
|
end
|
188
188
|
|
189
189
|
def render_data(message, data)
|
@@ -39,7 +39,7 @@ module DeviseTokenAuth
|
|
39
39
|
@resource = resource_class.with_reset_password_token(resource_params[:reset_password_token])
|
40
40
|
|
41
41
|
if @resource && @resource.reset_password_period_valid?
|
42
|
-
|
42
|
+
token = @resource.create_token
|
43
43
|
|
44
44
|
# ensure that user is confirmed
|
45
45
|
@resource.skip_confirmation! if confirmable_enabled? && !@resource.confirmed_at
|
@@ -52,8 +52,8 @@ module DeviseTokenAuth
|
|
52
52
|
yield @resource if block_given?
|
53
53
|
|
54
54
|
redirect_header_options = { reset_password: true }
|
55
|
-
redirect_headers = build_redirect_headers(token,
|
56
|
-
|
55
|
+
redirect_headers = build_redirect_headers(token.token,
|
56
|
+
token.client,
|
57
57
|
redirect_header_options)
|
58
58
|
redirect_to(@resource.build_auth_url(@redirect_url,
|
59
59
|
redirect_headers))
|
@@ -92,7 +92,7 @@ module DeviseTokenAuth
|
|
92
92
|
def resource_update_method
|
93
93
|
allow_password_change = recoverable_enabled? && @resource.allow_password_change == true
|
94
94
|
if DeviseTokenAuth.check_current_password_before_update == false || allow_password_change
|
95
|
-
'
|
95
|
+
'update'
|
96
96
|
else
|
97
97
|
'update_with_password'
|
98
98
|
end
|
@@ -52,7 +52,7 @@ module DeviseTokenAuth
|
|
52
52
|
|
53
53
|
if active_for_authentication?
|
54
54
|
# email auth has been bypassed, authenticate user
|
55
|
-
@
|
55
|
+
@token = @resource.create_token
|
56
56
|
@resource.save!
|
57
57
|
update_auth_header
|
58
58
|
end
|
@@ -181,7 +181,7 @@ module DeviseTokenAuth
|
|
181
181
|
elsif account_update_params.key?(:current_password)
|
182
182
|
'update_with_password'
|
183
183
|
else
|
184
|
-
'
|
184
|
+
'update'
|
185
185
|
end
|
186
186
|
end
|
187
187
|
|
@@ -26,7 +26,7 @@ module DeviseTokenAuth
|
|
26
26
|
if (@resource.respond_to?(:valid_for_authentication?) && !@resource.valid_for_authentication? { valid_password }) || !valid_password
|
27
27
|
return render_create_error_bad_credentials
|
28
28
|
end
|
29
|
-
@
|
29
|
+
@token = @resource.create_token
|
30
30
|
@resource.save
|
31
31
|
|
32
32
|
sign_in(:user, @resource, store: false, bypass: false)
|
@@ -48,11 +48,11 @@ module DeviseTokenAuth
|
|
48
48
|
def destroy
|
49
49
|
# remove auth instance variables so that after_action does not run
|
50
50
|
user = remove_instance_variable(:@resource) if @resource
|
51
|
-
|
52
|
-
|
51
|
+
client = @token.client if @token.client
|
52
|
+
@token.clear!
|
53
53
|
|
54
|
-
if user &&
|
55
|
-
user.tokens.delete(
|
54
|
+
if user && client && user.tokens[client]
|
55
|
+
user.tokens.delete(client)
|
56
56
|
user.save!
|
57
57
|
|
58
58
|
yield user if block_given?
|
@@ -35,13 +35,13 @@ module DeviseTokenAuth
|
|
35
35
|
@resource = resource_class.unlock_access_by_token(params[:unlock_token])
|
36
36
|
|
37
37
|
if @resource.persisted?
|
38
|
-
|
38
|
+
token = @resource.create_token
|
39
39
|
@resource.save!
|
40
40
|
yield @resource if block_given?
|
41
41
|
|
42
42
|
redirect_header_options = { unlock: true }
|
43
|
-
redirect_headers = build_redirect_headers(token,
|
44
|
-
|
43
|
+
redirect_headers = build_redirect_headers(token.token,
|
44
|
+
token.client,
|
45
45
|
redirect_header_options)
|
46
46
|
redirect_to(@resource.build_auth_url(after_unlock_path_for(@resource),
|
47
47
|
redirect_headers))
|
@@ -1,12 +1,10 @@
|
|
1
|
+
require_relative 'tokens_serialization'
|
2
|
+
|
1
3
|
module DeviseTokenAuth::Concerns::ActiveRecordSupport
|
2
4
|
extend ActiveSupport::Concern
|
3
5
|
|
4
6
|
included do
|
5
|
-
serialize :tokens,
|
6
|
-
|
7
|
-
# can't set default on text fields in mysql, simulate here instead.
|
8
|
-
after_save :set_empty_token_hash
|
9
|
-
after_initialize :set_empty_token_hash
|
7
|
+
serialize :tokens, DeviseTokenAuth::TokensSerialization
|
10
8
|
end
|
11
9
|
|
12
10
|
class_methods do
|
@@ -14,21 +12,5 @@ module DeviseTokenAuth::Concerns::ActiveRecordSupport
|
|
14
12
|
def dta_find_by(attrs = {})
|
15
13
|
find_by(attrs)
|
16
14
|
end
|
17
|
-
|
18
|
-
protected
|
19
|
-
|
20
|
-
def tokens_has_json_column_type?
|
21
|
-
database_exists? && table_exists? && columns_hash['tokens'] && columns_hash['tokens'].type.in?([:json, :jsonb])
|
22
|
-
end
|
23
|
-
|
24
|
-
def database_exists?
|
25
|
-
ActiveRecord::Base.connection_pool.with_connection { |con| con.active? } rescue false
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
protected
|
30
|
-
|
31
|
-
def set_empty_token_hash
|
32
|
-
self.tokens ||= {} if has_attribute?(:tokens)
|
33
15
|
end
|
34
16
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DeviseTokenAuth::TokensSerialization
|
2
|
+
# Serialization hash to json
|
3
|
+
def self.dump(object)
|
4
|
+
object.each_value(&:compact!) unless object.nil?
|
5
|
+
JSON.generate(object)
|
6
|
+
end
|
7
|
+
|
8
|
+
# Deserialization json to hash
|
9
|
+
def self.load(json)
|
10
|
+
case json
|
11
|
+
when String
|
12
|
+
JSON.parse(json)
|
13
|
+
when NilClass
|
14
|
+
{}
|
15
|
+
else
|
16
|
+
json
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'bcrypt'
|
4
|
-
|
5
3
|
module DeviseTokenAuth::Concerns::User
|
6
4
|
extend ActiveSupport::Concern
|
7
5
|
|
@@ -9,7 +7,7 @@ module DeviseTokenAuth::Concerns::User
|
|
9
7
|
@token_equality_cache ||= {}
|
10
8
|
|
11
9
|
key = "#{token_hash}/#{token}"
|
12
|
-
result = @token_equality_cache[key] ||=
|
10
|
+
result = @token_equality_cache[key] ||= DeviseTokenAuth::TokenFactory.token_hash_is_token?(token_hash, token)
|
13
11
|
@token_equality_cache = {} if @token_equality_cache.size > 10000
|
14
12
|
result
|
15
13
|
end
|
@@ -86,27 +84,25 @@ module DeviseTokenAuth::Concerns::User
|
|
86
84
|
send_devise_notification(:unlock_instructions, raw, opts)
|
87
85
|
raw
|
88
86
|
end
|
89
|
-
end
|
90
87
|
|
91
|
-
|
92
|
-
|
93
|
-
token ||= SecureRandom.urlsafe_base64(nil, false)
|
94
|
-
expiry ||= (Time.zone.now + token_lifespan).to_i
|
88
|
+
def create_token(client: nil, lifespan: nil, cost: nil, **token_extras)
|
89
|
+
token = DeviseTokenAuth::TokenFactory.create(client: client, lifespan: lifespan, cost: cost)
|
95
90
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
91
|
+
tokens[token.client] = {
|
92
|
+
token: token.token_hash,
|
93
|
+
expiry: token.expiry
|
94
|
+
}.merge!(token_extras)
|
100
95
|
|
101
|
-
|
96
|
+
clean_old_tokens
|
102
97
|
|
103
|
-
|
98
|
+
token
|
99
|
+
end
|
104
100
|
end
|
105
101
|
|
106
|
-
def valid_token?(token,
|
107
|
-
return false unless tokens[
|
108
|
-
return true if token_is_current?(token,
|
109
|
-
return true if token_can_be_reused?(token,
|
102
|
+
def valid_token?(token, client = 'default')
|
103
|
+
return false unless tokens[client]
|
104
|
+
return true if token_is_current?(token, client)
|
105
|
+
return true if token_can_be_reused?(token, client)
|
110
106
|
|
111
107
|
# return false if none of the above conditions are met
|
112
108
|
false
|
@@ -116,10 +112,10 @@ module DeviseTokenAuth::Concerns::User
|
|
116
112
|
# can be passed on from the client
|
117
113
|
def send_confirmation_notification?; false; end
|
118
114
|
|
119
|
-
def token_is_current?(token,
|
115
|
+
def token_is_current?(token, client)
|
120
116
|
# ghetto HashWithIndifferentAccess
|
121
|
-
expiry = tokens[
|
122
|
-
token_hash = tokens[
|
117
|
+
expiry = tokens[client]['expiry'] || tokens[client][:expiry]
|
118
|
+
token_hash = tokens[client]['token'] || tokens[client][:token]
|
123
119
|
|
124
120
|
return true if (
|
125
121
|
# ensure that expiry and token are set
|
@@ -134,10 +130,10 @@ module DeviseTokenAuth::Concerns::User
|
|
134
130
|
end
|
135
131
|
|
136
132
|
# allow batch requests to use the previous token
|
137
|
-
def token_can_be_reused?(token,
|
133
|
+
def token_can_be_reused?(token, client)
|
138
134
|
# ghetto HashWithIndifferentAccess
|
139
|
-
updated_at = tokens[
|
140
|
-
last_token = tokens[
|
135
|
+
updated_at = tokens[client]['updated_at'] || tokens[client][:updated_at]
|
136
|
+
last_token = tokens[client]['last_token'] || tokens[client][:last_token]
|
141
137
|
|
142
138
|
return true if (
|
143
139
|
# ensure that the last token and its creation time exist
|
@@ -147,40 +143,39 @@ module DeviseTokenAuth::Concerns::User
|
|
147
143
|
updated_at.to_time > Time.zone.now - DeviseTokenAuth.batch_request_buffer_throttle &&
|
148
144
|
|
149
145
|
# ensure that the token is valid
|
150
|
-
::
|
146
|
+
DeviseTokenAuth::TokenFactory.valid_token_hash?(last_token)
|
151
147
|
)
|
152
148
|
end
|
153
149
|
|
154
150
|
# update user's auth token (should happen on each request)
|
155
|
-
def create_new_auth_token(
|
151
|
+
def create_new_auth_token(client = nil)
|
156
152
|
now = Time.zone.now
|
157
153
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
last_token: tokens.fetch(client_id, {})['token'],
|
154
|
+
token = create_token(
|
155
|
+
client: client,
|
156
|
+
last_token: tokens.fetch(client, {})['token'],
|
162
157
|
updated_at: now
|
163
158
|
)
|
164
159
|
|
165
|
-
update_auth_header(token,
|
160
|
+
update_auth_header(token.token, token.client)
|
166
161
|
end
|
167
162
|
|
168
|
-
def build_auth_header(token,
|
163
|
+
def build_auth_header(token, client = 'default')
|
169
164
|
# client may use expiry to prevent validation request if expired
|
170
165
|
# must be cast as string or headers will break
|
171
|
-
expiry = tokens[
|
166
|
+
expiry = tokens[client]['expiry'] || tokens[client][:expiry]
|
172
167
|
|
173
168
|
{
|
174
169
|
DeviseTokenAuth.headers_names[:"access-token"] => token,
|
175
170
|
DeviseTokenAuth.headers_names[:"token-type"] => 'Bearer',
|
176
|
-
DeviseTokenAuth.headers_names[:"client"] =>
|
171
|
+
DeviseTokenAuth.headers_names[:"client"] => client,
|
177
172
|
DeviseTokenAuth.headers_names[:"expiry"] => expiry.to_s,
|
178
173
|
DeviseTokenAuth.headers_names[:"uid"] => uid
|
179
174
|
}
|
180
175
|
end
|
181
176
|
|
182
|
-
def update_auth_header(token,
|
183
|
-
headers = build_auth_header(token,
|
177
|
+
def update_auth_header(token, client = 'default')
|
178
|
+
headers = build_auth_header(token, client)
|
184
179
|
clean_old_tokens
|
185
180
|
save!
|
186
181
|
|
@@ -194,9 +189,9 @@ module DeviseTokenAuth::Concerns::User
|
|
194
189
|
DeviseTokenAuth::Url.generate(base_url, args)
|
195
190
|
end
|
196
191
|
|
197
|
-
def extend_batch_buffer(token,
|
198
|
-
tokens[
|
199
|
-
update_auth_header(token,
|
192
|
+
def extend_batch_buffer(token, client)
|
193
|
+
tokens[client]['updated_at'] = Time.zone.now
|
194
|
+
update_auth_header(token, client)
|
200
195
|
end
|
201
196
|
|
202
197
|
def confirmed?
|
@@ -207,10 +202,6 @@ module DeviseTokenAuth::Concerns::User
|
|
207
202
|
as_json(except: %i[tokens created_at updated_at])
|
208
203
|
end
|
209
204
|
|
210
|
-
def token_lifespan
|
211
|
-
DeviseTokenAuth.token_lifespan
|
212
|
-
end
|
213
|
-
|
214
205
|
protected
|
215
206
|
|
216
207
|
def destroy_expired_tokens
|
@@ -236,8 +227,8 @@ module DeviseTokenAuth::Concerns::User
|
|
236
227
|
return unless should_remove_tokens_after_password_reset?
|
237
228
|
|
238
229
|
if tokens.present? && tokens.many?
|
239
|
-
|
240
|
-
self.tokens = {
|
230
|
+
client, token_data = tokens.max_by { |cid, v| v[:expiry] || v['expiry'] }
|
231
|
+
self.tokens = { client => token_data }
|
241
232
|
end
|
242
233
|
end
|
243
234
|
|