##// END OF EJS Templates
Allow "stay logged in" from multiple browsers (#10840)....
Jean-Philippe Lang -
r15792:5d4b5fd1f68a
parent child
Show More
@@ -25,18 +25,70 class Token < ActiveRecord::Base
25 cattr_accessor :validity_time
25 cattr_accessor :validity_time
26 self.validity_time = 1.day
26 self.validity_time = 1.day
27
27
28 class << self
29 attr_reader :actions
30
31 def add_action(name, options)
32 options.assert_valid_keys(:max_instances, :validity_time)
33 @actions ||= {}
34 @actions[name.to_s] = options
35 end
36 end
37
38 add_action :api, max_instances: 1, validity_time: nil
39 add_action :autologin, max_instances: 10, validity_time: Proc.new { Setting.autologin.to_i.days }
40 add_action :feeds, max_instances: 1, validity_time: nil
41 add_action :recovery, max_instances: 1, validity_time: Proc.new { Token.validity_time }
42 add_action :register, max_instances: 1, validity_time: Proc.new { Token.validity_time }
43 add_action :session, max_instances: 10, validity_time: nil
44
28 def generate_new_token
45 def generate_new_token
29 self.value = Token.generate_token_value
46 self.value = Token.generate_token_value
30 end
47 end
31
48
32 # Return true if token has expired
49 # Return true if token has expired
33 def expired?
50 def expired?
34 return Time.now > self.created_on + self.class.validity_time
51 return created_on < self.class.invalid_when_created_before(action)
52 end
53
54 def max_instances
55 Token.actions.has_key?(action) ? Token.actions[action][:max_instances] : 1
56 end
57
58 def self.invalid_when_created_before(action = nil)
59 if Token.actions.has_key?(action)
60 validity_time = Token.actions[action][:validity_time]
61 validity_time = validity_time.call(action) if validity_time.respond_to? :call
62 else
63 validity_time = self.validity_time
64 end
65
66 if validity_time.nil?
67 0
68 else
69 Time.now - validity_time
70 end
35 end
71 end
36
72
37 # Delete all expired tokens
73 # Delete all expired tokens
38 def self.destroy_expired
74 def self.destroy_expired
39 Token.where("action NOT IN (?) AND created_on < ?", ['feeds', 'api', 'session'], Time.now - validity_time).delete_all
75 t = Token.arel_table
76
77 # Unknown actions have default validity_time
78 condition = t[:action].not_in(self.actions.keys).and(t[:created_on].lt(invalid_when_created_before))
79
80 self.actions.each do |action, options|
81 validity_time = invalid_when_created_before(action)
82
83 # Do not delete tokens, which don't become invalid
84 next if validity_time.nil?
85
86 condition = condition.or(
87 t[:action].eq(action).and(t[:created_on].lt(validity_time))
88 )
89 end
90
91 Token.where(condition).delete_all
40 end
92 end
41
93
42 # Returns the active user who owns the key for the given action
94 # Returns the active user who owns the key for the given action
@@ -80,8 +132,8 class Token < ActiveRecord::Base
80 def delete_previous_tokens
132 def delete_previous_tokens
81 if user
133 if user
82 scope = Token.where(:user_id => user.id, :action => action)
134 scope = Token.where(:user_id => user.id, :action => action)
83 if action == 'session'
135 if max_instances > 1
84 ids = scope.order(:updated_on => :desc).offset(9).ids
136 ids = scope.order(:updated_on => :desc).offset(max_instances - 1).ids
85 if ids.any?
137 if ids.any?
86 Token.delete(ids)
138 Token.delete(ids)
87 end
139 end
@@ -29,31 +29,34 class TokenTest < ActiveSupport::TestCase
29
29
30 def test_create_should_remove_existing_tokens
30 def test_create_should_remove_existing_tokens
31 user = User.find(1)
31 user = User.find(1)
32 t1 = Token.create(:user => user, :action => 'autologin')
32 t1 = Token.create(:user => user, :action => 'register')
33 t2 = Token.create(:user => user, :action => 'autologin')
33 t2 = Token.create(:user => user, :action => 'register')
34 assert_not_equal t1.value, t2.value
34 assert_not_equal t1.value, t2.value
35 assert !Token.exists?(t1.id)
35 assert !Token.exists?(t1.id)
36 assert Token.exists?(t2.id)
36 assert Token.exists?(t2.id)
37 end
37 end
38
38
39 def test_create_session_token_should_keep_last_10_tokens
39 def test_create_session_or_autologin_token_should_keep_last_10_tokens
40 Token.delete_all
40 Token.delete_all
41 user = User.find(1)
41 user = User.find(1)
42
42
43 assert_difference 'Token.count', 10 do
43 ["autologin", "session"].each do |action|
44 10.times { Token.create!(:user => user, :action => 'session') }
44 assert_difference 'Token.count', 10 do
45 end
45 10.times { Token.create!(:user => user, :action => action) }
46 end
46
47
47 assert_no_difference 'Token.count' do
48 assert_no_difference 'Token.count' do
48 Token.create!(:user => user, :action => 'session')
49 Token.create!(:user => user, :action => action)
50 end
49 end
51 end
50 end
52 end
51
53
52 def test_destroy_expired_should_not_destroy_feeds_and_api_tokens
54 def test_destroy_expired_should_not_destroy_session_feeds_and_api_tokens
53 Token.delete_all
55 Token.delete_all
54
56
55 Token.create!(:user_id => 1, :action => 'api', :created_on => 7.days.ago)
57 Token.create!(:user_id => 1, :action => 'api', :created_on => 7.days.ago)
56 Token.create!(:user_id => 1, :action => 'feeds', :created_on => 7.days.ago)
58 Token.create!(:user_id => 1, :action => 'feeds', :created_on => 7.days.ago)
59 Token.create!(:user_id => 1, :action => 'session', :created_on => 7.days.ago)
57
60
58 assert_no_difference 'Token.count' do
61 assert_no_difference 'Token.count' do
59 assert_equal 0, Token.destroy_expired
62 assert_equal 0, Token.destroy_expired
@@ -63,12 +66,24 class TokenTest < ActiveSupport::TestCase
63 def test_destroy_expired_should_destroy_expired_tokens
66 def test_destroy_expired_should_destroy_expired_tokens
64 Token.delete_all
67 Token.delete_all
65
68
66 Token.create!(:user_id => 1, :action => 'autologin', :created_on => 7.days.ago)
69 # Expiration of autologin tokens is determined by Setting.autologin
67 Token.create!(:user_id => 2, :action => 'autologin', :created_on => 3.days.ago)
70 Setting.autologin = "7"
68 Token.create!(:user_id => 3, :action => 'autologin', :created_on => 1.hour.ago)
71 Token.create!(:user_id => 2, :action => 'autologin', :created_on => 3.weeks.ago)
72 Token.create!(:user_id => 3, :action => 'autologin', :created_on => 3.days.ago)
73
74 # Expiration of register and recovery tokens is determined by Token.validity_time
75 Token.create!(:user_id => 1, :action => 'register', :created_on => 7.days.ago)
76 Token.create!(:user_id => 3, :action => 'register', :created_on => 7.hours.ago)
77
78 Token.create!(:user_id => 2, :action => 'recovery', :created_on => 3.days.ago)
79 Token.create!(:user_id => 3, :action => 'recovery', :created_on => 3.hours.ago)
80
81 # Expiration of tokens with unknown action is determined by Token.validity_time
82 Token.create!(:user_id => 2, :action => 'unknown_action', :created_on => 2.days.ago)
83 Token.create!(:user_id => 3, :action => 'unknown_action', :created_on => 2.hours.ago)
69
84
70 assert_difference 'Token.count', -2 do
85 assert_difference 'Token.count', -4 do
71 assert_equal 2, Token.destroy_expired
86 assert_equal 4, Token.destroy_expired
72 end
87 end
73 end
88 end
74
89
General Comments 0
You need to be logged in to leave comments. Login now