session-check 2.0.0 → 2.0.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.
- checksums.yaml +4 -4
- data/README.md +19 -1
- data/app/assets/javascripts/session_check.js +125 -0
- data/app/views/_session_check.html.erb +10 -33
- data/config/routes.rb +8 -1
- data/lib/session/check/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 75caa11e24f6f750c18ee096a9d39ba72c86713e74836d479885625f2d72d262
|
|
4
|
+
data.tar.gz: 6eaa656c8f9aac3a935483393aa4835e9286d6e96fe87446477c238ab575cd75
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5375698f650fb0fccf732a4a7c735e4e9248084a6b3d2f3126d49be384116cfb3b66751bbc549f137c6f6f3971a99d35dc2fbc641ce611136aff0718f073a67e
|
|
7
|
+
data.tar.gz: 9bc95912cb792257bd9449702a0092d29331b5be003b191061b2b7b8b3e62add21d1bef242513ac7f0b8409ef5a6db2bfc2752bd099bc25a04149b6d983b33bc
|
data/README.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
Session Check
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
[](https://rubygems.org/gems/session-check)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
2
6
|
|
|
3
7
|
A gem that returns you to your application's sign in page when your Devise session expires.
|
|
4
8
|
|
|
@@ -72,8 +76,22 @@ server-side ping endpoint and the initial JS `should_session_check` value. All o
|
|
|
72
76
|
|
|
73
77
|
If `session_active_proc` is not set the gem uses the default Devise behaviour, computing remaining session time from the Warden last-request timestamp.
|
|
74
78
|
|
|
79
|
+
# Development
|
|
80
|
+
|
|
81
|
+
The client-side JS lives in `app/assets/javascripts/session_check.js` as plain, dependency-free JS
|
|
82
|
+
so it can be unit tested in isolation. The `_session_check` partial only passes configuration in via
|
|
83
|
+
`window.SessionCheckConfig` and inlines this file's contents — no asset pipeline setup is required
|
|
84
|
+
by consuming applications.
|
|
85
|
+
|
|
86
|
+
JS unit tests (Jest + jsdom) live under `spec/javascript` and are scoped to this repo only —
|
|
87
|
+
`package.json`/`node_modules` are dev-only and excluded from the published gem. Run them with:
|
|
88
|
+
|
|
89
|
+
npm install
|
|
90
|
+
npm test
|
|
91
|
+
|
|
75
92
|
# Changelog
|
|
76
93
|
|
|
94
|
+
Version 2.0.1 : Fix session-expiry check drifting in background/inactive tabs
|
|
77
95
|
Version 2.0.0 : **Breaking change** — default Devise behaviour now correctly computes remaining session time from the Warden last-request timestamp rather than always returning the full timeout. `current_user` is no longer exposed to the session check partial. Added `session_active_proc` configuration option for non-Devise session support. Fixed setTimeout multiplier (5000 → 1000) so session checks fire at the correct interval. Bump your dependency to `>= 2.0.0`.
|
|
78
96
|
Version 1.1.0 : Added optional nonce
|
|
79
97
|
Version 0.2.1 : Added explicit reference to Devise (which is required)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/* eslint-disable no-var */
|
|
2
|
+
// This file is plain JS (no ERB) so it can be loaded directly in unit tests
|
|
3
|
+
// (see spec/javascript) as well as served as-is by the Rails asset pipeline.
|
|
4
|
+
//
|
|
5
|
+
// Configuration is supplied at runtime via a `window.SessionCheckConfig`
|
|
6
|
+
// object assigned by app/views/_session_check.html.erb, e.g.:
|
|
7
|
+
//
|
|
8
|
+
// window.SessionCheckConfig = {
|
|
9
|
+
// should_session_check: true,
|
|
10
|
+
// check_every_s: 30,
|
|
11
|
+
// session_time: 3600,
|
|
12
|
+
// logged_out_url: '/users/sign_in',
|
|
13
|
+
// reset_counter_on_ajax: true
|
|
14
|
+
// };
|
|
15
|
+
(function (global) {
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
// `createSessionCheck` builds a fresh instance of the session-check
|
|
19
|
+
// behaviour. `deps` allows tests to inject fakes for jQuery, the clock and
|
|
20
|
+
// timer functions instead of relying on browser globals.
|
|
21
|
+
function createSessionCheck(config, deps) {
|
|
22
|
+
config = config || {};
|
|
23
|
+
deps = deps || {};
|
|
24
|
+
|
|
25
|
+
var $ = deps.$ || global.$;
|
|
26
|
+
var now = deps.now || function () {
|
|
27
|
+
return Date.now();
|
|
28
|
+
};
|
|
29
|
+
var setTimeoutFn = deps.setTimeout || global.setTimeout;
|
|
30
|
+
var documentRef = deps.document || global.document;
|
|
31
|
+
var locationRef = deps.location || global;
|
|
32
|
+
|
|
33
|
+
var check_every_s = config.check_every_s;
|
|
34
|
+
var session_time = config.session_time;
|
|
35
|
+
var check_every_ms = check_every_s * 1000;
|
|
36
|
+
var min_check_interval_ms = 5 * 1000; // don't re-check more than once per 5s
|
|
37
|
+
var session_expires_at = now() + session_time * 1000; // absolute timestamp, not a countdown
|
|
38
|
+
var last_check_at = now();
|
|
39
|
+
|
|
40
|
+
var SessionCheck = {
|
|
41
|
+
should_session_check: !!config.should_session_check
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
var force_sign_in = function () {
|
|
45
|
+
locationRef.location = config.logged_out_url;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
var check_session_with_server = function () {
|
|
49
|
+
last_check_at = now();
|
|
50
|
+
$.get('/session_check/time_to_session_expiry')
|
|
51
|
+
.done(function (d) {
|
|
52
|
+
if (!d.session_exists) {
|
|
53
|
+
force_sign_in();
|
|
54
|
+
} else {
|
|
55
|
+
session_expires_at = now() + d.session_expires_in * 1000;
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
.fail(force_sign_in);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
var session_check = function () {
|
|
62
|
+
if (SessionCheck.should_session_check && now() >= session_expires_at) {
|
|
63
|
+
check_session_with_server();
|
|
64
|
+
}
|
|
65
|
+
setTimeoutFn(session_check, check_every_ms);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
var on_visibility_change = function () {
|
|
69
|
+
if (documentRef.visibilityState === 'visible' && SessionCheck.should_session_check) {
|
|
70
|
+
if (now() - last_check_at > min_check_interval_ms) {
|
|
71
|
+
check_session_with_server();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
var on_ajax_complete = function () {
|
|
77
|
+
session_expires_at = now() + session_time * 1000;
|
|
78
|
+
last_check_at = now();
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
var start = function () {
|
|
82
|
+
setTimeoutFn(session_check, check_every_ms);
|
|
83
|
+
|
|
84
|
+
// Whenever the tab becomes visible again, go straight to the server
|
|
85
|
+
// for ground truth instead of trusting local timers/clock math.
|
|
86
|
+
// Debounced so rapid tab-switching doesn't spam the endpoint.
|
|
87
|
+
documentRef.addEventListener('visibilitychange', on_visibility_change);
|
|
88
|
+
|
|
89
|
+
if (config.reset_counter_on_ajax) {
|
|
90
|
+
$.ajaxSetup({
|
|
91
|
+
complete: on_ajax_complete
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
SessionCheck: SessionCheck,
|
|
98
|
+
start: start,
|
|
99
|
+
// Exposed for unit testing only.
|
|
100
|
+
_internal: {
|
|
101
|
+
force_sign_in: force_sign_in,
|
|
102
|
+
check_session_with_server: check_session_with_server,
|
|
103
|
+
session_check: session_check,
|
|
104
|
+
on_visibility_change: on_visibility_change,
|
|
105
|
+
on_ajax_complete: on_ajax_complete,
|
|
106
|
+
get session_expires_at() {
|
|
107
|
+
return session_expires_at;
|
|
108
|
+
},
|
|
109
|
+
get last_check_at() {
|
|
110
|
+
return last_check_at;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
117
|
+
module.exports = createSessionCheck;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (typeof global.SessionCheckConfig !== 'undefined') {
|
|
121
|
+
var instance = createSessionCheck(global.SessionCheckConfig);
|
|
122
|
+
global.SessionCheck = instance.SessionCheck;
|
|
123
|
+
instance.start();
|
|
124
|
+
}
|
|
125
|
+
})(typeof window !== 'undefined' ? window : this);
|
|
@@ -1,35 +1,12 @@
|
|
|
1
1
|
<script<% if local_assigns[:nonce] %> nonce="<%= nonce %>"<% end %>>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
session_time_left = session_time_left - check_every_s;
|
|
13
|
-
if (SessionCheck.should_session_check && session_time_left < 0) {
|
|
14
|
-
$.get('/session_check/time_to_session_expiry')
|
|
15
|
-
.done(function (d) {
|
|
16
|
-
if (!d.session_exists) {
|
|
17
|
-
force_sign_in();
|
|
18
|
-
} else {
|
|
19
|
-
session_time_left = d.session_expires_in;
|
|
20
|
-
}
|
|
21
|
-
})
|
|
22
|
-
.fail(force_sign_in);
|
|
23
|
-
}
|
|
24
|
-
setTimeout(session_check, check_every_s * 1000);
|
|
25
|
-
};
|
|
26
|
-
setTimeout(session_check, check_every_s * 1000);
|
|
27
|
-
<% if reset_counter_on_ajax %>
|
|
28
|
-
$.ajaxSetup({
|
|
29
|
-
complete: function (xhr) {
|
|
30
|
-
session_time_left = <%= session_time %>;
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
<% end %>
|
|
34
|
-
}());
|
|
2
|
+
window.SessionCheckConfig = {
|
|
3
|
+
should_session_check: <%= session_active %>,
|
|
4
|
+
check_every_s: <%= check_every_s %>,
|
|
5
|
+
session_time: <%= session_time %>,
|
|
6
|
+
logged_out_url: <%= raw ERB::Util.json_escape(logged_out_url.to_json) %>,
|
|
7
|
+
reset_counter_on_ajax: <%= !!reset_counter_on_ajax %>
|
|
8
|
+
};
|
|
9
|
+
</script>
|
|
10
|
+
<script<% if local_assigns[:nonce] %> nonce="<%= nonce %>"<% end %>>
|
|
11
|
+
<%= raw File.read(Session::Check::Engine.root.join('app', 'assets', 'javascripts', 'session_check.js')) %>
|
|
35
12
|
</script>
|
data/config/routes.rb
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Draw directly into the host application's routes (rather than
|
|
4
|
+
# `Session::Check::Engine.routes.draw`) so the endpoint is auto-wired for any
|
|
5
|
+
# consuming app without requiring an explicit `mount Session::Check::Engine`,
|
|
6
|
+
# matching the README usage (`<%= session_check %>` only).
|
|
3
7
|
Rails.application.routes.draw do
|
|
4
|
-
get 'session_check/time_to_session_expiry',
|
|
8
|
+
get 'session_check/time_to_session_expiry',
|
|
9
|
+
to: 'session/check/session_checks#time_to_session_expiry',
|
|
10
|
+
format: :json,
|
|
11
|
+
defaults: { format: :json }
|
|
5
12
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: session-check
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Harry Lascelles
|
|
@@ -128,6 +128,7 @@ extensions: []
|
|
|
128
128
|
extra_rdoc_files: []
|
|
129
129
|
files:
|
|
130
130
|
- README.md
|
|
131
|
+
- app/assets/javascripts/session_check.js
|
|
131
132
|
- app/controllers/session/check/session_checks_controller.rb
|
|
132
133
|
- app/helpers/session/check/session_check_helper.rb
|
|
133
134
|
- app/views/_session_check.html.erb
|