From fe17c6ba75ef9d3bf01c7f7f942aa100b6c0c049 Mon Sep 17 00:00:00 2001 From: Tim Quelch <tim@tquelch.com> Date: Thu, 26 Sep 2024 06:41:52 +1000 Subject: [PATCH] Forcibly reload app from server when API is redirected (#3286) * Add advanced setting to reload app from server * Add change notes * Automatically reload when API call is redirected * Error on redirect so we don't use the response * Remove setting to reload * Update release notes --------- Co-authored-by: youngcw <calebyoung94@gmail.com> --- .../src/browser-preload.browser.js | 16 +++++++++++++++ packages/desktop-client/src/global-events.ts | 4 ++++ packages/loot-core/src/client/actions/app.ts | 6 ++++++ .../src/platform/server/fetch/index.web.ts | 20 ++++++++++++++++++- .../loot-core/src/types/server-events.d.ts | 1 + packages/loot-core/typings/window.d.ts | 1 + upcoming-release-notes/3286.md | 6 ++++++ 7 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 upcoming-release-notes/3286.md diff --git a/packages/desktop-client/src/browser-preload.browser.js b/packages/desktop-client/src/browser-preload.browser.js index 75065ca52..2522fce90 100644 --- a/packages/desktop-client/src/browser-preload.browser.js +++ b/packages/desktop-client/src/browser-preload.browser.js @@ -51,6 +51,22 @@ global.Actual = { window.location.reload(); }, + reload: () => { + if (window.navigator.serviceWorker == null) return; + + // Unregister the service worker handling routing and then reload. This should force the reload + // to query the actual server rather than delegating to the worker + return window.navigator.serviceWorker + .getRegistration('/') + .then(registration => { + if (registration == null) return; + return registration.unregister(); + }) + .then(() => { + window.location.reload(); + }); + }, + restartElectronServer: () => {}, openFileDialog: async ({ filters = [] }) => { diff --git a/packages/desktop-client/src/global-events.ts b/packages/desktop-client/src/global-events.ts index 81de63927..619f673b2 100644 --- a/packages/desktop-client/src/global-events.ts +++ b/packages/desktop-client/src/global-events.ts @@ -142,4 +142,8 @@ export function handleGlobalEvents(actions: BoundActions, store: Store<State>) { actions.closeBudgetUI(); actions.setAppState({ loadingText: null }); }); + + listen('api-fetch-redirected', () => { + actions.reloadApp(); + }); } diff --git a/packages/loot-core/src/client/actions/app.ts b/packages/loot-core/src/client/actions/app.ts index 6f6ca7696..e586f55dc 100644 --- a/packages/loot-core/src/client/actions/app.ts +++ b/packages/loot-core/src/client/actions/app.ts @@ -46,3 +46,9 @@ export function focused() { return send('app-focused'); }; } + +export function reloadApp() { + return () => { + global.Actual.reload(); + }; +} diff --git a/packages/loot-core/src/platform/server/fetch/index.web.ts b/packages/loot-core/src/platform/server/fetch/index.web.ts index db20b9acb..f93196b0f 100644 --- a/packages/loot-core/src/platform/server/fetch/index.web.ts +++ b/packages/loot-core/src/platform/server/fetch/index.web.ts @@ -1 +1,19 @@ -export const fetch = globalThis.fetch; +import * as connection from '../connection'; + +export const fetch = async ( + input: RequestInfo | URL, + options?: RequestInit, +): Promise<Response> => { + const response = await globalThis.fetch(input, options); + + // Detect if the API query has been redirected to a different origin. This may indicate that the + // request has been intercepted by an authentication proxy + const originalUrl = new URL(input instanceof Request ? input.url : input); + const responseUrl = new URL(response.url); + if (response.redirected && responseUrl.host !== originalUrl.host) { + connection.send('api-fetch-redirected'); + throw new Error(`API request redirected to ${responseUrl.host}`); + } + + return response; +}; diff --git a/packages/loot-core/src/types/server-events.d.ts b/packages/loot-core/src/types/server-events.d.ts index d256ddfd4..c53004a9c 100644 --- a/packages/loot-core/src/types/server-events.d.ts +++ b/packages/loot-core/src/types/server-events.d.ts @@ -18,4 +18,5 @@ export interface ServerEvents { 'start-load': unknown; 'sync-event': { type; subtype; meta; tables; syncDisabled }; 'undo-event': UndoState; + 'api-fetch-redirected': unknown; } diff --git a/packages/loot-core/typings/window.d.ts b/packages/loot-core/typings/window.d.ts index 870114cb6..9dde1c2b4 100644 --- a/packages/loot-core/typings/window.d.ts +++ b/packages/loot-core/typings/window.d.ts @@ -15,6 +15,7 @@ declare global { opts: Parameters<import('electron').Dialog['showOpenDialogSync']>[0], ) => Promise<string[]>; relaunch: () => void; + reload: (() => Promise<void>) | undefined; restartElectronServer: () => void; }; diff --git a/upcoming-release-notes/3286.md b/upcoming-release-notes/3286.md new file mode 100644 index 000000000..d055ab0de --- /dev/null +++ b/upcoming-release-notes/3286.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [TimQuelch] +--- + +Forcibly reload app when API request is redirected. This fixes issue #2793 -- GitLab