From 53576f5578295f8a81c4406e2732033d5b0d37a6 Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Mon, 10 Feb 2025 19:50:30 +0100 Subject: [PATCH 1/8] feat(config): add Session.cookieMaxAge allows users to control how long their session will be live, before it expires and they are forced to login again defaults to 1 day ("24 * 60 * 60 * 1000") as previously set in sessionParser --- config-sample.ini | 1 + src/services/config.ts | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config-sample.ini b/config-sample.ini index 939eaa7a5..49222b1fa 100644 --- a/config-sample.ini +++ b/config-sample.ini @@ -36,6 +36,7 @@ trustedReverseProxy=false # e.g. if you have https://your-domain.com/triliumNext/instanceA and https://your-domain.com/triliumNext/instanceB # you would want to set the cookiePath value to "/triliumNext/instanceA" for your first and "/triliumNext/instanceB" for your second instance cookiePath=/ +cookieMaxAge= [Sync] #syncServerHost= diff --git a/src/services/config.ts b/src/services/config.ts index b529d4792..28b598b53 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -34,6 +34,7 @@ export interface TriliumConfig { }; Session: { cookiePath: string; + cookieMaxAge: number; } Sync: { syncServerHost: string; @@ -81,7 +82,10 @@ const config: TriliumConfig = { Session: { cookiePath: - process.env.TRILIUM_SESSION_COOKIEPATH || iniConfig?.Session?.cookiePath || "/" + process.env.TRILIUM_SESSION_COOKIEPATH || iniConfig?.Session?.cookiePath || "/", + + cookieMaxAge: + process.env.TRILIUM_SESSION_COOKIEMAXAGE || iniConfig?.Session?.cookieMaxAge || "24 * 60 * 60 * 1000" // 24 hours in Milliseconds }, Sync: { From 4e23b5193d271c415bfade19e9eeed73c6cb8e12 Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Mon, 10 Feb 2025 19:51:05 +0100 Subject: [PATCH 2/8] feat(session_parser): use Session.cookieMaxAge from config --- src/routes/session_parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/session_parser.ts b/src/routes/session_parser.ts index eaaf0ebe9..d82e8be3d 100644 --- a/src/routes/session_parser.ts +++ b/src/routes/session_parser.ts @@ -12,7 +12,7 @@ const sessionParser = session({ cookie: { path: config.Session.cookiePath, httpOnly: true, - maxAge: 24 * 60 * 60 * 1000 // in milliseconds + maxAge: config.Session.cookieMaxAge }, name: "trilium.sid", store: new FileStore({ From 04827c0ce19105cdb98b764651b161b62b26db04 Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Mon, 10 Feb 2025 19:59:40 +0100 Subject: [PATCH 3/8] fix(session_parser): FileStore ttl should be ideally the same as session cookies maxAge this avoids having "unused" dead session on the filesystem --- src/routes/session_parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/session_parser.ts b/src/routes/session_parser.ts index d82e8be3d..22323ce58 100644 --- a/src/routes/session_parser.ts +++ b/src/routes/session_parser.ts @@ -16,7 +16,7 @@ const sessionParser = session({ }, name: "trilium.sid", store: new FileStore({ - ttl: 30 * 24 * 3600, + ttl: config.Session.cookieMaxAge / 1000, // needs value in seconds path: `${dataDir.TRILIUM_DATA_DIR}/sessions` }) }); From 2a740781cb42f9c087a3151a9fbf7e7791ea2b8b Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Thu, 13 Feb 2025 08:39:02 +0100 Subject: [PATCH 4/8] feat(session_parser): use seconds for setting maxAge and update default value to 21 days 21 days was used in the login route previously, when "remember me" was set --- src/routes/session_parser.ts | 4 ++-- src/services/config.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/session_parser.ts b/src/routes/session_parser.ts index 22323ce58..503cfff75 100644 --- a/src/routes/session_parser.ts +++ b/src/routes/session_parser.ts @@ -12,11 +12,11 @@ const sessionParser = session({ cookie: { path: config.Session.cookiePath, httpOnly: true, - maxAge: config.Session.cookieMaxAge + maxAge: config.Session.cookieMaxAge * 1000 // needs value in milliseconds }, name: "trilium.sid", store: new FileStore({ - ttl: config.Session.cookieMaxAge / 1000, // needs value in seconds + ttl: config.Session.cookieMaxAge, path: `${dataDir.TRILIUM_DATA_DIR}/sessions` }) }); diff --git a/src/services/config.ts b/src/services/config.ts index 28b598b53..b17ed954b 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -85,7 +85,7 @@ const config: TriliumConfig = { process.env.TRILIUM_SESSION_COOKIEPATH || iniConfig?.Session?.cookiePath || "/", cookieMaxAge: - process.env.TRILIUM_SESSION_COOKIEMAXAGE || iniConfig?.Session?.cookieMaxAge || "24 * 60 * 60 * 1000" // 24 hours in Milliseconds + process.env.TRILIUM_SESSION_COOKIEMAXAGE || iniConfig?.Session?.cookieMaxAge || 21 * 24 * 60 * 60 // 21 Days in Seconds }, Sync: { From 38215c46aec5ac3561b1efa05a2b242a6b39f464 Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Thu, 13 Feb 2025 09:04:34 +0100 Subject: [PATCH 5/8] feat(login): make use of default maxAge by sessionParser cookie will use the default value set in sessionParser middleware, which is controlled by config.Session.cookieMaxAge if rememberMe is not set -> the value is unset and the cookie becomes a non-persistent cookie, which the browser delete after the current session (e.g. when you close the browser) --- src/routes/login.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/routes/login.ts b/src/routes/login.ts index 21ebaf280..9bac3db74 100644 --- a/src/routes/login.ts +++ b/src/routes/login.ts @@ -70,9 +70,12 @@ function login(req: Request, res: Response) { } req.session.regenerate(() => { - const sessionMaxAge = 21 * 24 * 3600000 // 3 weeks in Milliseconds + if (!rememberMe) { + // unset default maxAge set by sessionParser + // Cookie becomes non-persistent and expires after current browser session (e.g. when browser is closed) + req.session.cookie.maxAge = undefined; + } - req.session.cookie.maxAge = (rememberMe) ? sessionMaxAge : undefined; req.session.loggedIn = true; res.redirect("."); From 201663d9ecbde7587c68f6d6661ca2315ebe0ec6 Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Thu, 13 Feb 2025 09:07:25 +0100 Subject: [PATCH 6/8] chore(prettier): fix prettier issues --- src/routes/login.ts | 1 - src/routes/session_parser.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/routes/login.ts b/src/routes/login.ts index 9bac3db74..68b98e893 100644 --- a/src/routes/login.ts +++ b/src/routes/login.ts @@ -80,7 +80,6 @@ function login(req: Request, res: Response) { res.redirect("."); }); - } function verifyPassword(guessedPassword: string) { diff --git a/src/routes/session_parser.ts b/src/routes/session_parser.ts index 503cfff75..89df0e037 100644 --- a/src/routes/session_parser.ts +++ b/src/routes/session_parser.ts @@ -12,7 +12,7 @@ const sessionParser = session({ cookie: { path: config.Session.cookiePath, httpOnly: true, - maxAge: config.Session.cookieMaxAge * 1000 // needs value in milliseconds + maxAge: config.Session.cookieMaxAge * 1000 // needs value in milliseconds }, name: "trilium.sid", store: new FileStore({ From cab0a5e41f3bad5a864092d3a056f2346466437d Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Thu, 13 Feb 2025 09:25:24 +0100 Subject: [PATCH 7/8] feat(config): improve Session descriptions --- config-sample.ini | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/config-sample.ini b/config-sample.ini index 49222b1fa..baa026730 100644 --- a/config-sample.ini +++ b/config-sample.ini @@ -30,13 +30,18 @@ trustedReverseProxy=false [Session] -# Use this setting to constrain the current instance's "Path" value for the set cookies +# Use this setting to set a custom value for the "Path" Attribute value of the session cookie. # This can be useful, when you have several instances running on the same domain, under different paths (e.g. by using a reverse proxy). -# It prevents your instances from overwriting each others' cookies. -# e.g. if you have https://your-domain.com/triliumNext/instanceA and https://your-domain.com/triliumNext/instanceB +# It prevents your instances from overwriting each others' cookies, allowing you to stay logged in multiple instances simultanteously. +# E.g. if you have instances running under https://your-domain.com/triliumNext/instanceA and https://your-domain.com/triliumNext/instanceB # you would want to set the cookiePath value to "/triliumNext/instanceA" for your first and "/triliumNext/instanceB" for your second instance cookiePath=/ -cookieMaxAge= + +# Use this setting to set a custom value for the "Max-Age" Attribute of the session cookie. +# This controls how long your session will be valid, before it expires and you need to log in again, when you use the "Remember Me" option. +# Value needs to be entered in Seconds. +# Default value is 1814400 Seconds, which is 21 Days. +cookieMaxAge=1814400 [Sync] #syncServerHost= From b692c00b8de0aef5380858570e8366c6773b9697 Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Thu, 13 Feb 2025 09:46:49 +0100 Subject: [PATCH 8/8] feat(config): improve typesafety by definitely returning a number previously it was either a number like string (in case env or config.ini was used) or a number (the fallback value) we now parseInt the value -> if any value is NaN (e.g. because it was incorrectly set) it will try with the next, before it uses the fallback value the strange looking `parseInt(String(process.env.TRILIUM_SESSION_COOKIEMAXAGE))` is required to make TypeScript happy, other variants of trying to get the value into a string were not good enough for typescript :-) The `String(process.env.TRILIUM_SESSION_COOKIEMAXAGE)` will now either return a number like value or 'undefined' (as string), which parseInt parses into NaN, which is falsy. --- src/services/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/config.ts b/src/services/config.ts index b17ed954b..b10015aa7 100644 --- a/src/services/config.ts +++ b/src/services/config.ts @@ -85,7 +85,7 @@ const config: TriliumConfig = { process.env.TRILIUM_SESSION_COOKIEPATH || iniConfig?.Session?.cookiePath || "/", cookieMaxAge: - process.env.TRILIUM_SESSION_COOKIEMAXAGE || iniConfig?.Session?.cookieMaxAge || 21 * 24 * 60 * 60 // 21 Days in Seconds + parseInt(String(process.env.TRILIUM_SESSION_COOKIEMAXAGE)) || parseInt(iniConfig?.Session?.cookieMaxAge) || 21 * 24 * 60 * 60 // 21 Days in Seconds }, Sync: {