From fb7844b872e1ade1e94bc202aeb135724e4175a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Fri, 14 Nov 2025 12:39:21 +0100 Subject: [PATCH 1/4] handle errors when checking latest version --- .../ApplicationUpdateManager.tsx | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/components/ApplicationUpdateManager/ApplicationUpdateManager.tsx b/src/components/ApplicationUpdateManager/ApplicationUpdateManager.tsx index 0a756419..393ac619 100644 --- a/src/components/ApplicationUpdateManager/ApplicationUpdateManager.tsx +++ b/src/components/ApplicationUpdateManager/ApplicationUpdateManager.tsx @@ -1,7 +1,7 @@ import { getVersion } from '@tauri-apps/api/app'; import { listen, type UnlistenFn } from '@tauri-apps/api/event'; +import { error } from '@tauri-apps/plugin-log'; import { useEffect, useState } from 'react'; - import { clientApi } from '../../pages/client/clientAPI/clientApi.ts'; import { useClientStore } from '../../pages/client/hooks/useClientStore'; import { TauriEventKey } from '../../pages/client/types'; @@ -71,16 +71,20 @@ export const ApplicationUpdateManager = () => { const getNewVersion = async (appVersion: string) => { if (!appVersion) return; - const response = await getLatestAppVersion(); - - setApplicationUpdateData({ - currentVersion: appVersion, - latestVersion: response.version, - releaseDate: response.release_date, - releaseNotesUrl: response.release_notes_url, - updateUrl: response.update_url, - dismissed: false, - }); + try { + const response = await getLatestAppVersion(); + + setApplicationUpdateData({ + currentVersion: appVersion, + latestVersion: response.version, + releaseDate: response.release_date, + releaseNotesUrl: response.release_notes_url, + updateUrl: response.update_url, + dismissed: false, + }); + } catch (e) { + error(`Failed to check latest app version: ${e}`); + } }; getNewVersion(appVersion); From 2782ef548b910ca7071ab47270b8498542647752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Fri, 14 Nov 2025 12:39:32 +0100 Subject: [PATCH 2/4] biome migration --- biome.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biome.json b/biome.json index 2441f3ed..db0dbff7 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json", + "$schema": "https://biomejs.dev/schemas/2.3.3/schema.json", "vcs": { "enabled": false, "clientKind": "git", From 346497aa29ccffe7b91ee5ff4579788463cfe181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Fri, 14 Nov 2025 12:43:16 +0100 Subject: [PATCH 3/4] handle proxy request rejection --- .../modals/MFAModal/MFAModal.tsx | 100 ++++++++++-------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/src/pages/client/pages/ClientInstancePage/components/LocationsList/modals/MFAModal/MFAModal.tsx b/src/pages/client/pages/ClientInstancePage/components/LocationsList/modals/MFAModal/MFAModal.tsx index 4915788e..fe97339e 100644 --- a/src/pages/client/pages/ClientInstancePage/components/LocationsList/modals/MFAModal/MFAModal.tsx +++ b/src/pages/client/pages/ClientInstancePage/components/LocationsList/modals/MFAModal/MFAModal.tsx @@ -117,56 +117,62 @@ export const MFAModal = () => { location_id: location.network_id, }; - const response = await fetch(mfaStartUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - CLIENT_VERSION_HEADER: platformInfo.client_version, - CLIENT_PLATFORM_HEADER: platformInfo.platform_info, - }, - body: JSON.stringify(data), - }); + try { + const response = await fetch(mfaStartUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + CLIENT_VERSION_HEADER: platformInfo.client_version, + CLIENT_PLATFORM_HEADER: platformInfo.platform_info, + }, + body: JSON.stringify(data), + }); - if (response.ok) { - const data = (await response.json()) as MFAStartResponse; - - switch (method) { - case 0: - setScreen('authenticator_app'); - break; - case 1: - setScreen('email'); - break; - case 2: - setScreen('openid_login'); - break; - case 4: - // just to be safe - if (!isPresent(data.challenge)) { - toaster.error('Unsupported response from proxy'); - } - setScreen('mobile_approve'); - break; - default: - toaster.error(localLL.errors.mfaStartGeneric()); + if (response.ok) { + const data = (await response.json()) as MFAStartResponse; + + switch (method) { + case 0: + setScreen('authenticator_app'); + break; + case 1: + setScreen('email'); + break; + case 2: + setScreen('openid_login'); + break; + case 4: + // just to be safe + if (!isPresent(data.challenge)) { + toaster.error('Unsupported response from proxy'); + } + setScreen('mobile_approve'); + break; + default: + toaster.error(localLL.errors.mfaStartGeneric()); + return; + } + setStartResponse(data); + return data; + } else { + const errorData = ((await response.json()) as unknown as MFAError).error; + error(`MFA failed to start with the following error: ${errorData}`); + if (method === 2) { + setScreen('openid_unavailable'); return; - } - setStartResponse(data); - return data; - } else { - const errorData = ((await response.json()) as unknown as MFAError).error; - error(`MFA failed to start with the following error: ${errorData}`); - if (method === 2) { - setScreen('openid_unavailable'); - return; - } + } - if (errorData === 'selected MFA method not available') { - toaster.error(localLL.errors.mfaNotConfigured()); - } else { - toaster.error(localLL.errors.mfaStartGeneric()); - } + if (errorData === 'selected MFA method not available') { + toaster.error(localLL.errors.mfaNotConfigured()); + } else { + toaster.error(localLL.errors.mfaStartGeneric()); + } + return; + } + } catch (rej) { + error(`Failed to execute proxy request: ${rej}`); + toaster.error(localLL.errors.mfaStartGeneric()); return; } }, @@ -583,6 +589,8 @@ const MFACodeForm = ({ description, token, proxyUrl, resetState }: MFACodeForm) body: JSON.stringify(data), }); + console.log('response: ', response); + if (response.ok) { closeModal(); const data = (await response.json()) as MFAFinishResponse; From f2946da1cf457bc90275052a896706e0133e654f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Fri, 14 Nov 2025 12:51:09 +0100 Subject: [PATCH 4/4] also update MFA finish --- src/i18n/en/index.ts | 2 + src/i18n/i18n-types.ts | 8 ++ .../modals/MFAModal/MFAModal.tsx | 82 ++++++++++--------- 3 files changed, 53 insertions(+), 39 deletions(-) diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts index c598695e..0fc79abe 100644 --- a/src/i18n/en/index.ts +++ b/src/i18n/en/index.ts @@ -770,6 +770,8 @@ If you want to disengage your VPN connection, simply press "deactivate". mfaNotConfigured: 'Selected method has not been configured.', mfaStartGeneric: 'Could not start MFA process. Please try again or contact administrator.', + mfaFinishGeneric: + 'Could not finish MFA process. Please try again or contact administrator.', instanceNotFound: 'Could not find instance.', locationNotSpecified: 'Location is not specified.', invalidCode: diff --git a/src/i18n/i18n-types.ts b/src/i18n/i18n-types.ts index 7eeaf5be..64140060 100644 --- a/src/i18n/i18n-types.ts +++ b/src/i18n/i18n-types.ts @@ -1702,6 +1702,10 @@ type RootTranslation = { * C​o​u​l​d​ ​n​o​t​ ​s​t​a​r​t​ ​M​F​A​ ​p​r​o​c​e​s​s​.​ ​P​l​e​a​s​e​ ​t​r​y​ ​a​g​a​i​n​ ​o​r​ ​c​o​n​t​a​c​t​ ​a​d​m​i​n​i​s​t​r​a​t​o​r​. */ mfaStartGeneric: string + /** + * C​o​u​l​d​ ​n​o​t​ ​f​i​n​i​s​h​ ​M​F​A​ ​p​r​o​c​e​s​s​.​ ​P​l​e​a​s​e​ ​t​r​y​ ​a​g​a​i​n​ ​o​r​ ​c​o​n​t​a​c​t​ ​a​d​m​i​n​i​s​t​r​a​t​o​r​. + */ + mfaFinishGeneric: string /** * C​o​u​l​d​ ​n​o​t​ ​f​i​n​d​ ​i​n​s​t​a​n​c​e​. */ @@ -3391,6 +3395,10 @@ export type TranslationFunctions = { * Could not start MFA process. Please try again or contact administrator. */ mfaStartGeneric: () => LocalizedString + /** + * Could not finish MFA process. Please try again or contact administrator. + */ + mfaFinishGeneric: () => LocalizedString /** * Could not find instance. */ diff --git a/src/pages/client/pages/ClientInstancePage/components/LocationsList/modals/MFAModal/MFAModal.tsx b/src/pages/client/pages/ClientInstancePage/components/LocationsList/modals/MFAModal/MFAModal.tsx index fe97339e..86cc148d 100644 --- a/src/pages/client/pages/ClientInstancePage/components/LocationsList/modals/MFAModal/MFAModal.tsx +++ b/src/pages/client/pages/ClientInstancePage/components/LocationsList/modals/MFAModal/MFAModal.tsx @@ -575,52 +575,56 @@ const MFACodeForm = ({ description, token, proxyUrl, resetState }: MFACodeForm) ); const finishMFA = async (code: string) => { - if (!location) return toaster.error(localLL.errors.mfaStartGeneric()); + if (!location) return toaster.error(localLL.errors.mfaFinishGeneric()); const data = { token, code: code }; - const response = await fetch(`${proxyUrl + CLIENT_MFA_ENDPOINT}/finish`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - CLIENT_VERSION_HEADER: platformInfo.client_version, - CLIENT_PLATFORM_HEADER: platformInfo.platform_info, - }, - body: JSON.stringify(data), - }); - - console.log('response: ', response); - - if (response.ok) { - closeModal(); - const data = (await response.json()) as MFAFinishResponse; - await connect({ - locationId: location?.id, - connectionType: location.connection_type, - presharedKey: data.preshared_key, + try { + const response = await fetch(`${proxyUrl + CLIENT_MFA_ENDPOINT}/finish`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + CLIENT_VERSION_HEADER: platformInfo.client_version, + CLIENT_PLATFORM_HEADER: platformInfo.platform_info, + }, + body: JSON.stringify(data), }); - } else { - const data = (await response.json()) as unknown as MFAError; - const { error: errorMessage } = data; - let message = ''; - - if (errorMessage === 'Unauthorized') { - message = localLL.errors.invalidCode(); - } else if ( - errorMessage === 'invalid token' || - errorMessage === 'login session not found' - ) { - console.error(data); - toaster.error(localLL.errors.tokenExpired()); - resetState(); + + if (response.ok) { + closeModal(); + const data = (await response.json()) as MFAFinishResponse; + await connect({ + locationId: location?.id, + connectionType: location.connection_type, + presharedKey: data.preshared_key, + }); + } else { + const data = (await response.json()) as unknown as MFAError; + const { error: errorMessage } = data; + let message = ''; + + if (errorMessage === 'Unauthorized') { + message = localLL.errors.invalidCode(); + } else if ( + errorMessage === 'invalid token' || + errorMessage === 'login session not found' + ) { + console.error(data); + toaster.error(localLL.errors.tokenExpired()); + resetState(); + error(JSON.stringify(data)); + return; + } else { + toaster.error(localLL.errors.mfaFinishGeneric()); + } + + setMFAError(message); error(JSON.stringify(data)); return; - } else { - toaster.error(localLL.errors.mfaStartGeneric()); } - - setMFAError(message); - error(JSON.stringify(data)); + } catch (rej) { + error(`Failed to execute proxy request: ${rej}`); + toaster.error(localLL.errors.mfaFinishGeneric()); return; } };