Skip to content

Commit b6b7ef0

Browse files
committed
ws: Add "set-session-timeout" command
and use it as a backup for the JavaScript session timeout implementation. With it, the session really ends at about the expected time, regardless of whether JavaScript is executed by the browser or not. We keep the JavaScript implementation so that session timeouts work with older cockpit-ws versions and to keep the cockpit-ws side simple. There anyway needs to be cooperation from JavaScript to perform a proper logout.
1 parent a0512db commit b6b7ef0

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

pkg/shell/idle.tsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export class IdleTimeoutState extends EventEmitter<IdleTimeoutStateEvents> {
3535
super();
3636

3737
this.#idle_start_time = Date.now();
38+
this.#disarm_ws_timeout();
3839

3940
cockpit.dbus(null, { bus: "internal" }).call("/config", "cockpit.Config", "GetUInt",
4041
["Session", "IdleTimeout", 0, 240, 0], {})
@@ -43,6 +44,7 @@ export class IdleTimeoutState extends EventEmitter<IdleTimeoutStateEvents> {
4344
if (this.#session_timeout > 0 && this.#standard_login) {
4445
this.setupIdleResetEventListeners(window);
4546
window.setInterval(this.#idleTick, 5000);
47+
this.#arm_ws_timeout();
4648
}
4749
})
4850
.catch(e => {
@@ -72,10 +74,35 @@ export class IdleTimeoutState extends EventEmitter<IdleTimeoutStateEvents> {
7274
};
7375

7476
#resetTimer = () => {
75-
if (this.final_countdown === null)
76-
this.#idle_start_time = Date.now();
77+
if (this.final_countdown === null) {
78+
const idle_time = Date.now() - this.#idle_start_time;
79+
if (idle_time > 10 * 1000) {
80+
this.#idle_start_time = Date.now();
81+
this.#arm_ws_timeout();
82+
}
83+
}
7784
};
7885

86+
#arm_ws_timeout() {
87+
// Tell cockpit-ws to kill the session 10 seconds after we are
88+
// supposed to have logged out here. This is an emergency
89+
// fallback mechanism for the case that the browser stops
90+
// executing our JavaScript. Once JavaScript starts running
91+
// again and the websocket has been closed by cockpit-ws and
92+
// the Shell will show the "Disconnected" curtain. Then the
93+
// timer ticks here will happen and will perform the browser
94+
// side of the logout immediately and we end up on the login
95+
// page with the expected "Logged out due to inactivity"
96+
// message.
97+
98+
cockpit.assert(this.#session_timeout > 0);
99+
cockpit.transport.control("set-session-timeout", { seconds: this.#session_timeout / 1000 + 10 });
100+
}
101+
102+
#disarm_ws_timeout() {
103+
cockpit.transport.control("set-session-timeout", { seconds: 0 });
104+
}
105+
79106
setupIdleResetEventListeners(win: Window) {
80107
// NOTE: This function will be called many many times for a
81108
// given window, not just once. Calling addEventListener

src/ws/cockpitwebservice.c

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ typedef struct {
4848
guint next_socket_id;
4949
} CockpitSockets;
5050

51+
static gboolean on_session_timeout (gpointer user_data);
52+
5153
static void
5254
cockpit_socket_free (gpointer data)
5355
{
@@ -187,6 +189,7 @@ struct _CockpitWebService {
187189
gboolean closing;
188190
GBytes *control_prefix;
189191
guint ping_timeout;
192+
guint session_timeout;
190193
gint callers;
191194
guint next_internal_id;
192195

@@ -270,6 +273,8 @@ cockpit_web_service_finalize (GObject *object)
270273
cockpit_creds_unref (self->creds);
271274
if (self->ping_timeout)
272275
g_source_remove (self->ping_timeout);
276+
if (self->session_timeout)
277+
g_source_remove (self->session_timeout);
273278

274279
g_hash_table_destroy (self->host_by_checksum);
275280
g_hash_table_destroy (self->checksum_by_host);
@@ -284,6 +289,19 @@ cockpit_web_service_unique_channel (CockpitWebService *self)
284289
return g_strdup_printf ("0:%d", self->next_internal_id++);
285290
}
286291

292+
static void
293+
set_session_timeout (CockpitWebService *self, gint64 seconds)
294+
{
295+
if (self->session_timeout)
296+
{
297+
g_source_remove (self->session_timeout);
298+
self->session_timeout = 0;
299+
}
300+
if (seconds > 0)
301+
self->session_timeout = g_timeout_add_seconds (seconds, on_session_timeout, self);
302+
}
303+
304+
287305
static void
288306
caller_begin (CockpitWebService *self)
289307
{
@@ -297,7 +315,10 @@ caller_end (CockpitWebService *self)
297315
g_return_if_fail (self->callers > 0);
298316
self->callers--;
299317
if (self->callers == 0)
300-
g_signal_emit (self, sig_idling, 0);
318+
{
319+
g_signal_emit (self, sig_idling, 0);
320+
set_session_timeout (self, 0);
321+
}
301322
g_object_unref (self);
302323
}
303324

@@ -933,6 +954,16 @@ process_logout (CockpitWebService *self,
933954
g_object_run_dispose (G_OBJECT (self));
934955
}
935956

957+
static void
958+
process_set_session_timeout (CockpitWebService *self,
959+
JsonObject *options)
960+
{
961+
gint64 seconds;
962+
if (!cockpit_json_get_int (options, "seconds", 0, &seconds))
963+
seconds = 0;
964+
set_session_timeout (self, seconds);
965+
}
966+
936967
static const gchar *
937968
process_socket_init (CockpitWebService *self,
938969
CockpitSocket *socket,
@@ -1044,6 +1075,10 @@ dispatch_inbound_command (CockpitWebService *self,
10441075
{
10451076
valid = process_ping (self, socket, options);
10461077
}
1078+
else if (!channel && g_strcmp0 (command, "set-session-timeout") == 0)
1079+
{
1080+
process_set_session_timeout (self, options);
1081+
}
10471082
else if (channel)
10481083
{
10491084
/* Relay anything with a channel by default */
@@ -1086,6 +1121,16 @@ on_web_socket_message (WebSocketConnection *connection,
10861121
}
10871122
}
10881123

1124+
static gboolean
1125+
on_session_timeout (gpointer user_data)
1126+
{
1127+
CockpitWebService *self = user_data;
1128+
g_warning ("session idle for too long, logging out");
1129+
process_logout (self, NULL);
1130+
self->session_timeout = 0;
1131+
return G_SOURCE_REMOVE;
1132+
}
1133+
10891134
static void
10901135
on_web_socket_open (WebSocketConnection *connection,
10911136
CockpitWebService *self)

0 commit comments

Comments
 (0)