diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-08-04 10:53:53 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-08-04 10:53:53 +0200 |
| commit | 61d14531b61cc78d951add7b3cdfd3623e45410b (patch) | |
| tree | 50fce79818d21f8ad497b64243a14a4c84b2a347 /gui | |
| parent | abf7bb0dd3021daef52593515a98b0ebb189d9a0 (diff) | |
| parent | 3496937abc7e6347e057a39ec6a40f49dd71e6a2 (diff) | |
| download | mullvadvpn-61d14531b61cc78d951add7b3cdfd3623e45410b.tar.xz mullvadvpn-61d14531b61cc78d951add7b3cdfd3623e45410b.zip | |
Merge branch 'win-firewall-errors'
Diffstat (limited to 'gui')
| -rw-r--r-- | gui/src/main/daemon-rpc.ts | 25 | ||||
| -rw-r--r-- | gui/src/main/index.ts | 2 | ||||
| -rw-r--r-- | gui/src/renderer/app.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/components/Connect.tsx | 4 | ||||
| -rw-r--r-- | gui/src/renderer/components/TunnelControl.tsx | 2 | ||||
| -rw-r--r-- | gui/src/shared/daemon-rpc-types.ts | 14 | ||||
| -rw-r--r-- | gui/src/shared/notifications/error.ts | 130 |
7 files changed, 122 insertions, 57 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts index 656efd760b..6071ce515f 100644 --- a/gui/src/main/daemon-rpc.ts +++ b/gui/src/main/daemon-rpc.ts @@ -259,12 +259,21 @@ const tunnelStateSchema = oneOf( object({ state: enumeration('error'), details: object({ - is_blocking: boolean, + block_failure: maybe( + object({ + reason: enumeration('generic', 'locked'), + details: maybe( + object({ + name: string, + pid: number, + }), + ), + }), + ), cause: oneOf( object({ reason: enumeration( 'ipv6_unavailable', - 'set_firewall_policy_error', 'set_dns_error', 'start_tunnel_error', 'is_offline', @@ -272,6 +281,18 @@ const tunnelStateSchema = oneOf( ), }), object({ + reason: enumeration('set_firewall_policy_error'), + details: object({ + reason: enumeration('generic', 'locked'), + details: maybe( + object({ + name: string, + pid: number, + }), + ), + }), + }), + object({ reason: enumeration('auth_failed'), details: maybe(string), }), diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts index 18dfc67d29..f375de7eca 100644 --- a/gui/src/main/index.ts +++ b/gui/src/main/index.ts @@ -863,7 +863,7 @@ class ApplicationMain { return 'securing'; case 'error': - if (tunnelState.details.isBlocking) { + if (!tunnelState.details.blockFailure) { return 'securing'; } else { return 'unsecured'; diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index 0dc076378a..c09ca39049 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -634,7 +634,7 @@ export default class AppRenderer { break; case 'error': - actions.updateBlockState(tunnelState.details.isBlocking); + actions.updateBlockState(!tunnelState.details.blockFailure); break; } } diff --git a/gui/src/renderer/components/Connect.tsx b/gui/src/renderer/components/Connect.tsx index 0db4a40141..184465bd7d 100644 --- a/gui/src/renderer/components/Connect.tsx +++ b/gui/src/renderer/components/Connect.tsx @@ -169,7 +169,7 @@ export default class Connect extends React.Component<IProps, IState> { case 'connected': return HeaderBarStyle.success; case 'error': - return status.details.isBlocking ? HeaderBarStyle.success : HeaderBarStyle.error; + return !status.details.blockFailure ? HeaderBarStyle.success : HeaderBarStyle.error; case 'disconnecting': switch (status.details) { case 'block': @@ -223,7 +223,7 @@ export default class Connect extends React.Component<IProps, IState> { case 'connected': return MarkerStyle.secure; case 'error': - return status.details.isBlocking ? MarkerStyle.secure : MarkerStyle.unsecure; + return !status.details.blockFailure ? MarkerStyle.secure : MarkerStyle.unsecure; case 'disconnected': return MarkerStyle.unsecure; case 'disconnecting': diff --git a/gui/src/renderer/components/TunnelControl.tsx b/gui/src/renderer/components/TunnelControl.tsx index 04236750ee..611c24d78e 100644 --- a/gui/src/renderer/components/TunnelControl.tsx +++ b/gui/src/renderer/components/TunnelControl.tsx @@ -176,7 +176,7 @@ export default class TunnelControl extends React.Component<ITunnelControlProps> case 'error': if ( this.props.tunnelState.state === 'error' && - !this.props.tunnelState.details.isBlocking + this.props.tunnelState.details.blockFailure ) { return ( <Wrapper> diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts index bec0275e9b..1f1779a4b0 100644 --- a/gui/src/shared/daemon-rpc-types.ts +++ b/gui/src/shared/daemon-rpc-types.ts @@ -15,6 +15,16 @@ export interface ILocation { bridgeHostname?: string; } +export type FirewallPolicyError = + | { reason: 'generic' } + | { + reason: 'locked'; + details?: { + name: string; + pid: number; + }; + }; + export type TunnelParameterError = | 'no_matching_relay' | 'no_matching_bridge_relay' @@ -25,12 +35,12 @@ export type ErrorStateCause = | { reason: | 'ipv6_unavailable' - | 'set_firewall_policy_error' | 'set_dns_error' | 'start_tunnel_error' | 'is_offline' | 'tap_adapter_problem'; } + | { reason: 'set_firewall_policy_error'; details: FirewallPolicyError } | { reason: 'tunnel_parameter_error'; details: TunnelParameterError } | { reason: 'auth_failed'; details?: string }; @@ -102,7 +112,7 @@ export type TunnelState = | { state: 'error'; details: IErrorState }; export interface IErrorState { - isBlocking: boolean; + blockFailure?: FirewallPolicyError; cause: ErrorStateCause; } diff --git a/gui/src/shared/notifications/error.ts b/gui/src/shared/notifications/error.ts index 1a8499739e..7b438edb54 100644 --- a/gui/src/shared/notifications/error.ts +++ b/gui/src/shared/notifications/error.ts @@ -1,7 +1,13 @@ import { sprintf } from 'sprintf-js'; import { hasExpired } from '../account-expiry'; import { AuthFailureKind, parseAuthFailure } from '../auth-failure'; -import { IErrorState, TunnelState, TunnelParameterError } from '../daemon-rpc-types'; +import { + IErrorState, + TunnelState, + TunnelParameterError, + ErrorStateCause, + FirewallPolicyError, +} from '../daemon-rpc-types'; import { messages } from '../gettext'; import { InAppNotification, @@ -27,7 +33,7 @@ export class ErrorNotificationProvider this.context.tunnelState, this.context.accountExpiry, ), - critical: !this.context.tunnelState.details.isBlocking, + critical: !!this.context.tunnelState.details.blockFailure, } : undefined; } @@ -36,7 +42,7 @@ export class ErrorNotificationProvider return this.context.tunnelState.state === 'error' ? { indicator: 'error', - title: this.context.tunnelState.details.isBlocking + title: !this.context.tunnelState.details.blockFailure ? messages.pgettext('in-app-notifications', 'BLOCKING INTERNET') : messages.pgettext('in-app-notifications', 'YOU MIGHT BE LEAKING NETWORK TRAFFIC'), subtitle: getInAppNotificationSubtitle(this.context.tunnelState), @@ -49,7 +55,7 @@ function getSystemNotificationMessage( tunnelState: { state: 'error'; details: IErrorState }, accountExpiry?: string, ) { - if (!tunnelState.details.isBlocking) { + if (tunnelState.details.blockFailure) { return messages.pgettext('notifications', 'Critical error (your attention is required)'); } else if ( (tunnelState.details.cause.reason === 'auth_failed' && @@ -75,57 +81,85 @@ function getSystemNotificationMessage( } function getInAppNotificationSubtitle(tunnelState: { state: 'error'; details: IErrorState }) { - if (!tunnelState.details.isBlocking) { - return messages.pgettext( + let blockFailureMessage = null; + if (tunnelState.details.blockFailure) { + const extraMessage = getPolicyMessage(tunnelState.details.blockFailure); + blockFailureMessage = `${messages.pgettext( 'in-app-notifications', - 'Failed to block all network traffic. Please troubleshoot or report the problem to us.', - ); - } else { - const blockReason = tunnelState.details.cause; - switch (blockReason.reason) { - case 'auth_failed': - return parseAuthFailure(blockReason.details).message; - case 'ipv6_unavailable': - return messages.pgettext( - 'in-app-notifications', - 'Could not configure IPv6, please enable it on your system or disable it in the app', - ); - case 'set_firewall_policy_error': { - let extraMessage = null; - switch (process.platform) { - case 'linux': - extraMessage = messages.pgettext('in-app-notifications', 'Your kernel may be outdated'); - break; - case 'win32': + 'Failed to block all network traffic', + )}${extraMessage ? '. ' + extraMessage : ''}`; + } + + const blockMessage = getBlockMessage(tunnelState.details.cause); + return blockFailureMessage + ? `${blockFailureMessage}. ${messages.pgettext( + 'in-app-notifications', + 'Original block reason', + )}: ${blockMessage}` + : blockMessage; +} + +function getBlockMessage(blockReason: ErrorStateCause): string { + switch (blockReason.reason) { + case 'auth_failed': + return parseAuthFailure(blockReason.details).message; + case 'ipv6_unavailable': + return messages.pgettext( + 'in-app-notifications', + 'Could not configure IPv6, please enable it on your system or disable it in the app', + ); + case 'set_firewall_policy_error': { + const extraMessage = getPolicyMessage(blockReason.details); + return `${messages.pgettext( + 'in-app-notifications', + 'Failed to apply firewall rules. The device might currently be unsecured', + )}${extraMessage ? '. ' + extraMessage : ''}`; + } + case 'set_dns_error': + return messages.pgettext('in-app-notifications', 'Failed to set system DNS server'); + case 'start_tunnel_error': + return messages.pgettext('in-app-notifications', 'Failed to start tunnel connection'); + case 'tunnel_parameter_error': + return getTunnelParameterMessage(blockReason.details); + case 'is_offline': + return messages.pgettext( + 'in-app-notifications', + 'This device is offline, no tunnels can be established', + ); + case 'tap_adapter_problem': + return messages.pgettext( + 'in-app-notifications', + "Unable to detect a working TAP adapter on this device. If you've disabled it, enable it again. Otherwise, please reinstall the app", + ); + } +} + +function getPolicyMessage(err: FirewallPolicyError): string | null { + let extraMessage = null; + switch (process.platform) { + case 'linux': + extraMessage = messages.pgettext('in-app-notifications', 'Your kernel may be outdated'); + break; + case 'win32': + switch (err.reason) { + case 'locked': + if (err.details) { + // TODO: Check if this message is ok + extraMessage = `${messages.pgettext( + 'in-app-notifications', + 'An application prevented the policy from being set', + )}: ${err.details.name}`; + } else { extraMessage = messages.pgettext( 'in-app-notifications', 'This might be caused by third party security software', ); - break; - } - return `${messages.pgettext( - 'in-app-notifications', - 'Failed to apply firewall rules. The device might currently be unsecured', - )}${extraMessage ? '. ' + extraMessage : ''}`; + } + break; } - case 'set_dns_error': - return messages.pgettext('in-app-notifications', 'Failed to set system DNS server'); - case 'start_tunnel_error': - return messages.pgettext('in-app-notifications', 'Failed to start tunnel connection'); - case 'tunnel_parameter_error': - return getTunnelParameterMessage(blockReason.details); - case 'is_offline': - return messages.pgettext( - 'in-app-notifications', - 'This device is offline, no tunnels can be established', - ); - case 'tap_adapter_problem': - return messages.pgettext( - 'in-app-notifications', - "Unable to detect a working TAP adapter on this device. If you've disabled it, enable it again. Otherwise, please reinstall the app", - ); - } + break; } + return extraMessage; } function getTunnelParameterMessage(err: TunnelParameterError): string { |
