diff options
3 files changed, 64 insertions, 11 deletions
diff --git a/desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx b/desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx index 9a7ad3c928..17ccab76a3 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/components/NotificationArea.tsx @@ -51,9 +51,9 @@ export default function NotificationArea(props: IProps) { const account = useSelector((state: IReduxState) => state.account); const locale = useSelector((state: IReduxState) => state.userInterface.locale); const tunnelState = useSelector((state: IReduxState) => state.connection.status); + const connection = useSelector((state: IReduxState) => state.connection); const version = useSelector((state: IReduxState) => state.version); const tunnelProtocol = useTunnelProtocol(); - const reduxConnection = useSelector((state) => state.connection); const fullRelayList = useSelector((state) => state.settings.relayLocations); const blockWhenDisconnected = useSelector( @@ -95,8 +95,8 @@ export default function NotificationArea(props: IProps) { hasExcludedApps, }), new NoOpenVpnServerAvailableNotificationProvider({ + connection, tunnelProtocol, - tunnelState: reduxConnection.status, relayLocations: fullRelayList, }), new ErrorNotificationProvider({ diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/notifications/no-open-vpn-server-available.ts b/desktop/packages/mullvad-vpn/src/renderer/lib/notifications/no-open-vpn-server-available.ts index d84466b0ba..566a61c80b 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/lib/notifications/no-open-vpn-server-available.ts +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/notifications/no-open-vpn-server-available.ts @@ -5,7 +5,6 @@ import { ErrorStateCause, TunnelParameterError, TunnelProtocol, - TunnelState, } from '../../../shared/daemon-rpc-types'; import { messages } from '../../../shared/gettext'; import { @@ -13,12 +12,16 @@ import { InAppNotificationProvider, InAppNotificationSubtitle, } from '../../../shared/notifications'; -import { IRelayLocationCountryRedux } from '../../redux/settings/reducers'; +import { IConnectionReduxState } from '../../redux/connection/reducers'; +import { + IRelayLocationCountryRedux, + IRelayLocationRelayRedux, +} from '../../redux/settings/reducers'; import { RoutePath } from '../routes'; interface NoOpenVpnServerAvailableNotificationContext { + connection: IConnectionReduxState; tunnelProtocol: TunnelProtocol; - tunnelState: TunnelState; relayLocations: IRelayLocationCountryRedux[]; } @@ -26,12 +29,20 @@ export class NoOpenVpnServerAvailableNotificationProvider implements InAppNotifi public constructor(private context: NoOpenVpnServerAvailableNotificationContext) {} public mayDisplay = () => { - const { tunnelState, tunnelProtocol } = this.context; + const { connection, tunnelProtocol } = this.context; + + const hasNoEnabledOpenVpnRelays = !this.anyOpenVpnLocationsEnabled(); + const isSelectedRelayOpenVpn = this.isSelectedRelayOpenVpn(); + const isTunnelProtocolOpenVpn = tunnelProtocol === 'openvpn'; + const hasNoMatchingRelay = + connection.status.state === 'error' && + connection.status.details.cause === ErrorStateCause.tunnelParameterError && + connection.status.details.parameterError === TunnelParameterError.noMatchingRelay; + return ( - tunnelProtocol === 'openvpn' && - tunnelState.state === 'error' && - tunnelState.details.cause === ErrorStateCause.tunnelParameterError && - tunnelState.details.parameterError === TunnelParameterError.noMatchingRelay + isTunnelProtocolOpenVpn && + hasNoMatchingRelay && + (isSelectedRelayOpenVpn || hasNoEnabledOpenVpnRelays) ); }; @@ -39,6 +50,7 @@ export class NoOpenVpnServerAvailableNotificationProvider implements InAppNotifi let title: string = ''; const subtitle: InAppNotificationSubtitle[] = []; const capitalizedOpenVpn = strings.openvpn.toUpperCase(); + if (this.anyOpenVpnLocationsEnabled()) { title = sprintf( // TRANSLATORS: Notification title when there are no openVPN servers @@ -111,6 +123,47 @@ export class NoOpenVpnServerAvailableNotificationProvider implements InAppNotifi }; } + private isSelectedRelayOpenVpn() { + const selectedRelay = this.getSelectedRelay(); + + if (selectedRelay) { + // NOTE: Even though 'bridge' is not specifically OpenVPN + // it is only used together with OpenVPN and as such + // we want to target it as well. + return selectedRelay.endpointType === 'openvpn' || selectedRelay.endpointType === 'bridge'; + } + + return false; + } + + private getSelectedRelay() { + const selectedRelay = this.context.relayLocations.reduce<IRelayLocationRelayRedux | undefined>( + (selectedRelay, location) => { + const isSelectedRelayCountry = location.name === this.context.connection.country; + if (isSelectedRelayCountry) { + const relayCity = location.cities.find( + (city) => city.name === this.context.connection.city, + ); + + if (relayCity) { + const relay = relayCity.relays.find( + (relay) => relay.hostname === this.context.connection.hostname, + ); + + if (relay) { + return relay; + } + } + } + + return selectedRelay; + }, + undefined, + ); + + return selectedRelay; + } + private anyOpenVpnLocationsEnabled() { return this.context.relayLocations.some((location) => { return location.cities.some((city) => { diff --git a/desktop/packages/mullvad-vpn/src/shared/constants/urls.ts b/desktop/packages/mullvad-vpn/src/shared/constants/urls.ts index f9a77a92b0..435200f7aa 100644 --- a/desktop/packages/mullvad-vpn/src/shared/constants/urls.ts +++ b/desktop/packages/mullvad-vpn/src/shared/constants/urls.ts @@ -5,7 +5,7 @@ export const urls = { faq: 'https://mullvad.net/help/tag/mullvad-app/', privacyGuide: 'https://mullvad.net/help/first-steps-towards-online-privacy/', download: 'https://mullvad.net/download/vpn/', - removingOpenVpnBlog: 'https://mullvad.net/en/blog/removing-openvpn-15th-january-2026', + removingOpenVpnBlog: 'https://mullvad.net/blog/removing-openvpn-15th-january-2026', } as const; type BaseUrl = (typeof urls)[keyof typeof urls]; |
