devise_token_auth 1.2.6 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2950da8c6b3eac0a2a3ee2b1659d5e321ca9890e5a9b0a1525dcbf11e95d67dd
4
- data.tar.gz: d04830c1c12f69b3537e80fae17d5914b0b22272a52b78d7226a04be560cadea
3
+ metadata.gz: 0d50f68558fe641e4412661bdd4dfc15ce37b047300353cd4736c7e314c9fed9
4
+ data.tar.gz: e73de38339a0d663e78bf8e0abbb416b46078440b922a11cf9e49ff7ec2e6bc5
5
5
  SHA512:
6
- metadata.gz: 0a7e1dcce01dabc1e270926ff05b54c166d861232ef6ecf7547d88442e2d11ab7c104fef833312bf73a69dd5e3dd7df4923f050baf3e4aee877f32df6392d352
7
- data.tar.gz: b44b9aa57a43fb58e86a7985957e9a5d425787ae65e898b480d7fefe02bf573433f27af356512ae2a4989c3a6d9f0b91a9cc1a1b3b2ef3f95a4b39557472ffa7
6
+ metadata.gz: 7b2f6973ffc5ba8b3763f36eeda7581fd698cfe1c6a556e714ec32c94b7f21e9f2da9b5b871c59419c1a3f26249dc1d560cb28b03b228fa9c4e5a81a294c12c4
7
+ data.tar.gz: 6d14031a8a4269655bd4f0d9c03f39fc360112e331f1e1e14f583127d58effbe32d23d1a5852cdf5bb5b07fce6a8ae05f6391863ccbff4c8cf9020e09773496d
@@ -261,8 +261,13 @@ module DeviseTokenAuth::Concerns::User
261
261
  return if tokens.blank? || !max_client_tokens_exceeded?
262
262
 
263
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
264
+ # this handles the case where token lifespan was reduced and old tokens exist.
265
+ # The threshold MUST be computed the same way TokenFactory.expiry writes
266
+ # expiries — calendar advance (Time.zone.now + lifespan) — otherwise a
267
+ # calendar Duration (e.g. 2.months) and its average-seconds form
268
+ # (token_lifespan.to_i) disagree by hours, and the freshly minted token
269
+ # gets purged out from under the response.
270
+ max_lifespan_expiry = (Time.zone.now + DeviseTokenAuth.token_lifespan).to_i
266
271
  tokens_to_keep = tokens.select do |_cid, v|
267
272
  expiry = (v[:expiry] || v['expiry']).to_i
268
273
  expiry <= max_lifespan_expiry
