activerecord-session_store 2.2.0 → 2.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 +4 -4
- data/CHANGELOG.md +1 -3
- data/README.md +11 -0
- data/lib/action_dispatch/session/active_record_store.rb +43 -14
- data/lib/active_record/session_store/railtie.rb +4 -0
- data/lib/active_record/session_store/session.rb +8 -1
- data/lib/active_record/session_store/sql_bypass.rb +16 -4
- data/lib/active_record/session_store/version.rb +1 -1
- data/lib/active_record/session_store.rb +7 -0
- metadata +10 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d410be8bc8f2608aab6f3362f842ffe56498e018ca813afb080096af80ed3c1
|
|
4
|
+
data.tar.gz: 4e520360edec22efb0647ce4aea99f4dd3996483e0ea8d8d95b59c3b8c49e8c6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c0a67cf16741647e87c32630beef7b5d51c978037eecb54157eb721d154a5081dbe2b340591b1c1f6b9597ec63aee1dbe6d865cfa82a3a375b2fe37cd249e8cb
|
|
7
|
+
data.tar.gz: 17b50e63572cebaf5bec61db9d1400908f947ef112cd386505022c1386914ca6520176979b64d16532747854ff273baf9dbb060c8e7c571769f54743ba8678ae
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
|
@@ -38,6 +38,13 @@ been updated in the last 30 days. The 30 days cutoff can be changed using the
|
|
|
38
38
|
Configuration
|
|
39
39
|
--------------
|
|
40
40
|
|
|
41
|
+
Disable fallback to use insecure session by providing the option
|
|
42
|
+
`secure_session_only` when setting up the session store.
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
Rails.application.config.session_store :active_record_store, key: '_my_app_session', secure_session_only: true
|
|
46
|
+
```
|
|
47
|
+
|
|
41
48
|
The default assumes a `sessions` table with columns:
|
|
42
49
|
|
|
43
50
|
* `id` (numeric primary key),
|
|
@@ -136,6 +143,10 @@ $ rake db:sessions:upgrade
|
|
|
136
143
|
This rake task is idempotent and can be run multiple times, and session data of
|
|
137
144
|
users will remain intact.
|
|
138
145
|
|
|
146
|
+
If you are using a custom class for storing your sessions (as described earlier
|
|
147
|
+
in `Configuration`), you need to copy and adapt this task or add a migration
|
|
148
|
+
containing equivalent code.
|
|
149
|
+
|
|
139
150
|
Please see [#151] for more details.
|
|
140
151
|
|
|
141
152
|
[#151]: https://github.com/rails/activerecord-session_store/pull/151
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require "active_support/core_ext/module/attribute_accessors"
|
|
2
|
-
require
|
|
2
|
+
require "action_dispatch/middleware/session/abstract_store"
|
|
3
3
|
|
|
4
4
|
module ActionDispatch
|
|
5
5
|
module Session
|
|
@@ -57,8 +57,16 @@ module ActionDispatch
|
|
|
57
57
|
# ActiveRecord::SessionStore::Session
|
|
58
58
|
class_attribute :session_class
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
DEFAULT_SAME_SITE = proc { |request| request.cookies_same_site_protection } # :nodoc:
|
|
61
61
|
ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS
|
|
62
|
+
SESSION_RECORD_KEY = "rack.session.record"
|
|
63
|
+
SESSION_RECORD_CREATED_KEY = "rack.session.record.created"
|
|
64
|
+
|
|
65
|
+
def initialize(app, options = {})
|
|
66
|
+
@secure_session_only = options.delete(:secure_session_only) { false }
|
|
67
|
+
options[:same_site] = DEFAULT_SAME_SITE unless options.key?(:same_site)
|
|
68
|
+
super
|
|
69
|
+
end
|
|
62
70
|
|
|
63
71
|
private
|
|
64
72
|
def get_session(request, sid)
|
|
@@ -78,6 +86,7 @@ module ActionDispatch
|
|
|
78
86
|
logger.silence do
|
|
79
87
|
record, sid = get_session_model(request, sid)
|
|
80
88
|
record.data = session_data
|
|
89
|
+
return sid unless record.changed? || record.new_record?
|
|
81
90
|
return false unless record.save
|
|
82
91
|
|
|
83
92
|
session_data = record.data
|
|
@@ -117,26 +126,47 @@ module ActionDispatch
|
|
|
117
126
|
|
|
118
127
|
def get_session_model(request, id)
|
|
119
128
|
logger.silence do
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
id = generate_sid
|
|
123
|
-
model = session_class.new(:session_id => id.private_id, :data => {})
|
|
124
|
-
model.save
|
|
125
|
-
end
|
|
126
|
-
if request.env[ENV_SESSION_OPTIONS_KEY][:id].nil?
|
|
127
|
-
request.env[SESSION_RECORD_KEY] = model
|
|
129
|
+
if can_reuse_session_record?(request, id)
|
|
130
|
+
model = request.env[SESSION_RECORD_KEY]
|
|
128
131
|
else
|
|
129
|
-
|
|
132
|
+
model = get_session_with_fallback(id)
|
|
133
|
+
|
|
134
|
+
new_record = false
|
|
135
|
+
|
|
136
|
+
unless model
|
|
137
|
+
id = generate_sid
|
|
138
|
+
model = session_class.new(:session_id => id.private_id, :data => {})
|
|
139
|
+
model.save
|
|
140
|
+
new_record = true
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
if request.env[ENV_SESSION_OPTIONS_KEY][:id].nil?
|
|
144
|
+
request.env[SESSION_RECORD_KEY] = model
|
|
145
|
+
request.env[SESSION_RECORD_CREATED_KEY] = new_record
|
|
146
|
+
else
|
|
147
|
+
unless request.env[SESSION_RECORD_KEY]
|
|
148
|
+
request.env[SESSION_RECORD_KEY] = model
|
|
149
|
+
request.env[SESSION_RECORD_CREATED_KEY] = new_record
|
|
150
|
+
end
|
|
151
|
+
end
|
|
130
152
|
end
|
|
153
|
+
|
|
131
154
|
[model, id]
|
|
132
155
|
end
|
|
133
156
|
end
|
|
134
157
|
|
|
158
|
+
def can_reuse_session_record?(request, id)
|
|
159
|
+
id &&
|
|
160
|
+
!request.env[SESSION_RECORD_CREATED_KEY] &&
|
|
161
|
+
(model = request.env[SESSION_RECORD_KEY]) &&
|
|
162
|
+
model.session_id == id.private_id
|
|
163
|
+
end
|
|
164
|
+
|
|
135
165
|
def get_session_with_fallback(sid)
|
|
136
|
-
if sid && !self.class.private_session_id?(sid.public_id)
|
|
166
|
+
if sid && sid.public_id.valid_encoding? && !self.class.private_session_id?(sid.public_id)
|
|
137
167
|
if (secure_session = session_class.find_by_session_id(sid.private_id))
|
|
138
168
|
secure_session
|
|
139
|
-
elsif (insecure_session = session_class.find_by_session_id(sid.public_id))
|
|
169
|
+
elsif !@secure_session_only && (insecure_session = session_class.find_by_session_id(sid.public_id))
|
|
140
170
|
insecure_session.session_id = sid.private_id # this causes the session to be secured
|
|
141
171
|
insecure_session
|
|
142
172
|
end
|
|
@@ -162,7 +192,6 @@ module ActionDispatch
|
|
|
162
192
|
# user tried to retrieve a session by a private key?
|
|
163
193
|
session_id =~ /\A\d+::/
|
|
164
194
|
end
|
|
165
|
-
|
|
166
195
|
end
|
|
167
196
|
end
|
|
168
197
|
end
|
|
@@ -4,6 +4,10 @@ module ActiveRecord
|
|
|
4
4
|
module SessionStore
|
|
5
5
|
class Railtie < Rails::Railtie
|
|
6
6
|
rake_tasks { load File.expand_path("../../../tasks/database.rake", __FILE__) }
|
|
7
|
+
|
|
8
|
+
initializer "activerecord-session_store.deprecator" do |app|
|
|
9
|
+
app.deprecators[:"activerecord-session_store"] = SessionStore.deprecator
|
|
10
|
+
end
|
|
7
11
|
end
|
|
8
12
|
end
|
|
9
13
|
end
|
|
@@ -38,6 +38,10 @@ module ActiveRecord
|
|
|
38
38
|
# Reset column info since it may be stale.
|
|
39
39
|
reset_column_information
|
|
40
40
|
if columns_hash['sessid']
|
|
41
|
+
SessionStore.deprecator.warn <<~MSG
|
|
42
|
+
Using a session ID column other than `session_id` is deprecated without replacement. You should migrate your session table to use `session_id`.
|
|
43
|
+
MSG
|
|
44
|
+
|
|
41
45
|
def self.find_by_session_id(session_id)
|
|
42
46
|
find_by_sessid(session_id)
|
|
43
47
|
end
|
|
@@ -64,7 +68,10 @@ module ActiveRecord
|
|
|
64
68
|
@data ||= self.class.deserialize(read_attribute(@@data_column_name)) || {}
|
|
65
69
|
end
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
def data=(data)
|
|
72
|
+
attribute_will_change!(@@data_column_name) if data != self.data
|
|
73
|
+
@data = data
|
|
74
|
+
end
|
|
68
75
|
|
|
69
76
|
# Has the session been loaded yet?
|
|
70
77
|
def loaded?
|
|
@@ -72,8 +72,6 @@ module ActiveRecord
|
|
|
72
72
|
attr_accessor :session_id
|
|
73
73
|
alias :new_record? :new_record
|
|
74
74
|
|
|
75
|
-
attr_writer :data
|
|
76
|
-
|
|
77
75
|
# Look for normal and serialized data, self.find_by_session_id's way of
|
|
78
76
|
# telling us to postpone deserializing until the data is requested.
|
|
79
77
|
# We need to handle a normal data attribute in case of a new record.
|
|
@@ -83,6 +81,7 @@ module ActiveRecord
|
|
|
83
81
|
@data = attributes[:data]
|
|
84
82
|
@serialized_data = attributes[:serialized_data]
|
|
85
83
|
@new_record = @serialized_data.nil?
|
|
84
|
+
@data_changed = false
|
|
86
85
|
end
|
|
87
86
|
|
|
88
87
|
# Returns true if the record is persisted, i.e. it's not a new record
|
|
@@ -106,6 +105,15 @@ module ActiveRecord
|
|
|
106
105
|
@data
|
|
107
106
|
end
|
|
108
107
|
|
|
108
|
+
def data=(data)
|
|
109
|
+
@data_changed = true if data != self.data
|
|
110
|
+
@data = data
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def changed?
|
|
114
|
+
persisted? && (@retrieved_by != session_id || @data_changed)
|
|
115
|
+
end
|
|
116
|
+
|
|
109
117
|
def save
|
|
110
118
|
return false unless loaded?
|
|
111
119
|
serialized_data = self.class.serialize(data)
|
|
@@ -113,7 +121,7 @@ module ActiveRecord
|
|
|
113
121
|
|
|
114
122
|
if @new_record
|
|
115
123
|
@new_record = false
|
|
116
|
-
connect.update <<-end_sql, 'Create session'
|
|
124
|
+
result = connect.update <<-end_sql, 'Create session'
|
|
117
125
|
INSERT INTO #{table_name} (
|
|
118
126
|
#{connect.quote_column_name(session_id_column)},
|
|
119
127
|
#{connect.quote_column_name(data_column)} )
|
|
@@ -122,7 +130,7 @@ module ActiveRecord
|
|
|
122
130
|
#{connect.quote(serialized_data)} )
|
|
123
131
|
end_sql
|
|
124
132
|
else
|
|
125
|
-
connect.update <<-end_sql, 'Update session'
|
|
133
|
+
result = connect.update <<-end_sql, 'Update session'
|
|
126
134
|
UPDATE #{table_name}
|
|
127
135
|
SET
|
|
128
136
|
#{connect.quote_column_name(data_column)}=#{connect.quote(serialized_data)},
|
|
@@ -130,6 +138,10 @@ module ActiveRecord
|
|
|
130
138
|
WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(@retrieved_by)}
|
|
131
139
|
end_sql
|
|
132
140
|
end
|
|
141
|
+
|
|
142
|
+
@retrieved_by = @session_id
|
|
143
|
+
@data_changed = false
|
|
144
|
+
result
|
|
133
145
|
end
|
|
134
146
|
|
|
135
147
|
def destroy
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'active_record'
|
|
2
2
|
require 'active_record/session_store/version'
|
|
3
3
|
require 'action_dispatch/session/active_record_store'
|
|
4
|
+
require 'active_support'
|
|
4
5
|
require 'active_support/core_ext/hash/keys'
|
|
5
6
|
require 'json'
|
|
6
7
|
|
|
@@ -8,6 +9,12 @@ module ActiveRecord
|
|
|
8
9
|
module SessionStore
|
|
9
10
|
autoload :Session, 'active_record/session_store/session'
|
|
10
11
|
|
|
12
|
+
class << self
|
|
13
|
+
def deprecator
|
|
14
|
+
@deprecator ||= ActiveSupport::Deprecation.new("3.0", "ActiveRecord::SessionStore")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
11
18
|
module ClassMethods # :nodoc:
|
|
12
19
|
mattr_accessor :serializer
|
|
13
20
|
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-session_store
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Heinemeier Hansson
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activerecord
|
|
@@ -15,42 +15,42 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '7.
|
|
18
|
+
version: '7.1'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '7.
|
|
25
|
+
version: '7.1'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: actionpack
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '7.
|
|
32
|
+
version: '7.1'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '7.
|
|
39
|
+
version: '7.1'
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: railties
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '7.
|
|
46
|
+
version: '7.1'
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - ">="
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '7.
|
|
53
|
+
version: '7.1'
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: rack
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -120,14 +120,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
120
120
|
requirements:
|
|
121
121
|
- - ">="
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: 2.
|
|
123
|
+
version: 2.7.0
|
|
124
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
requirements:
|
|
126
126
|
- - ">="
|
|
127
127
|
- !ruby/object:Gem::Version
|
|
128
128
|
version: '0'
|
|
129
129
|
requirements: []
|
|
130
|
-
rubygems_version: 3.6.
|
|
130
|
+
rubygems_version: 3.6.7
|
|
131
131
|
specification_version: 4
|
|
132
132
|
summary: An Action Dispatch session store backed by an Active Record class.
|
|
133
133
|
test_files: []
|