From fa1961d32c9d2775c5deed754fcf90ed57890e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ciarcin=CC=81ski?= Date: Thu, 21 Aug 2025 10:11:21 +0200 Subject: [PATCH 1/3] Fix MFA connection from tray menu --- src-tauri/src/events.rs | 2 ++ src-tauri/src/tray.rs | 15 +++------------ src/pages/client/ClientPage.tsx | 12 ++++++++++-- .../LocationCardConnectButton.tsx | 18 +----------------- src/pages/client/types.ts | 1 + 5 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src-tauri/src/events.rs b/src-tauri/src/events.rs index de510f76..58fdea5f 100644 --- a/src-tauri/src/events.rs +++ b/src-tauri/src/events.rs @@ -17,6 +17,7 @@ pub enum EventKey { DeadConnectionReconnected, ApplicationConfigChanged, AddInstance, + MfaTrigger, } impl From for &'static str { @@ -32,6 +33,7 @@ impl From for &'static str { EventKey::DeadConnectionReconnected => "dead-connection-reconnected", EventKey::ApplicationConfigChanged => "application-config-changed", EventKey::AddInstance => "add-instance", + EventKey::MfaTrigger => "mfa-trigger", } } } diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index a5b65ba8..fed24e03 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -12,6 +12,7 @@ use crate::{ commands::{all_instances, all_locations, connect, disconnect}, database::{models::location::Location, DB_POOL}, error::Error, + events::EventKey, ConnectionType, }; @@ -225,11 +226,6 @@ pub async fn configure_tray_icon(app: &AppHandle, theme: AppTrayTheme) -> Result } } -#[derive(Clone, serde::Serialize)] -struct MfaPayload<'a> { - message: &'a str, -} - async fn handle_location_tray_menu(id: String, handle: &AppHandle) { match id.parse::() { Ok(location_id) => { @@ -244,18 +240,13 @@ async fn handle_location_tray_menu(id: String, handle: &AppHandle) { disconnect(location_id, ConnectionType::Location, handle.clone()).await; } else { info!("Connect location with ID {id}"); - // check is mfa enabled and trigger modal on frontend + // Check if MFA is enabled. If so, trigger modal on frontend. if location.mfa_enabled() { info!( "MFA enabled for location with ID {:?}, trigger MFA modal", location.id ); - let _ = handle.emit( - "mfa-trigger", - MfaPayload { - message: "Trigger MFA event", - }, - ); + let _ = handle.emit(EventKey::MfaTrigger.into(), &location); } else if let Err(err) = connect(location_id, ConnectionType::Location, None, handle.clone()) .await diff --git a/src/pages/client/ClientPage.tsx b/src/pages/client/ClientPage.tsx index 0f43da22..b59015df 100644 --- a/src/pages/client/ClientPage.tsx +++ b/src/pages/client/ClientPage.tsx @@ -20,8 +20,10 @@ import { type DeadConDroppedPayload, type DeadConReconnectedPayload, type AddInstancePayload, + type CommonWireguardFields, TauriEventKey, } from './types'; +import { useMFAModal } from './pages/ClientInstancePage/components/LocationsList/modals/MFAModal/useMFAModal'; const { getInstances, getTunnels, getAppConfig } = clientApi; @@ -40,6 +42,7 @@ export const ClientPage = () => { const location = useLocation(); const toaster = useToaster(); const openDeadConDroppedModal = useDeadConDroppedModal((s) => s.open); + const openMFAModal = useMFAModal((state) => state.open); const { LL } = useI18nContext(); const { data: instances } = useQuery({ @@ -136,11 +139,15 @@ export const ClientPage = () => { }, ); - const doEnrollment = listen(TauriEventKey.ADD_INSTANCE, (data) => { + const addInstance = listen(TauriEventKey.ADD_INSTANCE, (data) => { useClientStore.setState({ instanceConfig: data.payload }); navigate(routes.client.addInstance, { replace: true }); }); + const mfaTrigger = listen(TauriEventKey.MFA_TRIGGER, (data) => { + openMFAModal(data.payload); + }); + return () => { deadConnectionDropped.then((cleanup) => cleanup()); deadConnectionReconnected.then((cleanup) => cleanup()); @@ -149,7 +156,8 @@ export const ClientPage = () => { instanceUpdate.then((cleanup) => cleanup()); locationUpdate.then((cleanup) => cleanup()); appConfigChanged.then((cleanup) => cleanup()); - doEnrollment.then((cleanup) => cleanup()); + addInstance.then((cleanup) => cleanup()); + mfaTrigger.then((cleanup) => cleanup()); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardConnectButton/LocationCardConnectButton.tsx b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardConnectButton/LocationCardConnectButton.tsx index 5d713e1e..404f8680 100644 --- a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardConnectButton/LocationCardConnectButton.tsx +++ b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardConnectButton/LocationCardConnectButton.tsx @@ -1,9 +1,8 @@ import './style.scss'; -import { listen } from '@tauri-apps/api/event'; import { error } from '@tauri-apps/plugin-log'; import classNames from 'classnames'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useI18nContext } from '../../../../../../../../i18n/i18n-react'; import SvgIconCheckmarkSmall from '../../../../../../../../shared/components/svg/IconCheckmarkSmall'; @@ -24,10 +23,6 @@ type Props = { location?: CommonWireguardFields; }; -type Payload = { - location?: CommonWireguardFields; -}; - export const LocationCardConnectButton = ({ location }: Props) => { const toaster = useToaster(); const [isLoading, setIsLoading] = useState(false); @@ -76,17 +71,6 @@ export const LocationCardConnectButton = ({ location }: Props) => { } }; - useEffect(() => { - async function listenMFAEvent() { - await listen('mfa-trigger', () => { - if (location) { - openMFAModal(location); - } - }); - } - listenMFAEvent(); - }, [openMFAModal, location]); - return (