Auto-extend session cookie every 30 minutes
| @@ -9,6 +9,9 @@ import { ensureImageFormatSupported, getBase64Async, humanFileSize } from './uti | ||
| 9 | 9 | export let currentUser = null; |
| 10 | 10 | export let accountsEnabled = false; |
| 11 | 11 | |
| 12 | +// Extend the session every 30 minutes | |
| 13 | +const SESSION_EXTEND_INTERVAL = 30 * 60 * 1000; | |
| 14 | + | |
| 12 | 15 | /** |
| 13 | 16 | * Enable or disable user account controls in the UI. |
| 14 | 17 | * @param {boolean} isEnabled User account controls enabled |
| @@ -894,6 +897,24 @@ async function slugify(text) { | ||
| 894 | 897 | } |
| 895 | 898 | } |
| 896 | 899 | |
| 900 | +/** | |
| 901 | + * Pings the server to extend the user session. | |
| 902 | + */ | |
| 903 | +async function extendUserSession() { | |
| 904 | + try { | |
| 905 | + const response = await fetch('/api/ping?extend=1', { | |
| 906 | + method: 'GET', | |
| 907 | + headers: getRequestHeaders(), | |
| 908 | + }); | |
| 909 | + | |
| 910 | + if (!response.ok) { | |
| 911 | + throw new Error('Ping did not succeed', { cause: response.status }); | |
| 912 | + } | |
| 913 | + } catch (error) { | |
| 914 | + console.error('Failed to extend user session', error); | |
| 915 | + } | |
| 916 | +} | |
| 917 | + | |
| 897 | 918 | jQuery(() => { |
| 898 | 919 | $('#logout_button').on('click', () => { |
| 899 | 920 | logout(); |
| @@ -904,4 +925,9 @@ jQuery(() => { | ||
| 904 | 925 | $('#account_button').on('click', () => { |
| 905 | 926 | openUserProfile(); |
| 906 | 927 | }); |
| 928 | + setInterval(async () => { | |
| 929 | + if (currentUser) { | |
| 930 | + await extendUserSession(); | |
| 931 | + } | |
| 932 | + }, SESSION_EXTEND_INTERVAL); | |
| 907 | 933 | }); |
| @@ -556,7 +556,13 @@ app.use('/api/users', usersPublicRouter); | ||
| 556 | 556 | |
| 557 | 557 | // Everything below this line requires authentication |
| 558 | 558 | app.use(requireLoginMiddleware); |
| 559 | 559 | app.get('/api/ping', (_request, response) => response.sendStatus(204));{ |
| 560 | + if (request.query.extend && request.session) { | |
| 561 | + request.session.touch = Date.now(); | |
| 562 | + } | |
| 563 | + | |
| 564 | + response.sendStatus(204); | |
| 565 | +}); | |
| 560 | 566 | |
| 561 | 567 | // File uploads |
| 562 | 568 | app.use(multer({ dest: uploadsPath, limits: { fieldSize: 10 * 1024 * 1024 } }).single('avatar')); |