Skip to content

Commit c90c741

Browse files
authored
✨ UX: Handle Cookie expiration (ITISFoundation#5536)
1 parent 86b1eaa commit c90c741

File tree

19 files changed

+209
-123
lines changed

19 files changed

+209
-123
lines changed

services/static-webserver/client/source/class/osparc/Application.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,11 +421,16 @@ qx.Class.define("osparc.Application", {
421421
/**
422422
* Resets session and restarts
423423
*/
424-
logout: function() {
425-
osparc.FlashMessenger.getInstance().logAs(this.tr("You are logged out"));
424+
logout: function(forcedReason) {
425+
if (forcedReason) {
426+
osparc.FlashMessenger.getInstance().logAs(forcedReason, "WARNING", 0);
427+
} else {
428+
osparc.FlashMessenger.getInstance().logAs(this.tr("You are logged out"), "INFO");
429+
}
426430

427431
osparc.data.PollTasks.getInstance().removeTasks();
428432
osparc.MaintenanceTracker.getInstance().stopTracker();
433+
osparc.CookieExpirationTracker.getInstance().stopTracker();
429434
osparc.announcement.Tracker.getInstance().stopTracker();
430435
osparc.auth.Manager.getInstance().logout();
431436
if ("closeEditor" in this.__mainPage) {
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2024 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
qx.Class.define("osparc.CookieExpirationTracker", {
19+
extend: qx.core.Object,
20+
type: "singleton",
21+
22+
statics: {
23+
PERMANENT_WARN_IN_ADVANCE: 60*60, // Show Permanent Flash Message 1h in advance
24+
LOG_OUT_BEFORE_EXPIRING: 60 // Log user out 1' in before expiring
25+
},
26+
27+
members: {
28+
__message: null,
29+
__messageTimer: null,
30+
__messageInterval: null,
31+
__logoutTimer: null,
32+
33+
startTracker: function() {
34+
const cookieMaxAge = osparc.store.StaticInfo.getInstance().getCookieMaxAge();
35+
if (cookieMaxAge) {
36+
const nowDate = new Date();
37+
const expirationTime = nowDate.getTime() + cookieMaxAge*1000 - this.self().LOG_OUT_BEFORE_EXPIRING*1000;
38+
const expirationDate = new Date(expirationTime);
39+
const showMessageIn = Math.max(cookieMaxAge - this.self().PERMANENT_WARN_IN_ADVANCE, 0);
40+
this.__messageTimer = setTimeout(() => {
41+
const willExpireIn = parseInt((expirationDate - nowDate)/1000);
42+
this.__displayFlashMessage(willExpireIn);
43+
}, showMessageIn*1000);
44+
45+
const logOutIn = Math.max(cookieMaxAge - this.self().LOG_OUT_BEFORE_EXPIRING, 0);
46+
this.__logoutTimer = setTimeout(() => this.__logoutUser(), logOutIn*1000);
47+
}
48+
},
49+
50+
stopTracker: function() {
51+
if (this.__messageTimer) {
52+
clearTimeout(this.__messageTimer);
53+
}
54+
if (this.__logoutTimer) {
55+
clearTimeout(this.__logoutTimer);
56+
}
57+
58+
this.__removeFlashMessage();
59+
},
60+
61+
__displayFlashMessage: function(willExpireIn) {
62+
const updateFlashMessage = () => {
63+
if (willExpireIn <= 0) {
64+
this.__removeFlashMessage();
65+
return;
66+
}
67+
68+
this.__updateFlashMessage(willExpireIn);
69+
willExpireIn--;
70+
};
71+
this.__messageInterval = setInterval(updateFlashMessage, 1000);
72+
},
73+
74+
__removeFlashMessage: function() {
75+
// removes a flash message if displaying
76+
if (this.__messageInterval) {
77+
clearInterval(this.__messageInterval);
78+
}
79+
if (this.__message) {
80+
osparc.FlashMessenger.getInstance().removeMessage(this.__message);
81+
this.__message = null;
82+
}
83+
},
84+
85+
__updateFlashMessage: function(timeoutSec = 1000) {
86+
const timeout = osparc.utils.Utils.formatSeconds(timeoutSec);
87+
const text = qx.locale.Manager.tr(`Your session will expire in ${timeout}.<br>Please log out and log in again.`);
88+
if (this.__message === null) {
89+
this.__message = osparc.FlashMessenger.getInstance().logAs(text, "WARNING", timeoutSec*1000);
90+
} else {
91+
this.__message.setMessage(text);
92+
}
93+
},
94+
95+
__logoutUser: function() {
96+
const reason = qx.locale.Manager.tr("Session expired");
97+
qx.core.Init.getApplication().logout(reason);
98+
}
99+
}
100+
});

services/static-webserver/client/source/class/osparc/FlashMessenger.js

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* Here is a little example of how to use the class.
2929
*
3030
* <pre class='javascript'>
31-
* osparc.FlashMessenger.getInstance().log(log);
31+
* osparc.FlashMessenger.getInstance().logAs(log);
3232
* </pre>
3333
*/
3434

@@ -55,8 +55,8 @@ qx.Class.define("osparc.FlashMessenger", {
5555

5656
statics: {
5757
MAX_DISPLAYED: 3,
58-
logAs: function(message, level, logger, duration) {
59-
return this.getInstance().logAs(message, level, logger, duration);
58+
logAs: function(message, level, duration) {
59+
return this.getInstance().logAs(message, level, duration);
6060
}
6161
},
6262

@@ -70,27 +70,21 @@ qx.Class.define("osparc.FlashMessenger", {
7070
*
7171
* @param {String} message Message that the message will show.
7272
* @param {String="INFO","DEBUG","WARNING","ERROR"} level Level of the warning. The color of the badge will change accordingly.
73-
* @param {*} logger IDK
7473
* @param {Number} duration
7574
*/
76-
logAs: function(message, level="INFO", logger=null, duration=null) {
75+
logAs: function(message, level="INFO", duration=null) {
7776
return this.log({
7877
message,
7978
level: level.toUpperCase(),
80-
logger,
8179
duration
8280
});
8381
},
8482

8583
log: function(logMessage) {
86-
// TODO: This doesn't look cool
87-
let message = osparc.utils.Utils.isObject(logMessage.message) && "message" in logMessage.message ?
84+
const message = osparc.utils.Utils.isObject(logMessage.message) && "message" in logMessage.message ?
8885
logMessage.message.message :
8986
logMessage.message;
90-
let logger = logMessage.logger;
91-
if (logger) {
92-
message = logger + ": " + message;
93-
}
87+
9488
const level = logMessage.level.toUpperCase(); // "DEBUG", "INFO", "WARNING", "ERROR"
9589

9690
const flashMessage = new osparc.ui.message.FlashMessage(message, level, logMessage.duration);
@@ -103,7 +97,7 @@ qx.Class.define("osparc.FlashMessenger", {
10397
/**
10498
* Private method to show a message to the user. It will stack it on the previous ones.
10599
*
106-
* @param {osparc.ui.message.FlashMessage} flashMessage FlassMessage element to show.
100+
* @param {osparc.ui.message.FlashMessage} flashMessage FlashMessage element to show.
107101
*/
108102
__showMessage: function(flashMessage) {
109103
this.__messages.remove(flashMessage);
@@ -122,13 +116,15 @@ qx.Class.define("osparc.FlashMessenger", {
122116
const wordCount = flashMessage.getMessage() ? flashMessage.getMessage().split(" ").length : 20;
123117
duration = Math.max(5500, wordCount*500); // An average reader takes 300ms to read a word
124118
}
125-
qx.event.Timer.once(() => this.removeMessage(flashMessage), this, duration);
119+
if (duration !== 0) {
120+
qx.event.Timer.once(() => this.removeMessage(flashMessage), this, duration);
121+
}
126122
},
127123

128124
/**
129125
* Private method to remove a message. If there are still messages in the queue, it will show the next available one.
130126
*
131-
* @param {osparc.ui.message.FlashMessage} flashMessage FlassMessage element to remove.
127+
* @param {osparc.ui.message.FlashMessage} flashMessage FlashMessage element to remove.
132128
*/
133129
removeMessage: function(flashMessage) {
134130
if (this.__messageContainer.indexOf(flashMessage) > -1) {

services/static-webserver/client/source/class/osparc/MaintenanceTracker.js

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ qx.Class.define("osparc.MaintenanceTracker", {
4242
statics: {
4343
CHECK_INTERVAL: 15*60*1000, // Check every 15'
4444
CLOSABLE_WARN_IN_ADVANCE: 24*60*60*1000, // Show Ribbon Closable Message 24h in advance
45-
PERMANENT_WARN_IN_ADVANCE: 30*60*1000 // Show Ribbon Permament Message 30' in advance
45+
PERMANENT_WARN_IN_ADVANCE: 30*60*1000 // Show Ribbon Permanent Message 30' in advance
4646
},
4747

4848
members: {
49-
__checkInternval: null,
49+
__checkInterval: null,
5050
__lastRibbonMessage: null,
5151
__logoutTimer: null,
5252

@@ -64,12 +64,12 @@ qx.Class.define("osparc.MaintenanceTracker", {
6464
.catch(err => console.error(err));
6565
};
6666
checkMaintenance();
67-
this.__checkInternval = setInterval(checkMaintenance, this.self().CHECK_INTERVAL);
67+
this.__checkInterval = setInterval(checkMaintenance, this.self().CHECK_INTERVAL);
6868
},
6969

7070
stopTracker: function() {
71-
if (this.__checkInternval) {
72-
clearInterval(this.__checkInternval);
71+
if (this.__checkInterval) {
72+
clearInterval(this.__checkInterval);
7373
}
7474
},
7575

@@ -160,27 +160,25 @@ qx.Class.define("osparc.MaintenanceTracker", {
160160
}
161161
},
162162

163+
__logout: function() {
164+
this.set({
165+
start: null,
166+
end: null,
167+
reason: null
168+
});
169+
const reason = qx.locale.Manager.tr("We are under maintenance. Please check back later");
170+
qx.core.Init.getApplication().logout(reason);
171+
},
172+
163173
__scheduleLogout: function() {
164174
this.__removeScheduledLogout();
165175

166-
const logoutUser = () => {
167-
this.set({
168-
start: null,
169-
end: null,
170-
reason: null
171-
});
172-
let text = qx.locale.Manager.tr("We are under maintenance.");
173-
text += "<br>";
174-
text += qx.locale.Manager.tr("Please check back later");
175-
osparc.FlashMessenger.getInstance().logAs(text, "WARNING");
176-
qx.core.Init.getApplication().logout();
177-
};
178176
const now = new Date();
179177
if (this.getStart().getTime() > now.getTime()) {
180178
const diff = this.getStart().getTime() - now.getTime();
181-
this.__logoutTimer = setTimeout(() => logoutUser(), diff);
179+
this.__logoutTimer = setTimeout(() => this.__logout(), diff);
182180
} else if (this.getStart().getTime() < now.getTime() && this.getEnd().getTime() > now.getTime()) {
183-
logoutUser();
181+
this.__logout();
184182
}
185183
},
186184

services/static-webserver/client/source/class/osparc/announcement/Tracker.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ qx.Class.define("osparc.announcement.Tracker", {
2424
},
2525

2626
members: {
27-
__checkInternval: null,
27+
__checkInterval: null,
2828
__announcements: null,
2929

3030
startTracker: function() {
@@ -40,12 +40,12 @@ qx.Class.define("osparc.announcement.Tracker", {
4040
.catch(err => console.error(err));
4141
};
4242
checkAnnouncements();
43-
this.__checkInternval = setInterval(checkAnnouncements, this.self().CHECK_INTERVAL);
43+
this.__checkInterval = setInterval(checkAnnouncements, this.self().CHECK_INTERVAL);
4444
},
4545

4646
stopTracker: function() {
47-
if (this.__checkInternval) {
48-
clearInterval(this.__checkInternval);
47+
if (this.__checkInterval) {
48+
clearInterval(this.__checkInterval);
4949
}
5050
},
5151

services/static-webserver/client/source/class/osparc/auth/ui/ResetPassView.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ qx.Class.define("osparc.auth.ui.ResetPassView", {
100100

101101
const failFun = msg => {
102102
msg = msg || this.tr("Could not reset password");
103-
osparc.FlashMessenger.getInstance().logAs(msg, "ERROR", "user");
103+
osparc.FlashMessenger.getInstance().logAs(msg, "ERROR");
104104
};
105105

106106
const manager = osparc.auth.Manager.getInstance();

services/static-webserver/client/source/class/osparc/desktop/MainPage.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ qx.Class.define("osparc.desktop.MainPage", {
5656
// Some resources request before building the main stack
5757
osparc.WindowSizeTracker.getInstance().startTracker();
5858
osparc.MaintenanceTracker.getInstance().startTracker();
59+
osparc.CookieExpirationTracker.getInstance().startTracker();
5960

6061
const store = osparc.store.Store.getInstance();
6162
const preloadPromises = [];
@@ -270,7 +271,7 @@ qx.Class.define("osparc.desktop.MainPage", {
270271
__showDashboard: function() {
271272
if (!osparc.data.Permissions.getInstance().canDo("dashboard.read")) {
272273
// If guest fails to load study, log him out
273-
osparc.auth.Manager.getInstance().logout();
274+
qx.core.Init.getApplication().logout();
274275
return;
275276
}
276277

services/static-webserver/client/source/class/osparc/desktop/StudyEditorIdlingTracker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ qx.Class.define("osparc.desktop.StudyEditorIdlingTracker", {
4242

4343
__updateFlashMessage: function(timeoutSec) {
4444
if (this.__idleFlashMessage === null) {
45-
this.__idleFlashMessage = osparc.FlashMessenger.getInstance().logAs(qx.locale.Manager.tr("Are you still there?"), "WARNING", null, timeoutSec*1000);
45+
this.__idleFlashMessage = osparc.FlashMessenger.getInstance().logAs(qx.locale.Manager.tr("Are you still there?"), "WARNING", timeoutSec*1000);
4646
}
4747

4848
let msg = qx.locale.Manager.tr("Are you still there?") + "<br>";

services/static-webserver/client/source/class/osparc/desktop/WorkbenchView.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
763763
const usedWallet = store.getWallets().find(wallet => wallet.getWalletId() === walletId);
764764
const walletName = usedWallet.getName();
765765
const text = `Wallet "${walletName}", running your service(s) has run out of credits. Stopping service(s) gracefully.`;
766-
osparc.FlashMessenger.getInstance().logAs(this.tr(text), "ERROR", null, flashMessageDisplayDuration);
766+
osparc.FlashMessenger.getInstance().logAs(this.tr(text), "ERROR", flashMessageDisplayDuration);
767767
}, this);
768768
}
769769
},

services/static-webserver/client/source/class/osparc/desktop/paymentMethods/PaymentMethods.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ qx.Class.define("osparc.desktop.paymentMethods.PaymentMethods", {
168168
.catch(err => {
169169
console.error(err)
170170
osparc.FlashMessenger.getInstance().logAs(
171-
this.tr("We could not retreive your saved payment methods. Please try again later."),
171+
this.tr("We could not retrieve your saved payment methods. Please try again later."),
172172
"ERROR"
173173
);
174174
});

0 commit comments

Comments
 (0)