@@ -76,7 +76,20 @@ module ActionDispatch::Routing
76
76
  match "#{full_path}/:provider", to: redirect(status: 307) { |params, request|
77
77
  # get the current querystring
78
78
  # TODO: deprecate in favor of using params
79
- qs = CGI::parse(request.env['QUERY_STRING'].empty? ? request.body.read : request.env['QUERY_STRING'] )
79
+ # `CGI.parse` is unavailable as of the cgi gem shipped with Ruby 3.5
80
+ # (pulled in by Rails 8.1). `Rack::Utils.parse_query` returns a bare
81
+ # value for single occurrences, so normalize to arrays to keep the
82
+ # shape `CGI.parse` returned.
83
+ # As of Rails 7.1 the request body may already have been read when
84
+ # this runs, in which case `read` returns "" and every param is
85
+ # silently dropped. Rewind first so POSTed params survive.
86
+ query_string = if request.env['QUERY_STRING'].empty?
87
+ request.body.rewind if request.body.respond_to?(:rewind)
88
+ request.body.read
89
+ else
90
+ request.env['QUERY_STRING']
91
+ end
92
+ qs = Rack::Utils.parse_query(query_string).transform_values { |v| Array(v) }
80
93
 
81
94
  # append name of current resource
82
95
  qs['resource_class'] = [resource]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeviseTokenAuth
4
- VERSION = '1.2.6'.freeze
4
+ VERSION = '1.3.0'.freeze
5
5
  end
@@ -62,8 +62,8 @@ class DeviseTokenAuth::ConfirmationsControllerTest < ActionController::TestCase
62
62
  end
63
63
 
64
64
  test 'redirect url includes token params' do
65
- assert @token_params.all? { |param| response.body.include?(param) }
66
- assert response.body.include?('account_confirmation_success')
65
+ assert @token_params.all? { |param| response.location.include?(param) }
66
+ assert response.location.include?('account_confirmation_success')
67
67
  end
68
68
  end
69
69
 
@@ -86,8 +86,8 @@ class DeviseTokenAuth::ConfirmationsControllerTest < ActionController::TestCase
86
86
  end
87
87
 
88
88
  test 'redirect url does not include token params' do
89
- refute @token_params.any? { |param| response.body.include?(param) }
90
- assert response.body.include?('account_confirmation_success')
89
+ refute @token_params.any? { |param| response.location.include?(param) }
90
+ assert response.location.include?('account_confirmation_success')
91
91
  end
92
92
  end
93
93
 
@@ -32,7 +32,10 @@ Rails.application.configure do
32
32
  config.action_controller.perform_caching = false
33
33
 
34
34
  # Raise exceptions instead of rendering exception templates.
35
- if Rails::VERSION::MAJOR >= 7 && Rails::VERSION::MINOR > 0
35
+ # Rails 7.1 turned this into an enum; `false` is no longer recognised and
36
+ # falls through to the "show everything" default. Note the version check must
37
+ # not be `MAJOR >= 7 && MINOR > 0`, which is false on Rails 8.0.
38
+ if Rails.gem_version >= Gem::Version.new('7.1')
36
39
  config.action_dispatch.show_exceptions = :none
37
40
  else
38
41
  config.action_dispatch.show_exceptions = false
@@ -7,11 +7,12 @@ class DeviseTokenAuth::CustomRoutesTest < ActiveSupport::TestCase
7
7
  Rails.application.reload_routes!
8
8
  end
9
9
  test 'custom controllers' do
10
- class ActionDispatch::Routing::Mapper
11
- include Mocha::ParameterMatchers
12
- end
13
10
  Rails.application.routes.draw do
14
- self.expects(:devise_for).with(
11
+ mapper = self
12
+ mapper.singleton_class.include(Mocha::API)
13
+ mapper.singleton_class.include(Mocha::ParameterMatchers)
14
+
15
+ mapper.expects(:devise_for).with(
15
16
  :users,
16
17
  has_entries(
17
18
  controllers: has_entries(
@@ -220,5 +220,32 @@ class UserTest < ActiveSupport::TestCase
220
220
  # We should have exactly 2 tokens: the new one and client_3
221
221
  assert_equal 2, @resource.tokens.length
222
222
  end
223
+
224
+ # Regression: with a calendar ActiveSupport::Duration lifespan, the token
225
+ # expiry is advanced by calendar (Time.zone.now + 2.months) while the old
226
+ # eager purge compared against an average-seconds threshold
227
+ # (token_lifespan.to_i). The freshly minted token's expiry sat just past
228
+ # that threshold and was silently dropped, leaving a 200 response whose
229
+ # advertised access-token no longer existed in user.tokens.
230
+ test 'keeps the freshly created token at the device cap with a calendar lifespan' do
231
+ DeviseTokenAuth.max_number_of_devices = 2
232
+ DeviseTokenAuth.token_lifespan = 2.months
233
+
234
+ # Fill the cap with tokens created a few hours ago (calendar expiry).
235
+ old_time = 4.hours.ago
236
+ @resource.tokens = {}
237
+ %w[client_1 client_2].each do |client|
238
+ @resource.tokens[client] = {
239
+ 'token' => 'x',
240
+ 'expiry' => (old_time + DeviseTokenAuth.token_lifespan).to_i
241
+ }
242
+ end
243
+
244
+ tok = @resource.create_token
245
+
246
+ assert @resource.tokens.key?(tok.client),
247
+ 'Freshly created token must survive clean_old_tokens'
248
+ assert_equal DeviseTokenAuth.max_number_of_devices, @resource.tokens.length
249
+ end
223
250
  end
224
251
  end
data/test/test_helper.rb CHANGED
@@ -38,7 +38,14 @@ end
38
38
  class ActiveSupport::TestCase
39
39
  include FactoryBot::Syntax::Methods
40
40
 
41
- ActiveRecord::Migration.check_pending! if DEVISE_TOKEN_AUTH_ORM == :active_record
41
+ if DEVISE_TOKEN_AUTH_ORM == :active_record
42
+ # `check_pending!` was deprecated in Rails 7.1 and removed in Rails 8.0
43
+ if ActiveRecord::Migration.respond_to?(:check_all_pending!)
44
+ ActiveRecord::Migration.check_all_pending!
45
+ else
46
+ ActiveRecord::Migration.check_pending!
47
+ end
48
+ end
42
49
 
43
50
  strategies = { active_record: :transaction,
44
51
  mongoid: :deletion }
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.6
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lynn Hurley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-11-21 00:00:00.000000000 Z
11
+ date: 2026-07-31 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: '8.2'
22
+ version: '8.3'
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: '8.2'
32
+ version: '8.3'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: devise
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: 3.5.2
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '5'
42
+ version: '6'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  version: 3.5.2
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '5'
52
+ version: '6'
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: bcrypt
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -82,16 +82,22 @@ dependencies:
82
82
  name: sqlite3
83
83
  requirement: !ruby/object:Gem::Requirement
84
84
  requirements:
85
- - - "~>"
85
+ - - ">="
86
86
  - !ruby/object:Gem::Version
87
87
  version: '1.4'
88
+ - - "<"
89
+ - !ruby/object:Gem::Version
90
+ version: '3.0'
88
91
  type: :development
89
92
  prerelease: false
90
93
  version_requirements: !ruby/object:Gem::Requirement
91
94
  requirements:
92
- - - "~>"
95
+ - - ">="
93
96
  - !ruby/object:Gem::Version
94
97
  version: '1.4'
98
+ - - "<"
99
+ - !ruby/object:Gem::Version
100
+ version: '3.0'
95
101
  - !ruby/object:Gem::Dependency
96
102
  name: pg
97
103
  requirement: !ruby/object:Gem::Requirement
@@ -129,7 +135,7 @@ dependencies:
129
135
  version: '4'
130
136
  - - "<"
131
137
  - !ruby/object:Gem::Version
132
- version: '8'
138
+ version: '10'
133
139
  type: :development
134
140
  prerelease: false
135
141
  version_requirements: !ruby/object:Gem::Requirement
@@ -139,7 +145,7 @@ dependencies:
139
145
  version: '4'
140
146
  - - "<"
141
147
  - !ruby/object:Gem::Version
142
- version: '8'
148
+ version: '10'
143
149
  - !ruby/object:Gem::Dependency
144
150
  name: mongoid-locker
145
151
  requirement: !ruby/object:Gem::Requirement