diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2018-09-13 12:51:32 +0300 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-09-13 12:51:32 +0300 |
| commit | 32be6c60e8a742214c3f092b31721b181902a73f (patch) | |
| tree | 9096afa3473b558426bd1409edef3d33ad9e8f55 | |
| parent | ae9a73f4c9a9f66b26f384061891ee451dae52fe (diff) | |
| parent | 4f304822baa38caa5b8f9d07b58d4183dd9f93ea (diff) | |
| download | mullvadvpn-32be6c60e8a742214c3f092b31721b181902a73f.tar.xz mullvadvpn-32be6c60e8a742214c3f092b31721b181902a73f.zip | |
Merge branch 'new-settings-rpc'
16 files changed, 448 insertions, 416 deletions
diff --git a/gui/packages/desktop/src/renderer/app.js b/gui/packages/desktop/src/renderer/app.js index 66154bcc9d..6b310613da 100644 --- a/gui/packages/desktop/src/renderer/app.js +++ b/gui/packages/desktop/src/renderer/app.js @@ -14,10 +14,9 @@ import { createMemoryHistory } from 'history'; import makeRoutes from './routes'; import ReconnectionBackoff from './lib/reconnection-backoff'; -import { DaemonRpc, ConnectionObserver, SubscriptionListener } from './lib/daemon-rpc'; +import { DaemonRpc, ConnectionObserver } from './lib/daemon-rpc'; import NotificationController from './lib/notification-controller'; import setShutdownHandler from './lib/shutdown-handler'; -import { NoAccountError } from './errors'; import configureStore from './redux/store'; import accountActions from './redux/account/actions'; @@ -26,11 +25,16 @@ import settingsActions from './redux/settings/actions'; import versionActions from './redux/version/actions'; import windowActions from './redux/window/actions'; +import SettingsProxy from './lib/subscription-proxy/settings-proxy'; +import TunnelStateProxy from './lib/subscription-proxy/tunnel-state-proxy'; + import type { WindowShapeParameters } from '../main/window-controller'; import type { AccountToken, + Settings, TunnelStateTransition, RelaySettingsUpdate, + RelaySettings, TunnelState, DaemonRpcProtocol, AccountData, @@ -56,9 +60,13 @@ export default class AppRenderer { _accountDataCache = new AccountDataCache((accountToken) => { return this._daemonRpc.getAccountData(accountToken); }); + _tunnelStateProxy = new TunnelStateProxy(this._daemonRpc, (tunnelState) => { + this._setTunnelState(tunnelState); + }); + _settingsProxy = new SettingsProxy(this._daemonRpc, (settings) => { + this._setSettings(settings); + }); _connectedToDaemon = false; - _accountToken: ?AccountToken; - _tunnelState: ?TunnelStateTransition; constructor() { const store = configureStore(null, this._memoryHistory); @@ -129,9 +137,6 @@ export default class AppRenderer { const accountData = await this._daemonRpc.getAccountData(accountToken); await this._daemonRpc.setAccount(accountToken); - // reset the account token with the one that we just sent to daemon - this._accountToken = accountToken; - actions.account.updateAccountExpiry(accountData.expiry); actions.account.loginSuccessful(); @@ -156,64 +161,12 @@ export default class AppRenderer { } } - async _restoreSession() { - const actions = this._reduxActions; - const history = this._memoryHistory; - - log.debug('Restoring session'); - - const accountToken = await this._daemonRpc.getAccount(); - - // save the account token received after connecting to daemon - this._accountToken = accountToken; - - if (accountToken) { - log.debug(`Got account token: ${accountToken}`); - actions.account.updateAccountToken(accountToken); - actions.account.loginSuccessful(); - - // take user to main view if user is still at launch screen `/` - if (history.location.pathname === '/') { - actions.history.replace('/connect'); - } else { - // TODO: Reinvent the navigation back in history to make sure that user does not end up on - // the restricted screen due to changes in daemon's state. - for (const entry of history.entries) { - if (entry.pathname === '/') { - entry.pathname = '/connect'; - } - } - } - } else { - log.debug('No account set, showing login view.'); - - // show window when account is not set - ipcRenderer.send('show-window'); - - // take user to `/login` screen if user is at launch screen `/` - if (history.location.pathname === '/') { - actions.history.replace('/login'); - } else { - // TODO: Reinvent the navigation back in history to make sure that user does not end up on - // the restricted screen due to changes in daemon's state. - for (const entry of history.entries) { - if (!entry.pathname.startsWith('/settings')) { - entry.pathname = '/login'; - } - } - } - } - } - async logout() { const actions = this._reduxActions; try { await this._daemonRpc.setAccount(null); - // reset the account token after log out - this._accountToken = null; - await this._fetchAccountHistory(); actions.account.loggedOut(); @@ -229,11 +182,10 @@ export default class AppRenderer { async connectTunnel() { const actions = this._reduxActions; + const tunnelState = await this._tunnelStateProxy.fetch(); + // connect only if tunnel is disconnected or blocked. - if ( - this._tunnelState && - (this._tunnelState.state === 'disconnected' || this._tunnelState.state === 'blocked') - ) { + if (tunnelState.state === 'disconnected' || tunnelState.state === 'blocked') { // switch to connecting state immediately to prevent a lag that may be caused by RPC // communication delay actions.connection.connecting(); @@ -250,11 +202,8 @@ export default class AppRenderer { return this._daemonRpc.updateRelaySettings(relaySettings); } - async fetchRelaySettings() { + _setRelaySettings(relaySettings: RelaySettings) { const actions = this._reduxActions; - const relaySettings = await this._daemonRpc.getRelaySettings(); - - log.debug('Got relay settings from daemon', JSON.stringify(relaySettings)); if (relaySettings.normal) { const payload = {}; @@ -280,17 +229,17 @@ export default class AppRenderer { actions.settings.updateRelay({ normal: payload, }); - } else if (relaySettings.custom_tunnel_endpoint) { - const custom_tunnel_endpoint = relaySettings.custom_tunnel_endpoint; + } else if (relaySettings.customTunnelEndpoint) { + const customTunnelEndpoint = relaySettings.customTunnelEndpoint; const { host, tunnel: { openvpn: { port, protocol }, }, - } = custom_tunnel_endpoint; + } = customTunnelEndpoint; actions.settings.updateRelay({ - custom_tunnel_endpoint: { + customTunnelEndpoint: { host, port, protocol, @@ -301,18 +250,16 @@ export default class AppRenderer { async updateAccountExpiry() { const actions = this._reduxActions; + const settings = await this._settingsProxy.fetch(); const accountDataCache = this._accountDataCache; - try { - const accountToken = this._accountToken; - if (accountToken) { - const accountData = await accountDataCache.fetch(accountToken); + if (settings && settings.accountToken) { + try { + const accountData = await accountDataCache.fetch(settings.accountToken); actions.account.updateAccountExpiry(accountData.expiry); - } else { - throw new NoAccountError(); + } catch (error) { + log.error(`Failed to update account expiry: ${error.message}`); } - } catch (e) { - log.error(`Failed to update account expiry: ${e.message}`); } } @@ -387,32 +334,6 @@ export default class AppRenderer { actions.settings.updateAutoConnect(autoConnect); } - async _fetchAllowLan() { - const actions = this._reduxActions; - const allowLan = await this._daemonRpc.getAllowLan(); - actions.settings.updateAllowLan(allowLan); - } - - async _fetchAutoConnect() { - const actions = this._reduxActions; - const autoConnect = await this._daemonRpc.getAutoConnect(); - actions.settings.updateAutoConnect(autoConnect); - } - - async _fetchTunnelState() { - const state = await this._daemonRpc.getState(); - - log.debug(`Got state: ${JSON.stringify(state)}`); - - this._onChangeTunnelState(state); - } - - async _fetchTunnelOptions() { - const actions = this._reduxActions; - const tunnelOptions = await this._daemonRpc.getTunnelOptions(); - actions.settings.updateEnableIpv6(tunnelOptions.enableIpv6); - } - async _fetchVersionInfo() { const actions = this._reduxActions; const latestVersionInfo = await this._daemonRpc.getVersionInfo(); @@ -429,32 +350,62 @@ export default class AppRenderer { // reset the reconnect backoff when connection established. this._reconnectBackoff.reset(); - // attempt to restore the session try { - await this._restoreSession(); + await this._runPrimaryApplicationFlow(); + } catch (error) { + log.error(`An error was raised when running the primary application flow: ${error.message}`); + } + } + + async _runPrimaryApplicationFlow() { + // fetch initial state and subscribe for changes + try { + await this._settingsProxy.fetch(); + } catch (error) { + log.error(`Cannot fetch the initial settings: ${error.message}`); + } + + try { + await this._tunnelStateProxy.fetch(); + } catch (error) { + log.error(`Cannot fetch the initial tunnel state: ${error.message}`); + } + + // fetch the rest of data + try { + await this._fetchRelayLocations(); } catch (error) { - log.error(`Failed to restore session: ${error.message}`); + log.error(`Cannot fetch the relay locations: ${error.message}`); } - // make sure to re-subscribe to state notifications when connection is re-established. try { - await this._subscribeStateListener(); + await this._fetchAccountHistory(); + } catch (error) { + log.error(`Cannot fetch the account history: ${error.message}`); + } + + // set the appropriate start view + await this._setStartView(); + + try { + await this._fetchLocation(); } catch (error) { - log.error(`Cannot subscribe for RPC notifications: ${error.message}`); + log.error(`Cannot fetch the location: ${error.message}`); } - // fetch initial state try { - await this._fetchInitialState(); + await this._fetchVersionInfo(); } catch (error) { - log.error(`Cannot fetch initial state: ${error.message}`); + log.error(`Cannot fetch the version information: ${error.message}`); } // auto connect the tunnel on startup // note: disabled when developing if (process.env.NODE_ENV !== 'development') { + const settings = await this._settingsProxy.fetch(); + // only connect if account is set in the daemon - if (this._accountToken) { + if (settings.accountToken) { try { log.debug('Autoconnect the tunnel'); await this.connectTunnel(); @@ -469,6 +420,51 @@ export default class AppRenderer { } } + async _setStartView() { + const actions = this._reduxActions; + const history = this._memoryHistory; + const settings = await this._settingsProxy.fetch(); + const accountToken = settings.accountToken; + + if (accountToken) { + log.debug(`Account token is set. Showing the tunnel view.`); + + actions.account.updateAccountToken(accountToken); + actions.account.loginSuccessful(); + + // take user to main view if user is still at launch screen `/` + if (history.location.pathname === '/') { + actions.history.replace('/connect'); + } else { + // TODO: Reinvent the navigation back in history to make sure that user does not end up on + // the restricted screen due to changes in daemon's state. + for (const entry of history.entries) { + if (entry.pathname === '/') { + entry.pathname = '/connect'; + } + } + } + } else { + log.debug('No account set, showing login view.'); + + // show window when account is not set + ipcRenderer.send('show-window'); + + // take user to `/login` screen if user is at launch screen `/` + if (history.location.pathname === '/') { + actions.history.replace('/login'); + } else { + // TODO: Reinvent the navigation back in history to make sure that user does not end up on + // the restricted screen due to changes in daemon's state. + for (const entry of history.entries) { + if (!entry.pathname.startsWith('/settings')) { + entry.pathname = '/login'; + } + } + } + } + } + _onCloseConnection(error: ?Error) { const actions = this._reduxActions; @@ -499,37 +495,8 @@ export default class AppRenderer { this._connectedToDaemon = false; } - _subscribeStateListener(): Promise<void> { - const listener = new SubscriptionListener( - (newState: TunnelStateTransition) => { - log.debug(`Got state update: '${JSON.stringify(newState)}'`); - - this._onChangeTunnelState(newState); - }, - (error: Error) => { - log.error(`Failed to deserialize the new state: ${error.message}`); - }, - ); - - return this._daemonRpc.subscribeStateListener(listener); - } - - _fetchInitialState() { - return Promise.all([ - this._fetchTunnelState(), - this.fetchRelaySettings(), - this._fetchRelayLocations(), - this._fetchAllowLan(), - this._fetchAutoConnect(), - this._fetchLocation(), - this._fetchAccountHistory(), - this._fetchTunnelOptions(), - this._fetchVersionInfo(), - ]); - } - - _onChangeTunnelState(tunnelState: TunnelStateTransition) { - this._tunnelState = tunnelState; + _setTunnelState(tunnelState: TunnelStateTransition) { + log.debug(`Tunnel state: ${tunnelState.state}`); this._updateConnectionStatus(tunnelState); this._updateUserLocation(tunnelState.state); @@ -537,6 +504,16 @@ export default class AppRenderer { this._showNotification(tunnelState.state); } + _setSettings(newSettings: Settings) { + const reduxSettings = this._reduxActions.settings; + + reduxSettings.updateAllowLan(newSettings.allowLan); + reduxSettings.updateAutoConnect(newSettings.autoConnect); + reduxSettings.updateEnableIpv6(newSettings.tunnelOptions.enableIpv6); + + this._setRelaySettings(newSettings.relaySettings); + } + async _updateUserLocation(tunnelState: TunnelState) { if (tunnelState === 'connecting' || tunnelState === 'disconnected') { try { diff --git a/gui/packages/desktop/src/renderer/components/SelectLocation.js b/gui/packages/desktop/src/renderer/components/SelectLocation.js index e9c9852ec2..f84cadd6f3 100644 --- a/gui/packages/desktop/src/renderer/components/SelectLocation.js +++ b/gui/packages/desktop/src/renderer/components/SelectLocation.js @@ -2,7 +2,7 @@ import * as React from 'react'; import ReactDOM from 'react-dom'; -import { View } from 'reactxp'; +import { View, Component } from 'reactxp'; import { Accordion } from '@mullvad/components'; import { Layout, Container } from './Layout'; import CustomScrollbars from './CustomScrollbars'; @@ -12,15 +12,16 @@ import * as Cell from './Cell'; import styles from './SelectLocationStyles'; import type { - SettingsReduxState, + RelaySettingsRedux, RelayLocationRedux, RelayLocationCityRedux, RelayLocationRelayRedux, } from '../redux/settings/reducers'; import type { RelayLocation } from '../lib/daemon-rpc'; -export type SelectLocationProps = { - settings: SettingsReduxState, +type Props = { + relaySettings: RelaySettingsRedux, + relayLocations: Array<RelayLocationRedux>, onClose: () => void, onSelect: (location: RelayLocation) => void, }; @@ -29,19 +30,19 @@ type State = { expanded: Array<string>, }; -export default class SelectLocation extends React.Component<SelectLocationProps, State> { - _selectedCell: ?Cell.CellButton; - _scrollView: ?CustomScrollbars; +export default class SelectLocation extends Component<Props, State> { + _selectedCellRef = React.createRef(); + _scrollViewRef = React.createRef(); state = { expanded: [], }; - constructor(props: SelectLocationProps, context?: any) { - super(props, context); + constructor(props: Props) { + super(props); // set initially expanded country based on relaySettings - const relaySettings = this.props.settings.relaySettings; + const relaySettings = this.props.relaySettings; if (relaySettings.normal) { const { location } = relaySettings.normal; if (location === 'any') { @@ -64,8 +65,8 @@ export default class SelectLocation extends React.Component<SelectLocationProps, componentDidMount() { // restore scroll to selected cell - const cell = this._selectedCell; - const scrollView = this._scrollView; + const cell = this._selectedCellRef.current; + const scrollView = this._scrollViewRef.current; if (scrollView && cell) { // eslint-disable-next-line react/no-find-dom-node @@ -90,7 +91,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, <HeaderTitle>Select location</HeaderTitle> </SettingsHeader> - <CustomScrollbars autoHide={true} ref={(ref) => (this._scrollView = ref)}> + <CustomScrollbars autoHide={true} ref={this._scrollViewRef}> <View style={styles.content}> <SettingsHeader style={styles.subtitle_header}> <HeaderSubTitle> @@ -99,7 +100,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, </HeaderSubTitle> </SettingsHeader> - {this.props.settings.relayLocations.map((relayCountry) => { + {this.props.relayLocations.map((relayCountry) => { return this._renderCountry(relayCountry); })} </View> @@ -112,7 +113,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, } _isSelected(selectedLocation: RelayLocation) { - const { relaySettings } = this.props.settings; + const relaySettings = this.props.relaySettings; if (relaySettings.normal) { const otherLocation = relaySettings.normal.location; @@ -173,11 +174,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, _renderCountry(relayCountry: RelayLocationRedux) { const isSelected = this._isSelected({ country: relayCountry.code }); - const onRef = isSelected - ? (element) => { - this._selectedCell = element; - } - : undefined; + const cellRef = isSelected ? this._selectedCellRef : undefined; // either expanded by user or when the city selected within the country const isExpanded = this.state.expanded.includes(relayCountry.code); @@ -206,7 +203,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, onPress={handleSelect} disabled={!relayCountry.hasActiveRelays} testName="country" - ref={onRef}> + ref={cellRef}> {this._relayStatusIndicator(relayCountry.hasActiveRelays, isSelected)} <Cell.Label>{relayCountry.name}</Cell.Label> @@ -238,11 +235,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, const isSelected = this._isSelected(relayLocation); - const onRef = isSelected - ? (element) => { - this._selectedCell = element; - } - : undefined; + const cellRef = isSelected ? this._selectedCellRef : undefined; // either expanded by user or when the city or a relay from the city is selected const isExpanded = this.state.expanded.includes(expandedCode); @@ -267,7 +260,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, cellHoverStyle={isSelected ? styles.sub_cell__selected : null} style={isSelected ? styles.sub_cell__selected : styles.sub_cell} testName="city" - ref={onRef}> + ref={cellRef}> {this._relayStatusIndicator(relayCity.hasActiveRelays, isSelected)} <Cell.Label>{relayCity.name}</Cell.Label> @@ -298,11 +291,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, const isSelected = this._isSelected(relayLocation); - const onRef = isSelected - ? (element) => { - this._selectedCell = element; - } - : undefined; + const cellRef = isSelected ? this._selectedCellRef : undefined; const handleSelect = !isSelected ? () => { @@ -317,7 +306,7 @@ export default class SelectLocation extends React.Component<SelectLocationProps, cellHoverStyle={isSelected ? styles.sub_sub_cell__selected : null} style={isSelected ? styles.sub_sub_cell__selected : styles.sub_sub_cell} testName="relay" - ref={onRef}> + ref={cellRef}> {this._relayStatusIndicator(true, isSelected)} <Cell.Label>{relay.hostname}</Cell.Label> diff --git a/gui/packages/desktop/src/renderer/containers/AdvancedSettingsPage.js b/gui/packages/desktop/src/renderer/containers/AdvancedSettingsPage.js index a5f0c4aaea..35e50b3653 100644 --- a/gui/packages/desktop/src/renderer/containers/AdvancedSettingsPage.js +++ b/gui/packages/desktop/src/renderer/containers/AdvancedSettingsPage.js @@ -24,8 +24,8 @@ const mapRelaySettingsToProtocolAndPort = (relaySettings: RelaySettingsRedux) => protocol: protocol === 'any' ? 'Automatic' : protocol, port: port === 'any' ? 'Automatic' : port, }; - } else if (relaySettings.custom_tunnel_endpoint) { - const { protocol, port } = relaySettings.custom_tunnel_endpoint; + } else if (relaySettings.customTunnelEndpoint) { + const { protocol, port } = relaySettings.customTunnelEndpoint; return { protocol, port }; } else { throw new Error('Unknown type of relay settings.'); @@ -56,7 +56,6 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, props: SharedRouteProps) => try { await props.app.updateRelaySettings(relayUpdate); - await props.app.fetchRelaySettings(); } catch (e) { log.error('Failed to update relay settings', e.message); } diff --git a/gui/packages/desktop/src/renderer/containers/ConnectPage.js b/gui/packages/desktop/src/renderer/containers/ConnectPage.js index 828d92959e..5edb4447cc 100644 --- a/gui/packages/desktop/src/renderer/containers/ConnectPage.js +++ b/gui/packages/desktop/src/renderer/containers/ConnectPage.js @@ -48,7 +48,7 @@ function getRelayName( } return 'Unknown'; - } else if (relaySettings.custom_tunnel_endpoint) { + } else if (relaySettings.customTunnelEndpoint) { return 'Custom'; } else { throw new Error('Unsupported relay settings.'); diff --git a/gui/packages/desktop/src/renderer/containers/SelectLocationPage.js b/gui/packages/desktop/src/renderer/containers/SelectLocationPage.js index c4a09f0e6f..80f4f64b74 100644 --- a/gui/packages/desktop/src/renderer/containers/SelectLocationPage.js +++ b/gui/packages/desktop/src/renderer/containers/SelectLocationPage.js @@ -11,23 +11,24 @@ import type { ReduxState, ReduxDispatch } from '../redux/store'; import type { SharedRouteProps } from '../routes'; const mapStateToProps = (state: ReduxState) => ({ - settings: state.settings, + relaySettings: state.settings.relaySettings, + relayLocations: state.settings.relayLocations, }); const mapDispatchToProps = (dispatch: ReduxDispatch, props: SharedRouteProps) => { const history = bindActionCreators({ goBack }, dispatch); return { onClose: () => history.goBack(), onSelect: async (relayLocation) => { + // dismiss the view first + history.goBack(); + try { const relayUpdate = RelaySettingsBuilder.normal() .location.fromRaw(relayLocation) .build(); await props.app.updateRelaySettings(relayUpdate); - await props.app.fetchRelaySettings(); await props.app.connectTunnel(); - - history.goBack(); } catch (e) { log.error(`Failed to select server: ${e.message}`); } diff --git a/gui/packages/desktop/src/renderer/lib/daemon-rpc.js b/gui/packages/desktop/src/renderer/lib/daemon-rpc.js index fcfcf6744a..b884002403 100644 --- a/gui/packages/desktop/src/renderer/lib/daemon-rpc.js +++ b/gui/packages/desktop/src/renderer/lib/daemon-rpc.js @@ -96,7 +96,7 @@ export type RelaySettings = normal: RelaySettingsNormal<TunnelConstraints<OpenVpnConstraints>>, |} | {| - custom_tunnel_endpoint: RelaySettingsCustom, + customTunnelEndpoint: RelaySettingsCustom, |}; // types describing the partial update of RelaySettings @@ -108,7 +108,7 @@ export type RelaySettingsUpdate = normal: RelaySettingsNormalUpdate, |} | {| - custom_tunnel_endpoint: RelaySettingsCustom, + customTunnelEndpoint: RelaySettingsCustom, |}; const constraint = <T>(constraintValue: SchemaNode<T>) => { @@ -179,9 +179,9 @@ export type RelayListCity = { export type RelayListHostname = { hostname: string, - ipv4_addr_in: string, - ipv4_addr_exit: string, - include_in_country: boolean, + ipv4AddrIn: string, + ipv4AddrExit: string, + includeInCountry: boolean, weight: number, }; @@ -213,6 +213,9 @@ const RelayListSchema = object({ export type TunnelOptions = { enableIpv6: boolean, + openvpn: { + mssfix: ?number, + }, }; const TunnelOptionsSchema = object({ @@ -294,26 +297,39 @@ export class SubscriptionListener<T> { } } +export type Settings = { + accountToken: AccountToken, + allowLan: boolean, + autoConnect: boolean, + relaySettings: RelaySettings, + tunnelOptions: TunnelOptions, +}; + +const SettingsSchema = object({ + account_token: maybe(string), + allow_lan: boolean, + auto_connect: boolean, + relay_settings: RelaySettingsSchema, + tunnel_options: TunnelOptionsSchema, +}); + export interface DaemonRpcProtocol { connect({ path: string }): void; disconnect(): void; getAccountData(AccountToken): Promise<AccountData>; getRelayLocations(): Promise<RelayList>; - getAccount(): Promise<?AccountToken>; setAccount(accountToken: ?AccountToken): Promise<void>; updateRelaySettings(RelaySettingsUpdate): Promise<void>; - getRelaySettings(): Promise<RelaySettings>; setAllowLan(boolean): Promise<void>; - getAllowLan(): Promise<boolean>; setEnableIpv6(boolean): Promise<void>; - getTunnelOptions(): Promise<TunnelOptions>; setAutoConnect(boolean): Promise<void>; - getAutoConnect(): Promise<boolean>; connectTunnel(): Promise<void>; disconnectTunnel(): Promise<void>; getLocation(): Promise<Location>; getState(): Promise<TunnelStateTransition>; + getSettings(): Promise<Settings>; subscribeStateListener(listener: SubscriptionListener<TunnelStateTransition>): Promise<void>; + subscribeSettingsListener(listener: SubscriptionListener<Settings>): Promise<void>; addConnectionObserver(observer: ConnectionObserver): void; removeConnectionObserver(observer: ConnectionObserver): void; getAccountHistory(): Promise<Array<AccountToken>>; @@ -386,94 +402,32 @@ export class DaemonRpc implements DaemonRpcProtocol { async getRelayLocations(): Promise<RelayList> { const response = await this._transport.send('get_relay_locations'); try { - return validate(RelayListSchema, response); + return camelCaseObjectKeys(validate(RelayListSchema, response)); } catch (error) { throw new ResponseParseError('Invalid response from get_relay_locations', error); } } - async getAccount(): Promise<?AccountToken> { - const response = await this._transport.send('get_account'); - if (response === null || typeof response === 'string') { - return response; - } else { - throw new ResponseParseError('Invalid response from get_account', null); - } - } - async setAccount(accountToken: ?AccountToken): Promise<void> { await this._transport.send('set_account', accountToken); } async updateRelaySettings(relaySettings: RelaySettingsUpdate): Promise<void> { - await this._transport.send('update_relay_settings', [relaySettings]); - } - - async getRelaySettings(): Promise<RelaySettings> { - const response = await this._transport.send('get_relay_settings'); - try { - const validatedObject = validate(RelaySettingsSchema, response); - - /* $FlowFixMe: - There is no way to express constraints with string literals, i.e: - - RelaySettingsSchema constraint: - oneOf(string, object) - - RelaySettings constraint: - 'any' | object - - These two are incompatible so we simply enforce the type for now. - */ - return ((validatedObject: any): RelaySettings); - } catch (e) { - throw new ResponseParseError('Invalid response from get_relay_settings', e); - } + await this._transport.send('update_relay_settings', [underscoreObjectKeys(relaySettings)]); } async setAllowLan(allowLan: boolean): Promise<void> { await this._transport.send('set_allow_lan', [allowLan]); } - async getAllowLan(): Promise<boolean> { - const response = await this._transport.send('get_allow_lan'); - if (typeof response === 'boolean') { - return response; - } else { - throw new ResponseParseError('Invalid response from get_allow_lan', null); - } - } - async setEnableIpv6(enableIpv6: boolean): Promise<void> { await this._transport.send('set_enable_ipv6', [enableIpv6]); } - async getTunnelOptions(): Promise<TunnelOptions> { - const response = await this._transport.send('get_tunnel_options'); - try { - const validatedObject = validate(TunnelOptionsSchema, response); - - return { - enableIpv6: validatedObject.enable_ipv6, - }; - } catch (error) { - throw new ResponseParseError('Invalid response from get_tunnel_options', error); - } - } - async setAutoConnect(autoConnect: boolean): Promise<void> { await this._transport.send('set_auto_connect', [autoConnect]); } - async getAutoConnect(): Promise<boolean> { - const response = await this._transport.send('get_auto_connect'); - if (typeof response === 'boolean') { - return response; - } else { - throw new ResponseParseError('Invalid response from get_auto_connect', null); - } - } - async connectTunnel(): Promise<void> { await this._transport.send('connect'); } @@ -500,10 +454,19 @@ export class DaemonRpc implements DaemonRpcProtocol { } } + async getSettings(): Promise<Settings> { + const response = await this._transport.send('get_settings'); + try { + return camelCaseObjectKeys(validate(SettingsSchema, response)); + } catch (error) { + throw new ResponseParseError('Invalid response from get_settings', error); + } + } + subscribeStateListener(listener: SubscriptionListener<TunnelStateTransition>): Promise<void> { return this._transport.subscribe('new_state', (payload) => { try { - const newState = validate(TunnelStateTransitionSchema, payload); + const newState = camelCaseObjectKeys(validate(TunnelStateTransitionSchema, payload)); listener._onEvent(newState); } catch (error) { listener._onError(new ResponseParseError('Invalid payload from new_state', error)); @@ -511,6 +474,17 @@ export class DaemonRpc implements DaemonRpcProtocol { }); } + subscribeSettingsListener(listener: SubscriptionListener<Settings>): Promise<void> { + return this._transport.subscribe('settings', (payload) => { + try { + const newSettings = camelCaseObjectKeys(validate(SettingsSchema, payload)); + listener._onEvent(newSettings); + } catch (error) { + listener._onError(new ResponseParseError('Invalid payload from settings', error)); + } + }); + } + async getAccountHistory(): Promise<Array<AccountToken>> { const response = await this._transport.send('get_account_history'); try { @@ -549,3 +523,38 @@ export class DaemonRpc implements DaemonRpcProtocol { } } } + +function underscoreToCamelCase(str: string): string { + return str.replace(/_([a-z])/gi, (matches) => matches[1].toUpperCase()); +} + +function camelCaseToUnderscore(str: string): string { + return str + .replace(/[a-z0-9][A-Z]/g, (matches) => `${matches[0]}_${matches[1].toLowerCase()}`) + .toLowerCase(); +} + +function camelCaseObjectKeys(object: Object) { + return transformObjectKeys(object, underscoreToCamelCase); +} + +function underscoreObjectKeys(object: Object) { + return transformObjectKeys(object, camelCaseToUnderscore); +} + +function transformObjectKeys(object: Object, keyTransformer: (string) => string) { + for (const sourceKey of Object.keys(object)) { + const targetKey = keyTransformer(sourceKey); + const sourceValue = object[sourceKey]; + + object[targetKey] = + sourceValue !== null && typeof sourceValue === 'object' + ? transformObjectKeys(sourceValue, keyTransformer) + : sourceValue; + + if (sourceKey !== targetKey) { + delete object[sourceKey]; + } + } + return object; +} diff --git a/gui/packages/desktop/src/renderer/lib/jsonrpc-client.js b/gui/packages/desktop/src/renderer/lib/jsonrpc-client.js index 9cafade681..0f51ca57cb 100644 --- a/gui/packages/desktop/src/renderer/lib/jsonrpc-client.js +++ b/gui/packages/desktop/src/renderer/lib/jsonrpc-client.js @@ -184,7 +184,7 @@ export default class JsonRpcClient<T> extends EventEmitter { } async subscribe(event: string, listener: (mixed) => void): Promise<*> { - log.silly(`Adding a listener to ${event}`); + log.silly(`Adding a listener for ${event}`); try { const subscriptionId = await this.send(`${event}_subscribe`); @@ -206,7 +206,7 @@ export default class JsonRpcClient<T> extends EventEmitter { return new Promise((resolve, reject) => { const transport = this._transport; if (!transport) { - reject(new Error('Websocket is not connected.')); + reject(new Error('RPC client transport is not connected.')); return; } @@ -288,10 +288,10 @@ export default class JsonRpcClient<T> extends EventEmitter { const listener = this._subscriptions.get(subscriptionId); if (listener) { - log.silly('Got notification', message.payload.method, message.payload.params.result); + log.silly(`Got notification for ${message.payload.method}`); listener(message.payload.params.result); } else { - log.warn('Got notification for', message.payload.method, 'but no one is listening for it'); + log.warn(`Got notification for ${message.payload.method} but no one is listening for it`); } } diff --git a/gui/packages/desktop/src/renderer/lib/relay-settings-builder.js b/gui/packages/desktop/src/renderer/lib/relay-settings-builder.js index 5065a485f6..dc865472d5 100644 --- a/gui/packages/desktop/src/renderer/lib/relay-settings-builder.js +++ b/gui/packages/desktop/src/renderer/lib/relay-settings-builder.js @@ -161,7 +161,7 @@ class CustomRelaySettingsBuilder { build(): RelaySettingsUpdate { return { - custom_tunnel_endpoint: this._payload, + customTunnelEndpoint: this._payload, }; } diff --git a/gui/packages/desktop/src/renderer/lib/subscription-proxy/base-proxy.js b/gui/packages/desktop/src/renderer/lib/subscription-proxy/base-proxy.js new file mode 100644 index 0000000000..b3ebfd2595 --- /dev/null +++ b/gui/packages/desktop/src/renderer/lib/subscription-proxy/base-proxy.js @@ -0,0 +1,118 @@ +// @flow + +import log from 'electron-log'; +import { ConnectionObserver, SubscriptionListener, ResponseParseError } from '../daemon-rpc'; +import type { DaemonRpcProtocol } from '../daemon-rpc'; + +export default class BaseSubscriptionProxy<T> { + _rpc: DaemonRpcProtocol; + _connectionObserver = new ConnectionObserver( + () => {}, + () => { + this._didDisconnectFromDaemon(); + }, + ); + + _isSubscribed = false; + _executingPromise: ?Promise<T>; + + _value: ?T; + _onUpdate: (T) => void; + + constructor(rpc: DaemonRpcProtocol, onUpdate: (T) => void) { + this._rpc = rpc; + this._onUpdate = onUpdate; + + rpc.addConnectionObserver(this._connectionObserver); + } + + async fetch(): Promise<T> { + // return the cached promise if there is an ongoing fetch + if (this._executingPromise) { + return this._executingPromise; + } + + // return the value if it's available + if (this._value) { + return this._value; + } + + // subscribe if needed and fetch the initial state. + const fetchPromise = this._subscribeAndFetchValue(); + + // cache the fetch promise + this._executingPromise = fetchPromise; + + try { + const value = await fetchPromise; + + // cache the initial value + this._value = value; + + // notify the delegate upon initial fetch + this._onUpdate(value); + + return value; + } catch (error) { + throw error; + } finally { + // unset the cached fetch promise + this._executingPromise = null; + } + } + + async _subscribeAndFetchValue(): Promise<T> { + if (!this._isSubscribed) { + await this._subscribeValueListener(); + this._isSubscribed = true; + } + + // request the initial value + return await this.constructor.requestValue(this._rpc); + } + + static subscribeValueListener( + _rpc: DaemonRpcProtocol, + _listener: SubscriptionListener<T>, + ): Promise<void> { + throw new Error( + `Override static ${this.constructor.name}.subscribeValueListener() in subclasses`, + ); + } + + static requestValue(_rpc: DaemonRpcProtocol): Promise<T> { + throw new Error(`Override static ${this.constructor.name}.requestValue() in subclasses`); + } + + _subscribeValueListener(): Promise<void> { + const listener = new SubscriptionListener( + (value: T) => { + this._didReceiveUpdate(value); + }, + (error: Error) => { + let reason = ''; + + if (error instanceof ResponseParseError) { + const validationError = error.validationError; + if (validationError) { + reason = ` Reason: ${validationError.message}`; + } + } + + log.error(`Failed to deserialize the payload: ${error.message}.${reason}`); + }, + ); + return this.constructor.subscribeValueListener(this._rpc, listener); + } + + _didReceiveUpdate(updatedValue: T) { + this._value = updatedValue; + this._onUpdate(updatedValue); + } + + _didDisconnectFromDaemon() { + this._isSubscribed = false; + this._executingPromise = null; + this._value = null; + } +} diff --git a/gui/packages/desktop/src/renderer/lib/subscription-proxy/settings-proxy.js b/gui/packages/desktop/src/renderer/lib/subscription-proxy/settings-proxy.js new file mode 100644 index 0000000000..6dc3e7e9b7 --- /dev/null +++ b/gui/packages/desktop/src/renderer/lib/subscription-proxy/settings-proxy.js @@ -0,0 +1,15 @@ +// @flow + +import BaseSubscriptionProxy from './base-proxy'; +import { SubscriptionListener } from '../daemon-rpc'; +import type { DaemonRpcProtocol, Settings } from '../daemon-rpc'; + +export default class SettingsProxy extends BaseSubscriptionProxy<Settings> { + static subscribeValueListener(rpc: DaemonRpcProtocol, listener: SubscriptionListener<Settings>) { + return rpc.subscribeSettingsListener(listener); + } + + static requestValue(rpc: DaemonRpcProtocol): Promise<Settings> { + return rpc.getSettings(); + } +} diff --git a/gui/packages/desktop/src/renderer/lib/subscription-proxy/tunnel-state-proxy.js b/gui/packages/desktop/src/renderer/lib/subscription-proxy/tunnel-state-proxy.js new file mode 100644 index 0000000000..520885fe98 --- /dev/null +++ b/gui/packages/desktop/src/renderer/lib/subscription-proxy/tunnel-state-proxy.js @@ -0,0 +1,18 @@ +// @flow + +import BaseSubscriptionProxy from './base-proxy'; +import { SubscriptionListener } from '../daemon-rpc'; +import type { DaemonRpcProtocol, TunnelStateTransition } from '../daemon-rpc'; + +export default class TunnelStateProxy extends BaseSubscriptionProxy<TunnelStateTransition> { + static subscribeValueListener( + rpc: DaemonRpcProtocol, + listener: SubscriptionListener<TunnelStateTransition>, + ) { + return rpc.subscribeStateListener(listener); + } + + static requestValue(rpc: DaemonRpcProtocol): Promise<TunnelStateTransition> { + return rpc.getState(); + } +} diff --git a/gui/packages/desktop/src/renderer/redux/settings/reducers.js b/gui/packages/desktop/src/renderer/redux/settings/reducers.js index 096dede5c2..e9b2ff61b2 100644 --- a/gui/packages/desktop/src/renderer/redux/settings/reducers.js +++ b/gui/packages/desktop/src/renderer/redux/settings/reducers.js @@ -12,7 +12,7 @@ export type RelaySettingsRedux = }, |} | {| - custom_tunnel_endpoint: { + customTunnelEndpoint: { host: string, port: number, protocol: RelayProtocol, diff --git a/gui/packages/desktop/test/components/SelectLocation.spec.js b/gui/packages/desktop/test/components/SelectLocation.spec.js index 3d35da0edd..f4aaf83ba1 100644 --- a/gui/packages/desktop/test/components/SelectLocation.spec.js +++ b/gui/packages/desktop/test/components/SelectLocation.spec.js @@ -5,11 +5,8 @@ import { shallow } from 'enzyme'; import { CloseBarItem } from '../../src/renderer/components/NavigationBar'; import SelectLocation from '../../src/renderer/components/SelectLocation'; -import type { SettingsReduxState } from '../../src/renderer/redux/settings/reducers'; -import type { SelectLocationProps } from '../../src/renderer/components/SelectLocation'; - describe('components/SelectLocation', () => { - const state: SettingsReduxState = { + const defaultProps = { relaySettings: { normal: { location: 'any', @@ -37,6 +34,13 @@ describe('components/SelectLocation', () => { includeInCountry: true, weight: 1, }, + { + hostname: 'fake2.mullvad.net', + ipv4AddrIn: '192.168.0.101', + ipv4AddrExit: '192.168.1.101', + includeInCountry: true, + weight: 1, + }, ], }, { @@ -58,39 +62,24 @@ describe('components/SelectLocation', () => { ], }, ], - autoConnect: false, - allowLan: false, - enableIpv6: true, - }; - - const makeProps = ( - state: SettingsReduxState, - mergeProps: $Shape<SelectLocationProps>, - ): SelectLocationProps => { - const defaultProps: SelectLocationProps = { - settings: state, - onClose: () => {}, - onSelect: (_server) => {}, - }; - return Object.assign({}, defaultProps, mergeProps); - }; - - const render = (props: SelectLocationProps) => { - return shallow(<SelectLocation {...props} />); }; it('should call close callback', (done) => { - const props = makeProps(state, { + const props = { + ...defaultProps, onClose: () => done(), - }); - const component = render(props) + onSelect: () => {}, + }; + const component = shallow(<SelectLocation {...props} />) .find(CloseBarItem) .dive(); component.simulate('press'); }); it('should call select callback for country', (done) => { - const props = makeProps(state, { + const props = { + ...defaultProps, + onClose: () => {}, onSelect: (location) => { try { expect(location).to.deep.equal({ @@ -101,14 +90,17 @@ describe('components/SelectLocation', () => { done(e); } }, - }); - const elements = getComponent(render(props), 'country'); + }; + const component = shallow(<SelectLocation {...props} />); + const elements = getComponent(component, 'country'); expect(elements).to.have.length(1); elements.at(0).simulate('press'); }); it('should call select callback for city', (done) => { - const props = makeProps(state, { + const props = { + ...defaultProps, + onClose: () => {}, onSelect: (location) => { try { expect(location).to.deep.equal({ @@ -119,8 +111,30 @@ describe('components/SelectLocation', () => { done(e); } }, - }); - const elements = getComponent(render(props), 'city'); + }; + const component = shallow(<SelectLocation {...props} />); + const elements = getComponent(component, 'city'); + expect(elements).to.have.length(2); + elements.at(0).simulate('press'); + }); + + it('should call select callback for relay', (done) => { + const props = { + ...defaultProps, + onClose: () => {}, + onSelect: (location) => { + try { + expect(location).to.deep.equal({ + hostname: ['se', 'mma', 'fake1.mullvad.net'], + }); + done(); + } catch (e) { + done(e); + } + }, + }; + const component = shallow(<SelectLocation {...props} />); + const elements = getComponent(component, 'relay'); expect(elements).to.have.length(2); elements.at(0).simulate('press'); }); diff --git a/gui/packages/desktop/test/relay-settings-builder.spec.js b/gui/packages/desktop/test/relay-settings-builder.spec.js index 3230861e0a..56126adca5 100644 --- a/gui/packages/desktop/test/relay-settings-builder.spec.js +++ b/gui/packages/desktop/test/relay-settings-builder.spec.js @@ -132,7 +132,7 @@ describe('Relay settings builder', () => { }) .build(), ).to.deep.equal({ - custom_tunnel_endpoint: { + customTunnelEndpoint: { host: 'se2.mullvad.net', tunnel: { openvpn: { diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs index 1bcdeb8dd2..8eb1a0348a 100644 --- a/mullvad-daemon/src/main.rs +++ b/mullvad-daemon/src/main.rs @@ -79,7 +79,7 @@ use std::{mem, thread}; use talpid_core::mpsc::IntoSender; use talpid_core::tunnel_state_machine::{self, TunnelCommand, TunnelParameters}; -use talpid_types::net::{TunnelEndpoint, TunnelOptions}; +use talpid_types::net::TunnelEndpoint; use talpid_types::tunnel::{BlockReason, TunnelStateTransition}; @@ -350,17 +350,12 @@ impl Daemon { GetAccountData(tx, account_token) => self.on_get_account_data(tx, account_token), GetRelayLocations(tx) => self.on_get_relay_locations(tx), SetAccount(tx, account_token) => self.on_set_account(tx, account_token), - GetAccount(tx) => self.on_get_account(tx), UpdateRelaySettings(tx, update) => self.on_update_relay_settings(tx, update), SetAllowLan(tx, allow_lan) => self.on_set_allow_lan(tx, allow_lan), - GetAllowLan(tx) => self.on_get_allow_lan(tx), SetAutoConnect(tx, auto_connect) => self.on_set_auto_connect(tx, auto_connect), - GetAutoConnect(tx) => self.on_get_auto_connect(tx), SetOpenVpnMssfix(tx, mssfix_arg) => self.on_set_openvpn_mssfix(tx, mssfix_arg), SetEnableIpv6(tx, enable_ipv6) => self.on_set_enable_ipv6(tx, enable_ipv6), - GetTunnelOptions(tx) => self.on_get_tunnel_options(tx), GetSettings(tx) => self.on_get_settings(tx), - GetRelaySettings(tx) => self.on_get_relay_settings(tx), GetVersionInfo(tx) => self.on_get_version_info(tx), GetCurrentVersion(tx) => self.on_get_current_version(tx), Shutdown => self.handle_trigger_shutdown_event(), @@ -471,17 +466,14 @@ impl Daemon { Self::oneshot_send(tx, current_version, "get_current_version response"); } - fn on_get_account(&self, tx: OneshotSender<Option<String>>) { - Self::oneshot_send(tx, self.settings.get_account_token(), "current account") - } - fn on_update_relay_settings(&mut self, tx: OneshotSender<()>, update: RelaySettingsUpdate) { let save_result = self.settings.update_relay_settings(update); match save_result.chain_err(|| "Unable to save settings") { - Ok(changed) => { + Ok(settings_changed) => { Self::oneshot_send(tx, (), "update_relay_settings response"); - - if changed { + if settings_changed { + self.management_interface_broadcaster + .notify_settings(&self.settings); info!("Initiating tunnel restart because the relay settings changed"); self.reconnect_tunnel(); } @@ -490,29 +482,21 @@ impl Daemon { } } - fn on_get_relay_settings(&self, tx: OneshotSender<RelaySettings>) { - Self::oneshot_send(tx, self.settings.get_relay_settings(), "relay settings") - } - fn on_set_allow_lan(&mut self, tx: OneshotSender<()>, allow_lan: bool) { let save_result = self.settings.set_allow_lan(allow_lan); match save_result.chain_err(|| "Unable to save settings") { Ok(settings_changed) => { + Self::oneshot_send(tx, (), "set_allow_lan response"); if settings_changed { self.management_interface_broadcaster .notify_settings(&self.settings); self.send_tunnel_command(TunnelCommand::AllowLan(allow_lan)); } - Self::oneshot_send(tx, (), "set_allow_lan response"); } Err(e) => error!("{}", e.display_chain()), } } - fn on_get_allow_lan(&self, tx: OneshotSender<bool>) { - Self::oneshot_send(tx, self.settings.get_allow_lan(), "allow lan") - } - fn on_set_auto_connect(&mut self, tx: OneshotSender<()>, auto_connect: bool) { let save_result = self.settings.set_auto_connect(auto_connect); match save_result.chain_err(|| "Unable to save settings") { @@ -527,14 +511,6 @@ impl Daemon { } } - fn on_get_auto_connect(&self, tx: OneshotSender<bool>) { - Self::oneshot_send( - tx, - self.settings.get_auto_connect(), - "get auto-connect response", - ) - } - fn on_set_openvpn_mssfix(&mut self, tx: OneshotSender<()>, mssfix_arg: Option<u16>) { let save_result = self.settings.set_openvpn_mssfix(mssfix_arg); match save_result.chain_err(|| "Unable to save settings") { @@ -565,11 +541,6 @@ impl Daemon { } } - fn on_get_tunnel_options(&self, tx: OneshotSender<TunnelOptions>) { - let tunnel_options = self.settings.get_tunnel_options().clone(); - Self::oneshot_send(tx, tunnel_options, "get_tunnel_options response"); - } - fn on_get_settings(&self, tx: OneshotSender<Settings>) { Self::oneshot_send(tx, self.settings.clone(), "get_settings response"); } diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index 2e534baf52..db5c3fedc1 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -10,7 +10,7 @@ use mullvad_types::account::{AccountData, AccountToken}; use mullvad_types::location::GeoIpLocation; use mullvad_paths; -use mullvad_types::relay_constraints::{RelaySettings, RelaySettingsUpdate}; +use mullvad_types::relay_constraints::RelaySettingsUpdate; use mullvad_types::relay_list::RelayList; use mullvad_types::settings::Settings; use mullvad_types::states::TargetState; @@ -25,7 +25,6 @@ use std::sync::{Arc, Mutex, RwLock}; use talpid_core::mpsc::IntoSender; use talpid_ipc; -use talpid_types::net::TunnelOptions; use talpid_types::tunnel::TunnelStateTransition; use uuid; @@ -53,10 +52,6 @@ build_rpc_trait! { #[rpc(meta, name = "set_account")] fn set_account(&self, Self::Metadata, Option<AccountToken>) -> BoxFuture<(), Error>; - /// Get which account is configured. - #[rpc(meta, name = "get_account")] - fn get_account(&self, Self::Metadata) -> BoxFuture<Option<AccountToken>, Error>; - /// Update constraints put on the type of tunnel connection to use #[rpc(meta, name = "update_relay_settings")] fn update_relay_settings( @@ -64,29 +59,14 @@ build_rpc_trait! { Self::Metadata, RelaySettingsUpdate ) -> BoxFuture<(), Error>; - /// Update constraints put on the type of tunnel connection to use - #[rpc(meta, name = "get_relay_settings")] - fn get_relay_settings( - &self, - Self::Metadata - ) -> BoxFuture<RelaySettings, Error>; - /// Set if the client should allow communication with the LAN while in secured state. #[rpc(meta, name = "set_allow_lan")] fn set_allow_lan(&self, Self::Metadata, bool) -> BoxFuture<(), Error>; - /// Get if the client should allow communication with the LAN while in secured state. - #[rpc(meta, name = "get_allow_lan")] - fn get_allow_lan(&self, Self::Metadata) -> BoxFuture<bool, Error>; - /// Set if the daemon should automatically establish a tunnel on start or not. #[rpc(meta, name = "set_auto_connect")] fn set_auto_connect(&self, Self::Metadata, bool) -> BoxFuture<(), Error>; - /// Get if the daemon should automatically establish a tunnel on start or not. - #[rpc(meta, name = "get_auto_connect")] - fn get_auto_connect(&self, Self::Metadata) -> BoxFuture<bool, Error>; - /// Try to connect if disconnected, or do nothing if already connecting/connected. #[rpc(meta, name = "connect")] fn connect(&self, Self::Metadata) -> BoxFuture<(), Error>; @@ -126,10 +106,6 @@ build_rpc_trait! { #[rpc(meta, name = "set_enable_ipv6")] fn set_enable_ipv6(&self, Self::Metadata, bool) -> BoxFuture<(), Error>; - /// Gets tunnel specific options - #[rpc(meta, name = "get_tunnel_options")] - fn get_tunnel_options(&self, Self::Metadata) -> BoxFuture<TunnelOptions, Error>; - /// Returns the current daemon settings #[rpc(meta, name = "get_settings")] fn get_settings(&self, Self::Metadata) -> BoxFuture<Settings, Error>; @@ -187,26 +163,16 @@ pub enum ManagementCommand { GetRelayLocations(OneshotSender<RelayList>), /// Set which account token to use for subsequent connection attempts. SetAccount(OneshotSender<()>, Option<AccountToken>), - /// Request the current account token being used. - GetAccount(OneshotSender<Option<AccountToken>>), /// Place constraints on the type of tunnel and relay UpdateRelaySettings(OneshotSender<()>, RelaySettingsUpdate), - /// Read the constraints put on the tunnel and relay - GetRelaySettings(OneshotSender<RelaySettings>), /// Set the allow LAN setting. SetAllowLan(OneshotSender<()>, bool), - /// Get the current allow LAN setting. - GetAllowLan(OneshotSender<bool>), /// Set the auto-connect setting. SetAutoConnect(OneshotSender<()>, bool), - /// Get the current auto-connect setting. - GetAutoConnect(OneshotSender<bool>), /// Set the mssfix argument for OpenVPN SetOpenVpnMssfix(OneshotSender<()>, Option<u16>), /// Set if IPv6 should be enabled in the tunnel SetEnableIpv6(OneshotSender<()>, bool), - /// Get the tunnel options - GetTunnelOptions(OneshotSender<TunnelOptions>), /// Get the daemon settings GetSettings(OneshotSender<Settings>), /// Get information about the currently running and latest app versions @@ -446,15 +412,6 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi Box::new(future) } - fn get_account(&self, _: Self::Metadata) -> BoxFuture<Option<AccountToken>, Error> { - debug!("get_account"); - let (tx, rx) = sync::oneshot::channel(); - let future = self - .send_command_to_daemon(ManagementCommand::GetAccount(tx)) - .and_then(|_| rx.map_err(|_| Error::internal_error())); - Box::new(future) - } - fn update_relay_settings( &self, _: Self::Metadata, @@ -470,15 +427,6 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi Box::new(future) } - fn get_relay_settings(&self, _: Self::Metadata) -> BoxFuture<RelaySettings, Error> { - debug!("get_relay_settings"); - let (tx, rx) = sync::oneshot::channel(); - let future = self - .send_command_to_daemon(ManagementCommand::GetRelaySettings(tx)) - .and_then(|_| rx.map_err(|_| Error::internal_error())); - Box::new(future) - } - fn set_allow_lan(&self, _: Self::Metadata, allow_lan: bool) -> BoxFuture<(), Error> { debug!("set_allow_lan({})", allow_lan); let (tx, rx) = sync::oneshot::channel(); @@ -488,15 +436,6 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi Box::new(future) } - fn get_allow_lan(&self, _: Self::Metadata) -> BoxFuture<bool, Error> { - debug!("get_allow_lan"); - let (tx, rx) = sync::oneshot::channel(); - let future = self - .send_command_to_daemon(ManagementCommand::GetAllowLan(tx)) - .and_then(|_| rx.map_err(|_| Error::internal_error())); - Box::new(future) - } - fn set_auto_connect(&self, _: Self::Metadata, auto_connect: bool) -> BoxFuture<(), Error> { debug!("set_auto_connect({})", auto_connect); let (tx, rx) = sync::oneshot::channel(); @@ -506,15 +445,6 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi Box::new(future) } - fn get_auto_connect(&self, _: Self::Metadata) -> BoxFuture<bool, Error> { - debug!("get_auto_connect"); - let (tx, rx) = sync::oneshot::channel(); - let future = self - .send_command_to_daemon(ManagementCommand::GetAutoConnect(tx)) - .and_then(|_| rx.map_err(|_| Error::internal_error())); - Box::new(future) - } - fn connect(&self, _: Self::Metadata) -> BoxFuture<(), Error> { debug!("connect"); let (tx, rx) = sync::oneshot::channel(); @@ -617,15 +547,6 @@ impl<T: From<ManagementCommand> + 'static + Send> ManagementInterfaceApi Box::new(future) } - fn get_tunnel_options(&self, _: Self::Metadata) -> BoxFuture<TunnelOptions, Error> { - debug!("get_tunnel_options"); - let (tx, rx) = sync::oneshot::channel(); - let future = self - .send_command_to_daemon(ManagementCommand::GetTunnelOptions(tx)) - .and_then(|_| rx.map_err(|_| Error::internal_error())); - Box::new(future) - } - fn get_settings(&self, _: Self::Metadata) -> BoxFuture<Settings, Error> { debug!("get_settings"); let (tx, rx) = sync::oneshot::channel(); |
