summaryrefslogtreecommitdiffhomepage
path: root/gui
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-09-03 08:09:30 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-09-03 08:09:30 -0300
commit9e440721700a7ab6a3d0d5c81c4d42949ea7108c (patch)
tree159c1ac066c679e3d9204c79b15e118426678e4f /gui
parenta23afed45caa953cb9765991a4692b66b3a39329 (diff)
parent13e272fe2c22a5b026aa4dc8cae80e9a68df4dc2 (diff)
downloadmullvadvpn-9e440721700a7ab6a3d0d5c81c4d42949ea7108c.tar.xz
mullvadvpn-9e440721700a7ab6a3d0d5c81c4d42949ea7108c.zip
Merge branch 'blocked-state'
Diffstat (limited to 'gui')
-rw-r--r--gui/packages/desktop/src/renderer/app.js49
-rw-r--r--gui/packages/desktop/src/renderer/components/Connect.js13
-rw-r--r--gui/packages/desktop/src/renderer/errors.js17
-rw-r--r--gui/packages/desktop/src/renderer/lib/daemon-rpc.js48
-rw-r--r--gui/packages/desktop/src/renderer/redux/connection/actions.js14
-rw-r--r--gui/packages/desktop/src/renderer/redux/connection/reducers.js13
6 files changed, 125 insertions, 29 deletions
diff --git a/gui/packages/desktop/src/renderer/app.js b/gui/packages/desktop/src/renderer/app.js
index e88d3d619c..b693a84544 100644
--- a/gui/packages/desktop/src/renderer/app.js
+++ b/gui/packages/desktop/src/renderer/app.js
@@ -402,10 +402,9 @@ export default class AppRenderer {
actions.settings.updateAutoConnect(autoConnect);
}
- async _fetchSecurityState() {
- const securityState = await this._daemonRpc.getState();
- const connectionState = this._tunnelStateToConnectionState(securityState);
- this._updateConnectionState(connectionState);
+ async _fetchTunnelState() {
+ const tunnelState = await this._daemonRpc.getState();
+ this._updateConnectionState(tunnelState);
}
async _fetchTunnelOptions() {
@@ -502,11 +501,9 @@ export default class AppRenderer {
}
if (newState) {
- const connectionState = this._tunnelStateToConnectionState(newState);
+ log.debug(`Got new state from daemon '${JSON.stringify(newState)}'`);
- log.debug(`Got new state from daemon '${newState}', translated to '${connectionState}'`);
-
- this._updateConnectionState(connectionState);
+ this._updateConnectionState(newState);
this._refreshStateOnChange();
}
});
@@ -514,7 +511,7 @@ export default class AppRenderer {
_fetchInitialState() {
return Promise.all([
- this._fetchSecurityState(),
+ this._fetchTunnelState(),
this.fetchRelaySettings(),
this._fetchRelayLocations(),
this._fetchAllowLan(),
@@ -530,6 +527,7 @@ export default class AppRenderer {
const iconTypes: { [ConnectionState]: TrayIconType } = {
connected: 'secured',
connecting: 'securing',
+ blocked: 'securing',
};
const type = iconTypes[connectionState] || 'unsecured';
@@ -545,28 +543,44 @@ export default class AppRenderer {
}
_tunnelStateToConnectionState(tunnelState: TunnelState): ConnectionState {
- if (tunnelState === 'disconnected' || tunnelState === 'disconnecting') {
- return 'disconnected';
- } else if (tunnelState === 'connected' || tunnelState === 'connecting') {
- return tunnelState;
+ switch (tunnelState.state) {
+ case 'disconnected':
+ // Fall through
+ case 'disconnecting':
+ return 'disconnected';
+ case 'connected':
+ return 'connected';
+ case 'connecting':
+ return 'connecting';
+ case 'blocked':
+ return 'blocked';
+ default:
+ throw new Error('Unknown tunnel state: ' + (tunnelState: empty));
}
- throw new Error('Unsupported state/target state combination: ' + JSON.stringify(tunnelState));
}
- _updateConnectionState(connectionState: ConnectionState) {
+ _updateConnectionState(tunnelState: TunnelState) {
const actions = this._reduxActions;
- switch (connectionState) {
+ switch (tunnelState.state) {
case 'connecting':
actions.connection.connecting();
break;
case 'connected':
actions.connection.connected();
break;
+ case 'disconnecting':
+ // Fall through
case 'disconnected':
actions.connection.disconnected();
break;
+ case 'blocked':
+ actions.connection.blocked(tunnelState.details);
+ break;
+ default:
+ log.error(`Unexpected TunnelState: ${(tunnelState: empty)}`);
}
+ const connectionState = this._tunnelStateToConnectionState(tunnelState);
this._updateTrayIcon(connectionState);
this._showNotification(connectionState);
}
@@ -582,6 +596,9 @@ export default class AppRenderer {
case 'disconnected':
this._notificationController.show('Unsecured');
break;
+ case 'blocked':
+ this._notificationController.show('Blocked all connections');
+ break;
default:
log.error(`Unexpected ConnectionState: ${(connectionState: empty)}`);
return;
diff --git a/gui/packages/desktop/src/renderer/components/Connect.js b/gui/packages/desktop/src/renderer/components/Connect.js
index d9c3768df6..bf08000ce5 100644
--- a/gui/packages/desktop/src/renderer/components/Connect.js
+++ b/gui/packages/desktop/src/renderer/components/Connect.js
@@ -10,7 +10,7 @@ import * as AppButton from './AppButton';
import Img from './Img';
import Map from './Map';
import styles from './ConnectStyles';
-import { NoCreditError, NoInternetError } from '../errors';
+import { BlockedError, NoCreditError, NoInternetError } from '../errors';
import WindowStateObserver from '../lib/window-state-observer';
import type { HeaderBarStyle } from './HeaderBar';
@@ -103,6 +103,11 @@ export default class Connect extends Component<Props, State> {
message = 'Your internet connection will be secured when you get back online';
}
+ if (error instanceof BlockedError) {
+ title = 'Blocked';
+ message = error.message;
+ }
+
return (
<View style={styles.connect}>
<View style={styles.status_icon}>
@@ -345,6 +350,7 @@ export default class Connect extends Component<Props, State> {
return 'error';
case 'connecting':
case 'connected':
+ case 'blocked':
return 'success';
default:
throw new Error(`Invalid ConnectionState: ${(status: empty)}`);
@@ -392,6 +398,11 @@ export default class Connect extends Component<Props, State> {
return new NoCreditError();
}
+ // Tunnel is blocked due to an error?
+ if (this.props.connection.status === 'blocked') {
+ return new BlockedError(this.props.connection.blockReason);
+ }
+
return null;
}
}
diff --git a/gui/packages/desktop/src/renderer/errors.js b/gui/packages/desktop/src/renderer/errors.js
index 7464851a1f..ddf0c239bb 100644
--- a/gui/packages/desktop/src/renderer/errors.js
+++ b/gui/packages/desktop/src/renderer/errors.js
@@ -1,5 +1,22 @@
// @flow
+import type { BlockReason } from './lib/daemon-rpc';
+
+export class BlockedError extends Error {
+ constructor(reason: BlockReason) {
+ switch (reason) {
+ case 'set_security_policy_error':
+ super('Failed to apply security policy');
+ break;
+ case 'start_tunnel_error':
+ super('Failed to start tunnel connection');
+ break;
+ default:
+ super(`Unknown error: ${(reason: empty)}`);
+ }
+ }
+}
+
export class NoCreditError extends Error {
constructor() {
super("Account doesn't have enough credit available for connection");
diff --git a/gui/packages/desktop/src/renderer/lib/daemon-rpc.js b/gui/packages/desktop/src/renderer/lib/daemon-rpc.js
index e590534d69..ae2e501268 100644
--- a/gui/packages/desktop/src/renderer/lib/daemon-rpc.js
+++ b/gui/packages/desktop/src/renderer/lib/daemon-rpc.js
@@ -41,7 +41,29 @@ const LocationSchema = object({
mullvad_exit_ip: boolean,
});
-export type TunnelState = 'disconnected' | 'connecting' | 'connected' | 'disconnecting';
+export type BlockReason = 'set_security_policy_error' | 'start_tunnel_error';
+export type DisconnectedState = {
+ state: 'disconnected',
+};
+export type ConnectingState = {
+ state: 'connecting',
+};
+export type ConnectedState = {
+ state: 'connected',
+};
+export type DisconnectingState = {
+ state: 'disconnecting',
+};
+export type BlockedState = {
+ state: 'blocked',
+ details: BlockReason,
+};
+export type TunnelState =
+ | DisconnectedState
+ | ConnectingState
+ | ConnectedState
+ | DisconnectingState
+ | BlockedState;
export type RelayProtocol = 'tcp' | 'udp';
export type RelayLocation = {| city: [string, string] |} | {| country: string |};
@@ -196,13 +218,23 @@ const AccountDataSchema = object({
expiry: string,
});
-const allTunnelStates: Array<TunnelState> = [
- 'disconnected',
- 'connecting',
- 'connected',
- 'disconnecting',
-];
-const TunnelStateSchema = enumeration(...allTunnelStates);
+const allBlockReasons: Array<BlockReason> = ['set_security_policy_error', 'start_tunnel_error'];
+const BlockedStateSchema = object({
+ state: enumeration('blocked'),
+ details: enumeration(...allBlockReasons),
+});
+const ConnectedStateSchema = object({ state: enumeration('connected') });
+const ConnectingStateSchema = object({ state: enumeration('connecting') });
+const DisconnectedStateSchema = object({ state: enumeration('disconnected') });
+const DisconnectingStateSchema = object({ state: enumeration('disconnecting') });
+
+const TunnelStateSchema = oneOf(
+ BlockedStateSchema,
+ ConnectedStateSchema,
+ ConnectingStateSchema,
+ DisconnectedStateSchema,
+ DisconnectingStateSchema,
+);
export type AppVersionInfo = {
currentIsSupported: boolean,
diff --git a/gui/packages/desktop/src/renderer/redux/connection/actions.js b/gui/packages/desktop/src/renderer/redux/connection/actions.js
index a4c5c68890..052d206986 100644
--- a/gui/packages/desktop/src/renderer/redux/connection/actions.js
+++ b/gui/packages/desktop/src/renderer/redux/connection/actions.js
@@ -14,6 +14,11 @@ type DisconnectedAction = {
type: 'DISCONNECTED',
};
+type BlockedAction = {
+ type: 'BLOCKED',
+ reason: string,
+};
+
type NewLocationAction = {
type: 'NEW_LOCATION',
newLocation: {
@@ -39,6 +44,7 @@ export type ConnectionAction =
| ConnectingAction
| ConnectedAction
| DisconnectedAction
+ | BlockedAction
| OnlineAction
| OfflineAction;
@@ -60,6 +66,13 @@ function disconnected(): DisconnectedAction {
};
}
+function blocked(reason: string): BlockedAction {
+ return {
+ type: 'BLOCKED',
+ reason,
+ };
+}
+
function newLocation(newLoc: $PropertyType<NewLocationAction, 'newLocation'>): NewLocationAction {
return {
type: 'NEW_LOCATION',
@@ -84,6 +97,7 @@ export default {
connecting,
connected,
disconnected,
+ blocked,
online,
offline,
};
diff --git a/gui/packages/desktop/src/renderer/redux/connection/reducers.js b/gui/packages/desktop/src/renderer/redux/connection/reducers.js
index c75d0f2a8f..d425dec438 100644
--- a/gui/packages/desktop/src/renderer/redux/connection/reducers.js
+++ b/gui/packages/desktop/src/renderer/redux/connection/reducers.js
@@ -3,7 +3,7 @@
import type { ReduxAction } from '../store';
import type { Ip } from '../../lib/daemon-rpc';
-export type ConnectionState = 'disconnected' | 'connecting' | 'connected';
+export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'blocked';
export type ConnectionReduxState = {
status: ConnectionState,
isOnline: boolean,
@@ -12,6 +12,7 @@ export type ConnectionReduxState = {
longitude: ?number,
country: ?string,
city: ?string,
+ blockReason: ?string,
};
const initialState: ConnectionReduxState = {
@@ -22,6 +23,7 @@ const initialState: ConnectionReduxState = {
longitude: null,
country: null,
city: null,
+ blockReason: null,
};
export default function(
@@ -33,13 +35,16 @@ export default function(
return { ...state, ...action.newLocation };
case 'CONNECTING':
- return { ...state, ...{ status: 'connecting' } };
+ return { ...state, ...{ status: 'connecting', blockReason: null } };
case 'CONNECTED':
- return { ...state, ...{ status: 'connected' } };
+ return { ...state, ...{ status: 'connected', blockReason: null } };
case 'DISCONNECTED':
- return { ...state, ...{ status: 'disconnected' } };
+ return { ...state, ...{ status: 'disconnected', blockReason: null } };
+
+ case 'BLOCKED':
+ return { ...state, ...{ status: 'blocked', blockReason: action.reason } };
case 'ONLINE':
return { ...state, ...{ isOnline: true } };