mongo_session_store 3.2.1 → 3.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/.github/workflows/ci.yml +136 -0
- data/.github/workflows/danger-comment.yml +17 -0
- data/.github/workflows/danger.yml +53 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +15 -6
- data/.rubocop_todo.yml +195 -0
- data/CHANGELOG.md +20 -13
- data/Dangerfile +5 -1
- data/Gemfile +2 -0
- data/Gemfile.danger +5 -0
- data/README.md +71 -9
- data/RELEASING.md +37 -0
- data/docker-compose.yml +5 -0
- data/gemfiles/rails-5.1-mongoid.gemfile +1 -1
- data/gemfiles/rails-6.0-mongo.gemfile +4 -1
- data/gemfiles/rails-6.0-mongoid.gemfile +4 -1
- data/gemfiles/rails-8.1-mongo.gemfile +15 -0
- data/gemfiles/rails-8.1-mongoid.gemfile +15 -0
- data/gemfiles/rails-current-mongo.gemfile +16 -0
- data/gemfiles/rails-current-mongoid.gemfile +3 -0
- data/lib/mongo_session_store/mongo_store.rb +1 -1
- data/lib/mongo_session_store/mongo_store_base.rb +7 -0
- data/lib/mongo_session_store/mongoid_store.rb +1 -0
- data/lib/mongo_session_store/version.rb +1 -1
- data/mongo_session_store.gemspec +4 -7
- data/script/test +20 -0
- data/script/test_inner +19 -0
- data/script/testenv +6 -0
- data/spec/.rubocop.yml +1 -1
- data/spec/integrations/devise_spec.rb +2 -2
- data/spec/lib/mongo_session_store/legacy_serialization_spec.rb +17 -0
- data/spec/lib/mongo_session_store/serialization_spec.rb +36 -0
- data/spec/lib/mongo_session_store/stale_sessions_spec.rb +77 -0
- data/spec/lib/mongo_session_store/version_spec.rb +8 -0
- data/spec/rails_helper.rb +4 -0
- data/spec/spec_helper.rb +14 -2
- data/spec/support/apps/rails_6.0_app/config/database.yml +9 -3
- data/spec/support/apps/rails_6.0_app/config/environments/test.rb +1 -1
- data/spec/support/helpers/test_database_helper.rb +1 -3
- data/spec/support/rack_app.rb +3 -1
- metadata +42 -235
- data/.travis.yml +0 -109
- data/gemfiles/rails-4.0-mongo.gemfile +0 -9
- data/gemfiles/rails-4.0-mongoid.gemfile +0 -9
- data/gemfiles/rails-4.1-mongo.gemfile +0 -9
- data/gemfiles/rails-4.1-mongoid.gemfile +0 -9
- data/gemfiles/rails-4.2-mongo.gemfile +0 -9
- data/gemfiles/rails-4.2-mongoid.gemfile +0 -9
- data/spec/support/apps/rails_4.0_app/Rakefile +0 -6
- data/spec/support/apps/rails_4.0_app/app/controllers/application_controller.rb +0 -5
- data/spec/support/apps/rails_4.0_app/app/controllers/home_controller.rb +0 -2
- data/spec/support/apps/rails_4.0_app/app/models/user.rb +0 -5
- data/spec/support/apps/rails_4.0_app/app/views/home/index.html.erb +0 -9
- data/spec/support/apps/rails_4.0_app/app/views/layouts/application.html.erb +0 -17
- data/spec/support/apps/rails_4.0_app/bin/bundle +0 -3
- data/spec/support/apps/rails_4.0_app/bin/rails +0 -4
- data/spec/support/apps/rails_4.0_app/bin/rake +0 -4
- data/spec/support/apps/rails_4.0_app/config/application.rb +0 -11
- data/spec/support/apps/rails_4.0_app/config/boot.rb +0 -4
- data/spec/support/apps/rails_4.0_app/config/database.yml +0 -11
- data/spec/support/apps/rails_4.0_app/config/environment.rb +0 -5
- data/spec/support/apps/rails_4.0_app/config/environments/development.rb +0 -12
- data/spec/support/apps/rails_4.0_app/config/environments/test.rb +0 -19
- data/spec/support/apps/rails_4.0_app/config/initializers/devise.rb +0 -254
- data/spec/support/apps/rails_4.0_app/config/initializers/secret_token.rb +0 -12
- data/spec/support/apps/rails_4.0_app/config/initializers/session_store.rb +0 -1
- data/spec/support/apps/rails_4.0_app/config/locales/devise.en.yml +0 -59
- data/spec/support/apps/rails_4.0_app/config/locales/en.yml +0 -23
- data/spec/support/apps/rails_4.0_app/config/mongo.yml +0 -11
- data/spec/support/apps/rails_4.0_app/config/mongoid.yml +0 -13
- data/spec/support/apps/rails_4.0_app/config/routes.rb +0 -5
- data/spec/support/apps/rails_4.0_app/config.ru +0 -4
- data/spec/support/apps/rails_4.0_app/db/migrate/20140301171212_add_devise_users.rb +0 -11
- data/spec/support/apps/rails_4.0_app/db/schema.rb +0 -25
- data/spec/support/apps/rails_4.0_app/lib/assets/.keep +0 -0
- data/spec/support/apps/rails_4.0_app/lib/tasks/.keep +0 -0
- data/spec/support/apps/rails_4.0_app/log/.keep +0 -0
- data/spec/support/apps/rails_4.1_app/Rakefile +0 -3
- data/spec/support/apps/rails_4.1_app/app/controllers/application_controller.rb +0 -5
- data/spec/support/apps/rails_4.1_app/app/controllers/home_controller.rb +0 -2
- data/spec/support/apps/rails_4.1_app/app/models/user.rb +0 -5
- data/spec/support/apps/rails_4.1_app/app/views/home/index.html.erb +0 -9
- data/spec/support/apps/rails_4.1_app/app/views/layouts/application.html.erb +0 -17
- data/spec/support/apps/rails_4.1_app/bin/bundle +0 -3
- data/spec/support/apps/rails_4.1_app/bin/rails +0 -4
- data/spec/support/apps/rails_4.1_app/bin/rake +0 -4
- data/spec/support/apps/rails_4.1_app/config/application.rb +0 -11
- data/spec/support/apps/rails_4.1_app/config/boot.rb +0 -4
- data/spec/support/apps/rails_4.1_app/config/database.yml +0 -11
- data/spec/support/apps/rails_4.1_app/config/environment.rb +0 -5
- data/spec/support/apps/rails_4.1_app/config/environments/development.rb +0 -12
- data/spec/support/apps/rails_4.1_app/config/environments/test.rb +0 -19
- data/spec/support/apps/rails_4.1_app/config/initializers/devise.rb +0 -254
- data/spec/support/apps/rails_4.1_app/config/initializers/session_store.rb +0 -1
- data/spec/support/apps/rails_4.1_app/config/locales/devise.en.yml +0 -59
- data/spec/support/apps/rails_4.1_app/config/locales/en.yml +0 -23
- data/spec/support/apps/rails_4.1_app/config/mongo.yml +0 -11
- data/spec/support/apps/rails_4.1_app/config/mongoid.yml +0 -13
- data/spec/support/apps/rails_4.1_app/config/routes.rb +0 -5
- data/spec/support/apps/rails_4.1_app/config/secrets.yml +0 -22
- data/spec/support/apps/rails_4.1_app/config.ru +0 -2
- data/spec/support/apps/rails_4.1_app/db/migrate/20140301171212_add_devise_users.rb +0 -11
- data/spec/support/apps/rails_4.1_app/db/schema.rb +0 -25
- data/spec/support/apps/rails_4.1_app/lib/assets/.keep +0 -0
- data/spec/support/apps/rails_4.1_app/lib/tasks/.keep +0 -0
- data/spec/support/apps/rails_4.1_app/log/.keep +0 -0
- data/spec/support/apps/rails_4.2_app/Rakefile +0 -2
- data/spec/support/apps/rails_4.2_app/app/controllers/application_controller.rb +0 -5
- data/spec/support/apps/rails_4.2_app/app/controllers/home_controller.rb +0 -2
- data/spec/support/apps/rails_4.2_app/app/models/user.rb +0 -5
- data/spec/support/apps/rails_4.2_app/app/views/home/index.html.erb +0 -9
- data/spec/support/apps/rails_4.2_app/app/views/layouts/application.html.erb +0 -15
- data/spec/support/apps/rails_4.2_app/bin/bundle +0 -3
- data/spec/support/apps/rails_4.2_app/bin/rails +0 -8
- data/spec/support/apps/rails_4.2_app/bin/rake +0 -4
- data/spec/support/apps/rails_4.2_app/config/application.rb +0 -11
- data/spec/support/apps/rails_4.2_app/config/boot.rb +0 -3
- data/spec/support/apps/rails_4.2_app/config/database.yml +0 -11
- data/spec/support/apps/rails_4.2_app/config/environment.rb +0 -5
- data/spec/support/apps/rails_4.2_app/config/environments/development.rb +0 -12
- data/spec/support/apps/rails_4.2_app/config/environments/test.rb +0 -19
- data/spec/support/apps/rails_4.2_app/config/initializers/devise.rb +0 -254
- data/spec/support/apps/rails_4.2_app/config/initializers/session_store.rb +0 -1
- data/spec/support/apps/rails_4.2_app/config/locales/en.yml +0 -23
- data/spec/support/apps/rails_4.2_app/config/mongo.yml +0 -11
- data/spec/support/apps/rails_4.2_app/config/mongoid.yml +0 -13
- data/spec/support/apps/rails_4.2_app/config/routes.rb +0 -5
- data/spec/support/apps/rails_4.2_app/config/secrets.yml +0 -22
- data/spec/support/apps/rails_4.2_app/config.ru +0 -4
- data/spec/support/apps/rails_4.2_app/db/migrate/20140301171212_add_devise_users.rb +0 -11
- data/spec/support/apps/rails_4.2_app/db/schema.rb +0 -25
data/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# MongoSessionStore
|
|
2
2
|
|
|
3
|
-
[](https://github.com/mongoid/mongo_session_store/actions/workflows/ci.yml?query=branch%3Amain)
|
|
4
4
|
[](http://badge.fury.io/rb/mongo_session_store)
|
|
5
|
-
[](https://coveralls.io/github/mongoid/mongo_session_store?branch=main)
|
|
6
6
|
|
|
7
7
|
## Description
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ MongoSessionStore is a [Rails][rails]-compatible session store for
|
|
|
11
11
|
Driver][mongo]. It also allows for custom Mongo session store that works with
|
|
12
12
|
any (or no!) Mongo ODM.
|
|
13
13
|
|
|
14
|
-
MongoSessionStore version 3 is compatible with Rails
|
|
14
|
+
MongoSessionStore version 3 is compatible with Rails 5.0+. For Rails
|
|
15
15
|
3 support please check out issue [#17][issue-rails3] for options and let us
|
|
16
16
|
know if you need support.
|
|
17
17
|
|
|
@@ -68,13 +68,57 @@ MongoidStore::Session.where(:updated_at.gt => 2.days.ago)
|
|
|
68
68
|
MongoStore::Session.where("updated_at" => { "$gt" => 2.days.ago })
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
### Serializable session values
|
|
72
|
+
|
|
73
|
+
Both adapters serialize session data with Ruby's `Marshal`. Store serializable values such as strings, numbers, arrays, and hashes, not requests, input streams, or uploaded files. Serialization errors are raised rather than silently discarding data.
|
|
74
|
+
|
|
75
|
+
Do not store `ActionController::Parameters` objects directly in the session. On Rails 7 and newer, their logging context can retain the request and its input stream, causing `TypeError: can't dump IO` (or a similar error for `StringIO`). A nested `params[:search]` object can retain that context too. Explicitly permit the values your application needs and convert them to a hash before saving:
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
session[:search] = params.require(:search).permit(:query, :sort).to_h
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This stores the permitted values without the request context. It does not make uploaded files or other non-serializable values serializable; store a durable identifier for those instead.
|
|
82
|
+
|
|
83
|
+
### Deleting stale sessions
|
|
84
|
+
|
|
85
|
+
Sessions are not automatically expired or deleted. To opt in to cleanup, call the store's `delete_stale_sessions` method with an explicit `Time` cutoff:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
# Mongoid
|
|
89
|
+
MongoidStore.delete_stale_sessions(before: 1.week.ago)
|
|
90
|
+
|
|
91
|
+
# MongoDB Ruby Driver
|
|
92
|
+
MongoStore.delete_stale_sessions(before: 1.week.ago)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The method returns the number deleted and uses the configured session collection. It performs a bulk database deletion without loading session data or running model callbacks. Only records whose `updated_at` is strictly earlier than the cutoff are deleted; records at the cutoff or without a timestamp are retained. Invalid cutoffs raise `ArgumentError`, and database errors propagate to the caller.
|
|
96
|
+
|
|
97
|
+
Run cleanup explicitly from a scheduled job or a Rails runner command, choosing a retention policy appropriate for your application:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
bin/rails runner 'MongoidStore.delete_stale_sessions(before: 1.week.ago)'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Deleting a session signs that session out on its next request. Cleanup is not cookie expiration or a guarantee of inactivity-based logout: `updated_at` tracks session saves, and a request that does not save the session may not refresh it. No default maximum age, background job, or TTL index is installed. For large collections, consider creating an ordinary index on `updated_at` as part of your database setup.
|
|
104
|
+
|
|
71
105
|
## Development
|
|
72
106
|
|
|
107
|
+
### Test environment
|
|
108
|
+
|
|
109
|
+
Start MongoDB with this script:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
script/testenv
|
|
113
|
+
```
|
|
114
|
+
|
|
73
115
|
### Testing
|
|
74
116
|
|
|
75
117
|
To run the tests for a specific store. You must first set a `BUNDLE_GEMFILE` in
|
|
76
118
|
the environment.
|
|
77
119
|
|
|
120
|
+
You can also use Docker, see the section below this one.
|
|
121
|
+
|
|
78
122
|
```sh
|
|
79
123
|
bundle exec rake
|
|
80
124
|
```
|
|
@@ -82,12 +126,6 @@ bundle exec rake
|
|
|
82
126
|
Examples:
|
|
83
127
|
|
|
84
128
|
```sh
|
|
85
|
-
BUNDLE_GEMFILE=gemfiles/rails-4.0-mongo.gemfile bundle exec rake
|
|
86
|
-
BUNDLE_GEMFILE=gemfiles/rails-4.0-mongoid.gemfile bundle exec rake
|
|
87
|
-
BUNDLE_GEMFILE=gemfiles/rails-4.1-mongo.gemfile bundle exec rake
|
|
88
|
-
BUNDLE_GEMFILE=gemfiles/rails-4.1-mongoid.gemfile bundle exec rake
|
|
89
|
-
BUNDLE_GEMFILE=gemfiles/rails-4.2-mongo.gemfile bundle exec rake
|
|
90
|
-
BUNDLE_GEMFILE=gemfiles/rails-4.2-mongoid.gemfile bundle exec rake
|
|
91
129
|
BUNDLE_GEMFILE=gemfiles/rails-5.0-mongo.gemfile bundle exec rake
|
|
92
130
|
BUNDLE_GEMFILE=gemfiles/rails-5.0-mongoid.gemfile bundle exec rake
|
|
93
131
|
BUNDLE_GEMFILE=gemfiles/rails-5.1-mongo.gemfile bundle exec rake
|
|
@@ -98,6 +136,30 @@ BUNDLE_GEMFILE=gemfiles/rails-6.0-mongo.gemfile bundle exec rake
|
|
|
98
136
|
BUNDLE_GEMFILE=gemfiles/rails-6.0-mongoid.gemfile bundle exec rake
|
|
99
137
|
```
|
|
100
138
|
|
|
139
|
+
For Rails 6.1 and newer, use `gemfiles/rails-current-mongo.gemfile` or `gemfiles/rails-current-mongoid.gemfile` with `RAILS_VERSION` and, for Mongoid, `MONGOID_VERSION` constraints:
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
RAILS_VERSION='~> 7.2.0' MONGOID_VERSION='~> 9.0' BUNDLE_GEMFILE=gemfiles/rails-current-mongoid.gemfile bundle exec rake test
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For Rails 8.0, also set `SQLITE_VERSION='~> 2.1'`; the dedicated Rails 8.1 Gemfiles already select SQLite 2.
|
|
146
|
+
|
|
147
|
+
Set `MONGODB_HOST` and `MONGODB_PORT` to use a non-default test server. The default is `127.0.0.1:27017`.
|
|
148
|
+
|
|
149
|
+
#### Docker testing
|
|
150
|
+
|
|
151
|
+
To run tests in a Docker container with a specific Ruby version and gemfile:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
BUNDLE_GEMFILE=gemfiles/rails-6.0-mongo.gemfile script/test
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The `BUNDLE_GEMFILE` environment variable is required. Ruby version defaults to 3.4 but can be customized:
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
RUBY_VERSION=2.7 BUNDLE_GEMFILE=gemfiles/rails-6.0-mongo.gemfile script/test
|
|
161
|
+
```
|
|
162
|
+
|
|
101
163
|
### Performance benchmark
|
|
102
164
|
|
|
103
165
|
The repository includes a performance benchmark. It runs against all available
|
data/RELEASING.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
Release from a clean local checkout of the upstream repository, not a fork. You need push access, RubyGems ownership with MFA, and an authenticated GitHub CLI.
|
|
4
|
+
|
|
5
|
+
## Prepare
|
|
6
|
+
|
|
7
|
+
1. Run `git switch main`, `git pull --ff-only`, and confirm that `origin` points to `mongoid/mongo_session_store`.
|
|
8
|
+
2. Choose the next semantic version, update `lib/mongo_session_store/version.rb`, and replace the unreleased changelog heading with the version and release date. Remove the contribution placeholder.
|
|
9
|
+
3. With MongoDB running, install dependencies and run `bundle exec rake test` using each supported adapter's `BUNDLE_GEMFILE`, for example `gemfiles/rails-6.0-mongo.gemfile` and `gemfiles/rails-6.0-mongoid.gemfile`. Run `bundle exec rubocop` with the default Gemfile.
|
|
10
|
+
4. Commit the preparation, push `main`, and wait for the complete GitHub Actions matrix to pass for that commit.
|
|
11
|
+
|
|
12
|
+
## Publish
|
|
13
|
+
|
|
14
|
+
Do not use the legacy `rake release` task: it assumes `master` and performs interactive edits. Build and publish the prepared version explicitly:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
version=3.2.2 # Replace with the version being released.
|
|
18
|
+
gem build mongo_session_store.gemspec
|
|
19
|
+
git tag "v$version"
|
|
20
|
+
git push origin "v$version"
|
|
21
|
+
gem push "mongo_session_store-$version.gem"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Enter a fresh RubyGems MFA code when prompted. Create a GitHub release from the same tag, using the matching changelog section as the release notes:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
gh release create "v$version" --repo mongoid/mongo_session_store \
|
|
28
|
+
--verify-tag --title "$version" --notes-file /path/to/release-notes.md --latest
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Verify the exact version at `https://rubygems.org/gems/mongo_session_store/versions/VERSION` and inspect `gh release view "v$version" --repo mongoid/mongo_session_store` to confirm a published, non-draft release.
|
|
32
|
+
|
|
33
|
+
If publication is interrupted, check the remote tag, RubyGems version, and GitHub release first. Resume only the missing step; never move a published tag or rebuild an already published version. If the gem push needs a new code, retry that command with `--otp CODE`.
|
|
34
|
+
|
|
35
|
+
## Next development version
|
|
36
|
+
|
|
37
|
+
Increment the patch version in `lib/mongo_session_store/version.rb`, add a new `## (unreleased)` section with a contribution placeholder, and commit and push the changes to `main`. Remove the local built gem after successful publication.
|
data/docker-compose.yml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
source "https://rubygems.org"
|
|
2
|
+
|
|
3
|
+
gem "mongo", "~> 2.0"
|
|
4
|
+
gem "rails", "~> 8.1.0"
|
|
5
|
+
gem "devise", "~> 5.0"
|
|
6
|
+
gem "sqlite3", "~> 2.0"
|
|
7
|
+
gem "bigdecimal"
|
|
8
|
+
gem "mutex_m"
|
|
9
|
+
gem "drb"
|
|
10
|
+
gem "base64"
|
|
11
|
+
gem "benchmark"
|
|
12
|
+
gem "ostruct"
|
|
13
|
+
gem "simplecov", "~> 0.22", :require => false
|
|
14
|
+
|
|
15
|
+
gemspec :path => "../"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
source "https://rubygems.org"
|
|
2
|
+
|
|
3
|
+
gem "mongoid", "~> 9.0"
|
|
4
|
+
gem "rails", "~> 8.1.0"
|
|
5
|
+
gem "devise", "~> 5.0"
|
|
6
|
+
gem "sqlite3", "~> 2.0"
|
|
7
|
+
gem "bigdecimal"
|
|
8
|
+
gem "mutex_m"
|
|
9
|
+
gem "drb"
|
|
10
|
+
gem "base64"
|
|
11
|
+
gem "benchmark"
|
|
12
|
+
gem "ostruct"
|
|
13
|
+
gem "simplecov", "~> 0.22", :require => false
|
|
14
|
+
|
|
15
|
+
gemspec :path => "../"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
source "https://rubygems.org"
|
|
2
|
+
|
|
3
|
+
gem "rails", ENV.fetch("RAILS_VERSION", "~> 7.2.0")
|
|
4
|
+
gem "mongo", "~> 2.0"
|
|
5
|
+
gem "devise", "~> 4.9"
|
|
6
|
+
gem "sqlite3", ENV.fetch("SQLITE_VERSION", "~> 1.4")
|
|
7
|
+
gem "logger"
|
|
8
|
+
gem "bigdecimal"
|
|
9
|
+
gem "mutex_m"
|
|
10
|
+
gem "drb"
|
|
11
|
+
gem "base64"
|
|
12
|
+
gem "benchmark"
|
|
13
|
+
gem "ostruct"
|
|
14
|
+
gem "simplecov", "~> 0.22", :require => false if ENV["COVERAGE"] == "true"
|
|
15
|
+
|
|
16
|
+
gemspec :path => "../"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require "action_dispatch"
|
|
1
2
|
require "action_dispatch/middleware/session/abstract_store"
|
|
2
3
|
|
|
3
4
|
module ActionDispatch
|
|
@@ -15,6 +16,12 @@ module ActionDispatch
|
|
|
15
16
|
self::Session
|
|
16
17
|
end
|
|
17
18
|
|
|
19
|
+
def self.delete_stale_sessions(before:)
|
|
20
|
+
raise ArgumentError, "before must be a Time" unless before.is_a?(Time)
|
|
21
|
+
|
|
22
|
+
session_class.collection.find("updated_at" => { "$lt" => before.getutc }).delete_many.deleted_count
|
|
23
|
+
end
|
|
24
|
+
|
|
18
25
|
private
|
|
19
26
|
|
|
20
27
|
def session_class
|
data/mongo_session_store.gemspec
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require File.expand_path("
|
|
1
|
+
require File.expand_path("lib/mongo_session_store/version", __dir__)
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = "mongo_session_store"
|
|
@@ -17,10 +17,7 @@ Gem::Specification.new do |s|
|
|
|
17
17
|
s.add_dependency "actionpack", ">= 4.0"
|
|
18
18
|
s.add_dependency "mongo", "~> 2.0"
|
|
19
19
|
|
|
20
|
-
s.add_development_dependency "
|
|
21
|
-
s.add_development_dependency "
|
|
22
|
-
s.add_development_dependency "
|
|
23
|
-
s.add_development_dependency "rake", "~> 11"
|
|
24
|
-
s.add_development_dependency "rubocop", "0.45.0"
|
|
25
|
-
s.add_development_dependency "mongoid-danger", "~> 0.1.0"
|
|
20
|
+
s.add_development_dependency "capybara", ">= 2.15"
|
|
21
|
+
s.add_development_dependency "rake"
|
|
22
|
+
s.add_development_dependency "rspec-rails", ">= 4.0"
|
|
26
23
|
end
|
data/script/test
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -eu
|
|
4
|
+
|
|
5
|
+
if [ -z "${BUNDLE_GEMFILE:-}" ]; then
|
|
6
|
+
echo "Error: BUNDLE_GEMFILE environment variable is required"
|
|
7
|
+
echo "Example: BUNDLE_GEMFILE=gemfiles/rails-6.0-mongo.gemfile script/test"
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
RUBY_VERSION=${RUBY_VERSION:-3.4}
|
|
12
|
+
|
|
13
|
+
docker run --rm -it \
|
|
14
|
+
--network mongo_session_store_default \
|
|
15
|
+
-e MONGODB_HOST=mongodb \
|
|
16
|
+
-e BUNDLE_GEMFILE="${BUNDLE_GEMFILE}" \
|
|
17
|
+
-v "$(pwd):/app" \
|
|
18
|
+
-w /app \
|
|
19
|
+
"ruby:${RUBY_VERSION}" \
|
|
20
|
+
/app/script/test_inner
|
data/script/test_inner
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -eu
|
|
4
|
+
|
|
5
|
+
export BUNDLE_GEMFILE
|
|
6
|
+
export BUNDLE_PATH="/app/tmp/bundler/$RUBY_VERSION/$BUNDLE_GEMFILE"
|
|
7
|
+
|
|
8
|
+
ruby_version=$(ruby -e 'puts RUBY_VERSION')
|
|
9
|
+
major=$(echo "$ruby_version" | cut -d. -f1)
|
|
10
|
+
minor=$(echo "$ruby_version" | cut -d. -f2)
|
|
11
|
+
|
|
12
|
+
if [ "$major" -lt 2 ] || ([ "$major" -eq 2 ] && [ "$minor" -le 7 ]); then
|
|
13
|
+
gem install bundler -v 1.17.3
|
|
14
|
+
else
|
|
15
|
+
gem install bundler
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
bundle install
|
|
19
|
+
bundle exec rspec
|
data/script/testenv
ADDED
data/spec/.rubocop.yml
CHANGED
|
@@ -15,7 +15,7 @@ describe Devise::SessionsController, :type => :request do
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def create_user
|
|
18
|
-
post "/users", prepare_request_params(
|
|
18
|
+
post "/users", **prepare_request_params(
|
|
19
19
|
"user[email]" => "person@example.com",
|
|
20
20
|
"user[password]" => "secret",
|
|
21
21
|
"user[password_confirmation]" => "secret"
|
|
@@ -23,7 +23,7 @@ describe Devise::SessionsController, :type => :request do
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def sign_in
|
|
26
|
-
post "/users/sign_in", prepare_request_params(
|
|
26
|
+
post "/users/sign_in", **prepare_request_params(
|
|
27
27
|
"user[email]" => "person@example.com",
|
|
28
28
|
"user[password]" => "secret",
|
|
29
29
|
"user[password_confirmation]" => "secret"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "Legacy session serialization" do
|
|
4
|
+
let(:session_class) { mongo_orm == "mongoid" ? MongoidStore::Session : MongoStore::Session }
|
|
5
|
+
|
|
6
|
+
it "reads raw marshalled strings as well as BSON binary data" do
|
|
7
|
+
payload = { "nested" => { "count" => 2 }, "tags" => %w[old session] }
|
|
8
|
+
session = session_class.new
|
|
9
|
+
|
|
10
|
+
expect(session.send(:unpack, Marshal.dump(payload))).to eq(payload)
|
|
11
|
+
expect(session.send(:unpack, BSON::Binary.new(Marshal.dump(payload), :generic))).to eq(payload)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "returns nil when there is no serialized payload" do
|
|
15
|
+
expect(session_class.new.send(:unpack, nil)).to be_nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require "rails_helper"
|
|
2
|
+
|
|
3
|
+
describe "Session data serialization" do
|
|
4
|
+
let(:session_class) { mongo_orm == "mongoid" ? MongoidStore::Session : MongoStore::Session }
|
|
5
|
+
let(:id) { generate_sid }
|
|
6
|
+
let(:search) { { "query" => "painting", "admin" => "1" } }
|
|
7
|
+
let(:parameters) do
|
|
8
|
+
values = { "search" => search }
|
|
9
|
+
if Gem.loaded_specs["rails"].version >= Gem::Version.new("7.0")
|
|
10
|
+
request = ActionDispatch::TestRequest.create("rack.input" => StringIO.new)
|
|
11
|
+
ActionController::Parameters.new(values, :request => request)
|
|
12
|
+
else
|
|
13
|
+
ActionController::Parameters.new(values)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "round-trips explicitly permitted parameter values without request context" do
|
|
18
|
+
record = session_class.new(:_id => id)
|
|
19
|
+
record.data = { "search" => parameters.require(:search).permit(:query).to_h }
|
|
20
|
+
record.save
|
|
21
|
+
|
|
22
|
+
expect(session_class.where(:_id => id).first.data).to eq(
|
|
23
|
+
"search" => { "query" => "painting" }
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
if Gem.loaded_specs["rails"].version >= Gem::Version.new("7.0")
|
|
28
|
+
it "reports serialization errors for raw parameters retaining an input stream" do
|
|
29
|
+
record = session_class.new(:_id => id)
|
|
30
|
+
record.data = { "search" => parameters[:search] }
|
|
31
|
+
|
|
32
|
+
expect { record.save }.to raise_error(TypeError, /StringIO/)
|
|
33
|
+
expect(session_class.collection.find(:_id => id).count).to eq(0)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe ".delete_stale_sessions" do
|
|
4
|
+
let(:store) { mongo_orm == "mongoid" ? MongoidStore : MongoStore }
|
|
5
|
+
let(:collection) { store.session_class.collection }
|
|
6
|
+
let(:cutoff) { Time.utc(2026, 1, 1) }
|
|
7
|
+
|
|
8
|
+
it "deletes only sessions last updated strictly before the cutoff" do
|
|
9
|
+
collection.insert_many([
|
|
10
|
+
{ :_id => "stale", :updated_at => cutoff - 1 },
|
|
11
|
+
{ :_id => "boundary", :updated_at => cutoff },
|
|
12
|
+
{ :_id => "active", :created_at => cutoff - 100, :updated_at => cutoff + 1 },
|
|
13
|
+
{ :_id => "undated" },
|
|
14
|
+
{ :_id => "null-date", :updated_at => nil }
|
|
15
|
+
])
|
|
16
|
+
|
|
17
|
+
expect(store.delete_stale_sessions(:before => cutoff)).to eq(1)
|
|
18
|
+
expect(collection.find.map { |doc| doc["_id"] }.sort).to eq(
|
|
19
|
+
%w[active boundary null-date undated]
|
|
20
|
+
)
|
|
21
|
+
expect(store.delete_stale_sessions(:before => cutoff)).to eq(0)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "returns zero for an empty collection" do
|
|
25
|
+
expect(store.delete_stale_sessions(:before => cutoff)).to eq(0)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "accepts a cutoff with a UTC offset" do
|
|
29
|
+
collection.insert_one(:_id => "stale", :updated_at => cutoff - 1)
|
|
30
|
+
local_cutoff = cutoff.getlocal("-05:00")
|
|
31
|
+
|
|
32
|
+
expect(store.delete_stale_sessions(:before => local_cutoff)).to eq(1)
|
|
33
|
+
expect(local_cutoff.utc_offset).to eq(-5 * 60 * 60)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "accepts a Rails time-zone cutoff" do
|
|
37
|
+
collection.insert_one(:_id => "stale", :updated_at => cutoff - 1)
|
|
38
|
+
zoned_cutoff = cutoff.in_time_zone("Eastern Time (US & Canada)")
|
|
39
|
+
expect(store.delete_stale_sessions(:before => zoned_cutoff)).to eq(1)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "rejects invalid cutoffs without deleting sessions" do
|
|
43
|
+
collection.insert_one(:_id => "stale", :updated_at => cutoff - 1)
|
|
44
|
+
|
|
45
|
+
[nil, "2026-01-01", 1].each do |value|
|
|
46
|
+
expect { store.delete_stale_sessions(:before => value) }.to raise_error(
|
|
47
|
+
ArgumentError, "before must be a Time"
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
expect(collection.find.count).to eq(1)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "uses the configured collection without touching the default collection" do
|
|
54
|
+
collection.insert_one(:_id => "default", :updated_at => cutoff - 1)
|
|
55
|
+
original_name = MongoSessionStore.collection_name
|
|
56
|
+
begin
|
|
57
|
+
MongoSessionStore.collection_name = "custom_sessions"
|
|
58
|
+
custom_collection = store.session_class.collection
|
|
59
|
+
custom_collection.insert_one(:_id => "custom", :updated_at => cutoff - 1)
|
|
60
|
+
|
|
61
|
+
expect(store.delete_stale_sessions(:before => cutoff)).to eq(1)
|
|
62
|
+
expect(custom_collection.find.count).to eq(0)
|
|
63
|
+
ensure
|
|
64
|
+
MongoSessionStore.collection_name = original_name
|
|
65
|
+
end
|
|
66
|
+
expect(collection.find.count).to eq(1)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "does not suppress database errors" do
|
|
70
|
+
allow(store.session_class).to receive(:collection)
|
|
71
|
+
.and_raise(MongoSessionStore::Error, "unavailable")
|
|
72
|
+
|
|
73
|
+
expect { store.delete_stale_sessions(:before => cutoff) }.to raise_error(
|
|
74
|
+
MongoSessionStore::Error, "unavailable"
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
end
|
data/spec/rails_helper.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
ENV["RAILS_ENV"] = "test"
|
|
2
|
+
require "logger"
|
|
3
|
+
require "active_support"
|
|
2
4
|
rails_version = Gem.loaded_specs["rails"].version.to_s[/^\d\.\d/]
|
|
5
|
+
# Later Rails versions use the same minimal integration app as Rails 6.
|
|
6
|
+
rails_version = "6.0" if Gem.loaded_specs["rails"].version >= Gem::Version.new("6.0")
|
|
3
7
|
if Gem.loaded_specs["rails"].version >= Gem::Version.new("5.2")
|
|
4
8
|
require "active_support/message_encryptor"
|
|
5
9
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
if ENV["COVERAGE"] == "true"
|
|
2
|
+
require "simplecov"
|
|
3
|
+
SimpleCov.command_name "RSpec #{Gem.loaded_specs.key?("mongoid") ? "Mongoid" : "Mongo"}"
|
|
4
|
+
SimpleCov.start do
|
|
5
|
+
track_files "lib/**/*.rb"
|
|
6
|
+
add_filter "/spec/"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require "logger"
|
|
1
11
|
require "mongo"
|
|
2
12
|
require "mongoid" if Gem.loaded_specs["mongoid"]
|
|
3
13
|
require "mongo_session_store"
|
|
@@ -27,6 +37,8 @@ RSpec.configure do |config|
|
|
|
27
37
|
config.before :suite do
|
|
28
38
|
Mongo::Logger.logger.level = ::Logger::INFO
|
|
29
39
|
|
|
40
|
+
mongodb_host = ENV["MONGODB_HOST"] || "127.0.0.1"
|
|
41
|
+
mongodb_port = ENV["MONGODB_PORT"] || "27017"
|
|
30
42
|
if mongo_orm == "mongoid"
|
|
31
43
|
Mongoid.logger.level = Logger::INFO
|
|
32
44
|
Mongoid.configure do |c|
|
|
@@ -34,14 +46,14 @@ RSpec.configure do |config|
|
|
|
34
46
|
"clients" => {
|
|
35
47
|
"default" => {
|
|
36
48
|
"database" => TestDatabaseHelper.test_database_name,
|
|
37
|
-
"hosts" => ["
|
|
49
|
+
"hosts" => ["#{mongodb_host}:#{mongodb_port}"]
|
|
38
50
|
}
|
|
39
51
|
}
|
|
40
52
|
)
|
|
41
53
|
end
|
|
42
54
|
else
|
|
43
55
|
MongoStore::Session.database = Mongo::Client.new(
|
|
44
|
-
["
|
|
56
|
+
["#{mongodb_host}:#{mongodb_port}"],
|
|
45
57
|
:database => TestDatabaseHelper.test_database_name
|
|
46
58
|
)
|
|
47
59
|
end
|
|
@@ -10,16 +10,22 @@ default: &default
|
|
|
10
10
|
timeout: 5000
|
|
11
11
|
|
|
12
12
|
development:
|
|
13
|
-
|
|
13
|
+
adapter: sqlite3
|
|
14
|
+
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
|
15
|
+
timeout: 5000
|
|
14
16
|
database: db/development.sqlite3
|
|
15
17
|
|
|
16
18
|
# Warning: The database defined as "test" will be erased and
|
|
17
19
|
# re-generated from your development database when you run "rake".
|
|
18
20
|
# Do not set this db to the same as development or production.
|
|
19
21
|
test:
|
|
20
|
-
|
|
22
|
+
adapter: sqlite3
|
|
23
|
+
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
|
24
|
+
timeout: 5000
|
|
21
25
|
database: db/test.sqlite3
|
|
22
26
|
|
|
23
27
|
production:
|
|
24
|
-
|
|
28
|
+
adapter: sqlite3
|
|
29
|
+
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
|
30
|
+
timeout: 5000
|
|
25
31
|
database: db/production.sqlite3
|
|
@@ -31,7 +31,7 @@ Rails.application.configure do
|
|
|
31
31
|
config.action_controller.allow_forgery_protection = false
|
|
32
32
|
|
|
33
33
|
# Print deprecation notices to the stderr.
|
|
34
|
-
config.active_support.deprecation = :stderr
|
|
34
|
+
config.active_support.deprecation = :stderr if Rails.gem_version < Gem::Version.new("7.1")
|
|
35
35
|
|
|
36
36
|
# Raises error for missing translations.
|
|
37
37
|
# config.action_view.raise_on_missing_translations = true
|
data/spec/support/rack_app.rb
CHANGED
|
@@ -9,6 +9,8 @@ class MyApp
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
MyAppWrapped = Rack::Builder.new do |builder|
|
|
12
|
-
|
|
12
|
+
if defined?(Rack::Session::Cookie)
|
|
13
|
+
builder.use Rack::Session::Cookie, :secret => "Very secret secret"
|
|
14
|
+
end
|
|
13
15
|
builder.run MyApp.new
|
|
14
16
|
end
|