From e99089efc80e519363948d6076d406161cf87c49 Mon Sep 17 00:00:00 2001 From: colinl Date: Wed, 25 Mar 2026 13:55:17 +0000 Subject: [PATCH 1/3] Perform pre-fetch before websocket connection to protect against redirection to login page --- ui/src/main.mjs | 61 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/ui/src/main.mjs b/ui/src/main.mjs index 008d2311..e884a4cf 100644 --- a/ui/src/main.mjs +++ b/ui/src/main.mjs @@ -217,23 +217,50 @@ fetch('_setup') // default interval - every 2.5 seconds function reconnect (interval = 2500) { if (disconnected) { - socket.connect() - if (retryCount >= 14) { - // trying for over 1 minute - interval = 30000 // interval at 30 seconds - } else if (retryCount >= 4) { - // trying for over 10 seconds - interval = 5000 // interval at 5 seconds - } - retryCount++ - // if still within our maximum retry count - if (retryCount <= MAX_RETRIES) { - // check for a connection again in milliseconds - reconnectTO = setTimeout(reconnect, interval) - } else { - // we have been retrying for 5 minutes so give up and reload the page - forcePageReload('Too many retries') - } + /** Prior to trying the socket connect, use an http fetch to check for redirection to auth proxy + * fetch '_setup' as that is a short json file + * use redirect: 'manual' to stop any redirection to a login page in case it causes a CORS error + */ + fetch("_setup", { redirect: 'manual', cache: 'no-cache' }) + .then(function (res) { + const contentType = res.headers?.get("content-type") + /** If the content type is not application/json then likely it is a login request, + * or a failed redirection to login page, either of which would cause the websocket + * connect to fail, so reload the page in order to show the login request. + * Allow it continue the first few times though, allowing the socket connect code to fail + * and retry, in case this is just a transient issue + */ + if((contentType && contentType.includes("application/json")) || retryCount < 3) { + tryConnect(interval) + } else { + forcePageReload('Websocket pre-fetch failed') + } + }) + .catch(function (err) { + // there is some sort of network failure, let the websocket connection code handle that + tryConnect(interval) + }) + } + } + + // default interval - every 2.5 seconds + function tryConnect(interval) { + socket.connect() + if (retryCount >= 14) { + // trying for over 1 minute + interval = 30000 // interval at 30 seconds + } else if (retryCount >= 4) { + // trying for over 10 seconds + interval = 5000 // interval at 5 seconds + } + retryCount++ + // if still within our maximum retry count + if (retryCount <= MAX_RETRIES) { + // check for a connection again in milliseconds + reconnectTO = setTimeout(reconnect, interval) + } else { + // we have been retrying for 5 minutes so give up and reload the page + forcePageReload('Too many retries') } } From e54af60fbc8d4f566956f995c6021b02a373ad0f Mon Sep 17 00:00:00 2001 From: colinl Date: Wed, 25 Mar 2026 15:04:14 +0000 Subject: [PATCH 2/3] Lint error fixes --- ui/src/main.mjs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/src/main.mjs b/ui/src/main.mjs index e884a4cf..68f7a6a5 100644 --- a/ui/src/main.mjs +++ b/ui/src/main.mjs @@ -221,22 +221,22 @@ fetch('_setup') * fetch '_setup' as that is a short json file * use redirect: 'manual' to stop any redirection to a login page in case it causes a CORS error */ - fetch("_setup", { redirect: 'manual', cache: 'no-cache' }) + fetch('_setup', { redirect: 'manual', cache: 'no-cache' }) .then(function (res) { - const contentType = res.headers?.get("content-type") + const contentType = res.headers?.get('content-type') /** If the content type is not application/json then likely it is a login request, * or a failed redirection to login page, either of which would cause the websocket * connect to fail, so reload the page in order to show the login request. * Allow it continue the first few times though, allowing the socket connect code to fail * and retry, in case this is just a transient issue */ - if((contentType && contentType.includes("application/json")) || retryCount < 3) { + if ((contentType && contentType.includes('application/json')) || retryCount < 3) { tryConnect(interval) } else { forcePageReload('Websocket pre-fetch failed') } }) - .catch(function (err) { + .catch(function () { // there is some sort of network failure, let the websocket connection code handle that tryConnect(interval) }) @@ -244,7 +244,7 @@ fetch('_setup') } // default interval - every 2.5 seconds - function tryConnect(interval) { + function tryConnect (interval) { socket.connect() if (retryCount >= 14) { // trying for over 1 minute From 056015a1d442478bdc1701f7d984fd54c53ae94b Mon Sep 17 00:00:00 2001 From: colinl Date: Fri, 27 Mar 2026 14:17:26 +0000 Subject: [PATCH 3/3] Reduced time till page reload is forced --- ui/src/main.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/main.mjs b/ui/src/main.mjs index 68f7a6a5..0dc1a864 100644 --- a/ui/src/main.mjs +++ b/ui/src/main.mjs @@ -229,8 +229,10 @@ fetch('_setup') * connect to fail, so reload the page in order to show the login request. * Allow it continue the first few times though, allowing the socket connect code to fail * and retry, in case this is just a transient issue + * retryCount will still be 0 after first failure, so it will not force a page reload until + * it has failed 3 times */ - if ((contentType && contentType.includes('application/json')) || retryCount < 3) { + if ((contentType && contentType.includes('application/json')) || retryCount < 2) { tryConnect(interval) } else { forcePageReload('Websocket pre-fetch failed')