From e2b3a3209214396fce8817a57230ff19fb330898 Mon Sep 17 00:00:00 2001 From: Paul Albrecht Date: Thu, 30 Jul 2026 18:42:11 +0200 Subject: [PATCH 1/2] Make peer inactivity expiration duration configurable in the UI The management API already supports peer_inactivity_expiration (seconds), but the Authentication settings page hardcoded 600 on every save. This had two consequences: - The inactivity duration could only be set via the API. - Any value set via the API was silently reset to 10 minutes the next time an admin saved the Authentication page. This change adds an "Inactivity Expiration" input (minutes/hours/days) below the "Require login after disconnect" toggle, mirroring the existing Session Expiration input. When the toggle is disabled, the stored account value is preserved instead of being overwritten. Also completes the useExpirationState destructuring for the inactivity state, which previously mislabeled the setExpiresIn setter as the interval value. --- src/modules/settings/AuthenticationTab.tsx | 78 +++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/src/modules/settings/AuthenticationTab.tsx b/src/modules/settings/AuthenticationTab.tsx index 28ba315a1..79f006736 100644 --- a/src/modules/settings/AuthenticationTab.tsx +++ b/src/modules/settings/AuthenticationTab.tsx @@ -105,7 +105,9 @@ export default function AuthenticationTab({ account }: Readonly) { peerInactivityExpirationEnabled, setPeerInactivityExpirationEnabled, peerInactivityExpiresIn, + setPeerInactivityExpiresIn, peerInactivityExpireInterval, + setPeerInactivityExpireInterval, ] = useExpirationState({ enabled: account.settings.peer_inactivity_expiration_enabled, expirationInSeconds: account.settings.peer_inactivity_expiration || 600, @@ -131,6 +133,10 @@ export default function AuthenticationTab({ account }: Readonly) { const saveChanges = async () => { const expiration = convertToSeconds(expiresIn, expireInterval); + const inactivityExpiration = convertToSeconds( + peerInactivityExpiresIn, + peerInactivityExpireInterval, + ); notify({ title: "Save Authentication Settings", @@ -145,7 +151,9 @@ export default function AuthenticationTab({ account }: Readonly) { peer_inactivity_expiration_enabled: loginExpiration ? peerInactivityExpirationEnabled : false, - peer_inactivity_expiration: 600, + peer_inactivity_expiration: peerInactivityExpirationEnabled + ? inactivityExpiration + : account.settings.peer_inactivity_expiration || 600, extra: { ...account.settings?.extra, peer_approval_enabled: isAnyIntegrationEnabled @@ -412,10 +420,76 @@ export default function AuthenticationTab({ account }: Readonly) { helpText={ <> Enable to require authentication after users disconnect from - management for 10 minutes. + management for the configured period of time. } /> +
+
+ + + Time a peer can stay disconnected from management before + re-authentication is required. + +
+
+ setPeerInactivityExpiresIn(e.target.value)} + /> + +
+
From 272683b0e13c7eacdabb65512229afb4ec81e9cb Mon Sep 17 00:00:00 2001 From: Paul Albrecht Date: Thu, 30 Jul 2026 18:54:49 +0200 Subject: [PATCH 2/2] Address review: validate inactivity duration, preserve stored 0 - Block saving while the inactivity duration input is empty or non-positive (convertToSeconds yields NaN for a cleared input) by disabling the Save button and guarding the request payload. - Use ?? instead of || so a stored peer_inactivity_expiration of 0 is preserved rather than silently replaced with 600. --- src/modules/settings/AuthenticationTab.tsx | 28 +++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/modules/settings/AuthenticationTab.tsx b/src/modules/settings/AuthenticationTab.tsx index 79f006736..4d3c26cf2 100644 --- a/src/modules/settings/AuthenticationTab.tsx +++ b/src/modules/settings/AuthenticationTab.tsx @@ -110,7 +110,7 @@ export default function AuthenticationTab({ account }: Readonly) { setPeerInactivityExpireInterval, ] = useExpirationState({ enabled: account.settings.peer_inactivity_expiration_enabled, - expirationInSeconds: account.settings.peer_inactivity_expiration || 600, + expirationInSeconds: account.settings.peer_inactivity_expiration ?? 600, timeRange: ["minutes", "hours", "days"], }); @@ -131,12 +131,20 @@ export default function AuthenticationTab({ account }: Readonly) { isLocalMFAEnabled, ]); + // An empty/cleared input converts to NaN; block saving until it's a + // positive number so the API never receives an invalid duration. + const inactivityExpirationSeconds = convertToSeconds( + peerInactivityExpiresIn, + peerInactivityExpireInterval, + ); + const isInactivityExpirationInvalid = + loginExpiration && + peerInactivityExpirationEnabled && + (!Number.isFinite(inactivityExpirationSeconds) || + inactivityExpirationSeconds <= 0); + const saveChanges = async () => { const expiration = convertToSeconds(expiresIn, expireInterval); - const inactivityExpiration = convertToSeconds( - peerInactivityExpiresIn, - peerInactivityExpireInterval, - ); notify({ title: "Save Authentication Settings", @@ -152,8 +160,8 @@ export default function AuthenticationTab({ account }: Readonly) { ? peerInactivityExpirationEnabled : false, peer_inactivity_expiration: peerInactivityExpirationEnabled - ? inactivityExpiration - : account.settings.peer_inactivity_expiration || 600, + ? inactivityExpirationSeconds + : account.settings.peer_inactivity_expiration ?? 600, extra: { ...account.settings?.extra, peer_approval_enabled: isAnyIntegrationEnabled @@ -227,7 +235,11 @@ export default function AuthenticationTab({ account }: Readonly) {