diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2022-05-12 14:21:15 +0200 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2022-05-13 10:49:25 +0200 |
| commit | 5c99fdee273b54a26224c79ef839fc3d9f615707 (patch) | |
| tree | 71d4c36555ed0de0184ec945a39f81f4c315ad2f /gui/src | |
| parent | 64f206b034c9480ba21fe89472724121bac321e0 (diff) | |
| download | mullvadvpn-5c99fdee273b54a26224c79ef839fc3d9f615707.tar.xz mullvadvpn-5c99fdee273b54a26224c79ef839fc3d9f615707.zip | |
Update to new device state rpc calls
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/main/daemon-rpc.ts | 64 | ||||
| -rw-r--r-- | gui/src/main/index.ts | 102 | ||||
| -rw-r--r-- | gui/src/main/tray-icon-controller.ts | 28 | ||||
| -rw-r--r-- | gui/src/renderer/app.tsx | 112 | ||||
| -rw-r--r-- | gui/src/renderer/components/Account.tsx | 14 | ||||
| -rw-r--r-- | gui/src/renderer/containers/AccountPage.tsx | 2 | ||||
| -rw-r--r-- | gui/src/renderer/redux/account/actions.ts | 18 | ||||
| -rw-r--r-- | gui/src/shared/connect-helper.ts | 14 | ||||
| -rw-r--r-- | gui/src/shared/daemon-rpc-types.ts | 18 | ||||
| -rw-r--r-- | gui/src/shared/ipc-schema.ts | 11 |
10 files changed, 194 insertions, 189 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts index 84e832cd5f..c40e40b864 100644 --- a/gui/src/main/daemon-rpc.ts +++ b/gui/src/main/daemon-rpc.ts @@ -15,14 +15,14 @@ import { ConnectionConfig, Constraint, DaemonEvent, + DeviceEvent, + DeviceState, ErrorStateCause, FirewallPolicyError, IAccountData, IAppVersionInfo, IBridgeConstraints, IDevice, - IDeviceConfig, - IDeviceEvent, IDeviceRemoval, IDnsOptions, IErrorState, @@ -41,6 +41,8 @@ import { ITunnelStateRelayInfo, IWireguardConstraints, IWireguardTunnelData, + LoggedInDeviceState, + LoggedOutDeviceState, ObfuscationType, ProxySettings, ProxyType, @@ -513,18 +515,9 @@ export class DaemonRpc { return response.getValue(); } - public async getDevice(): Promise<IDeviceConfig | undefined> { - try { - const response = await this.callEmpty<grpcTypes.DeviceConfig>(this.client.getDevice); - return convertFromDeviceConfig(response); - } catch (e) { - const error = e as grpc.ServiceError; - if (error.code === grpc.status.NOT_FOUND) { - return undefined; - } else { - throw error; - } - } + public async getDevice(): Promise<DeviceState> { + const response = await this.callEmpty<grpcTypes.DeviceState>(this.client.getDevice); + return convertFromDeviceState(response); } public async updateDevice(): Promise<void> { @@ -1409,21 +1402,40 @@ function convertToTransportProtocol(protocol: RelayProtocol): grpcTypes.Transpor } } -function convertFromDeviceEvent(deviceEvent: grpcTypes.DeviceEvent): IDeviceEvent { - return { - deviceConfig: convertFromDeviceConfig(deviceEvent.getDevice()), - remote: deviceEvent.getRemote(), - }; +function convertFromDeviceEvent(deviceEvent: grpcTypes.DeviceEvent): DeviceEvent { + const deviceState = convertFromDeviceState(deviceEvent.getNewState()!); + switch (deviceEvent.getCause()) { + case grpcTypes.DeviceEvent.Cause.LOGGED_IN: + return { type: 'logged in', deviceState: deviceState as LoggedInDeviceState }; + case grpcTypes.DeviceEvent.Cause.LOGGED_OUT: + return { type: 'logged out', deviceState: deviceState as LoggedOutDeviceState }; + case grpcTypes.DeviceEvent.Cause.REVOKED: + return { type: 'revoked', deviceState: deviceState as LoggedOutDeviceState }; + case grpcTypes.DeviceEvent.Cause.UPDATED: + return { type: 'updated', deviceState: deviceState as LoggedInDeviceState }; + case grpcTypes.DeviceEvent.Cause.ROTATED_KEY: + return { type: 'rotated_key', deviceState: deviceState as LoggedInDeviceState }; + } } -function convertFromDeviceConfig(deviceConfig?: grpcTypes.DeviceConfig): IDeviceConfig | undefined { - const device = deviceConfig?.getDevice(); - return ( - deviceConfig && { - accountToken: deviceConfig.getAccountToken(), - device: device ? convertFromDevice(device) : undefined, +function convertFromDeviceState(deviceState: grpcTypes.DeviceState): DeviceState { + switch (deviceState.getState()) { + case grpcTypes.DeviceState.State.LOGGED_IN: { + const accountAndDevice = deviceState.getDevice()!; + const device = accountAndDevice.getDevice(); + return { + type: 'logged in', + accountAndDevice: { + accountToken: accountAndDevice.getAccountToken(), + device: device && convertFromDevice(device), + }, + }; } - ); + case grpcTypes.DeviceState.State.LOGGED_OUT: + return { type: 'logged out' }; + case grpcTypes.DeviceState.State.REVOKED: + return { type: 'revoked' }; + } } function convertFromDeviceRemoval(deviceRemoval: grpcTypes.RemoveDeviceEvent): Array<IDevice> { diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts index c1fb5407f7..4d0f915bb9 100644 --- a/gui/src/main/index.ts +++ b/gui/src/main/index.ts @@ -27,10 +27,10 @@ import { BridgeSettings, BridgeState, DaemonEvent, + DeviceEvent, + DeviceState, IAccountData, IAppVersionInfo, - IDeviceConfig, - IDeviceEvent, IDeviceRemoval, IDnsOptions, IRelayList, @@ -206,8 +206,7 @@ class ApplicationMain { }, }, }; - private deviceConfig?: IDeviceConfig; - private hasReceivedDeviceConfig = false; + private deviceState?: DeviceState; private guiSettings = new GuiSettings(); private tunnelStateExpectation?: Expectation; @@ -681,10 +680,13 @@ class ApplicationMain { // fetch device try { - this.setDeviceConfig({ deviceConfig: await this.daemonRpc.getDevice() }); - void this.daemonRpc - .updateDevice() - .catch((error: Error) => log.warn(`Failed to update device info: ${error.message}`)); + const deviceState = await this.daemonRpc.getDevice(); + this.handleDeviceEvent({ type: deviceState.type, deviceState } as DeviceEvent); + if (deviceState.type === 'logged in') { + void this.daemonRpc + .updateDevice() + .catch((error: Error) => log.warn(`Failed to update device info: ${error.message}`)); + } } catch (e) { const error = e as Error; log.error(`Failed to fetch device: ${error.message}`); @@ -749,7 +751,7 @@ class ApplicationMain { } // show window when account is not set - if (!this.deviceConfig) { + if (!this.isLoggedIn()) { this.windowController?.show(); } }; @@ -822,7 +824,7 @@ class ApplicationMain { } else if ('appVersionInfo' in daemonEvent) { this.setLatestVersion(daemonEvent.appVersionInfo); } else if ('device' in daemonEvent) { - this.setDeviceConfig(daemonEvent.device); + this.handleDeviceEvent(daemonEvent.device); } else if ('deviceRemoval' in daemonEvent) { if (this.windowController) { IpcMainEventChannel.account.notifyDevices( @@ -854,26 +856,14 @@ class ApplicationMain { } private connectTunnel = async (): Promise<void> => { - if ( - connectEnabled( - this.connectedToDaemon, - this.deviceConfig?.accountToken, - this.tunnelState.state, - ) - ) { + if (connectEnabled(this.connectedToDaemon, this.isLoggedIn(), this.tunnelState.state)) { this.setOptimisticTunnelState('connecting'); await this.daemonRpc.connectTunnel(); } }; private reconnectTunnel = async (): Promise<void> => { - if ( - reconnectEnabled( - this.connectedToDaemon, - this.deviceConfig?.accountToken, - this.tunnelState.state, - ) - ) { + if (reconnectEnabled(this.connectedToDaemon, this.isLoggedIn(), this.tunnelState.state)) { this.setOptimisticTunnelState('connecting'); await this.daemonRpc.reconnectTunnel(); } @@ -1166,28 +1156,41 @@ class ApplicationMain { } } - private setDeviceConfig(deviceEvent: IDeviceEvent) { - const oldDeviceConfig = this.deviceConfig; - this.deviceConfig = deviceEvent.deviceConfig; - this.hasReceivedDeviceConfig = true; + private handleDeviceEvent(deviceEvent: DeviceEvent) { + this.deviceState = deviceEvent.deviceState; if (this.isPerformingPostUpgrade) { void this.performPostUpgradeCheck(); } - // make sure to invalidate the account data cache when account tokens change - this.updateAccountDataOnAccountChange( - oldDeviceConfig?.accountToken, - deviceEvent.deviceConfig?.accountToken, - ); + switch (deviceEvent.deviceState.type) { + case 'logged in': + this.accountDataCache.fetch(deviceEvent.deviceState.accountAndDevice.accountToken); + break; + case 'logged out': + case 'revoked': + this.accountDataCache.invalidate(); + break; + } void this.updateAccountHistory(); + this.setTrayContextMenu(); if (this.windowController) { IpcMainEventChannel.account.notifyDevice(this.windowController.webContents, deviceEvent); } } + private isLoggedIn(): boolean { + return this.deviceState?.type === 'logged in'; + } + + private getAccountToken(): AccountToken | undefined { + return this.deviceState?.type === 'logged in' + ? this.deviceState.accountAndDevice.accountToken + : undefined; + } + private trayIconType(tunnelState: TunnelState, blockWhenDisconnected: boolean): TrayIconType { switch (tunnelState.state) { case 'connected': @@ -1270,8 +1273,7 @@ class ApplicationMain { tunnelState: this.tunnelState, settings: this.settings, isPerformingPostUpgrade: this.isPerformingPostUpgrade, - deviceConfig: this.deviceConfig, - hasReceivedDeviceConfig: this.hasReceivedDeviceConfig, + deviceState: this.deviceState, relayListPair: { relays: this.processRelaysForPresentation(this.relays, this.settings.relaySettings), bridges: this.processBridgesForPresentation(this.relays, this.settings.bridgeState), @@ -1363,7 +1365,7 @@ class ApplicationMain { IpcMainEventChannel.account.handleLogout(() => this.logout()); IpcMainEventChannel.account.handleGetWwwAuthToken(() => this.daemonRpc.getWwwAuthToken()); IpcMainEventChannel.account.handleSubmitVoucher(async (voucherCode: string) => { - const currentAccountToken = this.deviceConfig?.accountToken; + const currentAccountToken = this.getAccountToken(); const response = await this.daemonRpc.submitVoucher(voucherCode); if (currentAccountToken) { @@ -1374,9 +1376,9 @@ class ApplicationMain { }); IpcMainEventChannel.account.handleUpdateData(() => this.updateAccountData()); - IpcMainEventChannel.account.handleGetDevice(async () => { - const deviceConfig = await this.daemonRpc.getDevice(); - return deviceConfig?.device; + IpcMainEventChannel.account.handleGetDeviceState(async () => { + await this.daemonRpc.updateDevice(); + return this.daemonRpc.getDevice(); }); IpcMainEventChannel.account.handleListDevices((accountToken: AccountToken) => { return this.daemonRpc.listDevices(accountToken); @@ -1540,7 +1542,7 @@ class ApplicationMain { private async autoConnect() { if (process.env.NODE_ENV === 'development') { log.info('Skip autoconnect in development'); - } else if (this.deviceConfig && (!this.accountData || !hasExpired(this.accountData.expiry))) { + } else if (this.isLoggedIn() && (!this.accountData || !hasExpired(this.accountData.expiry))) { if (this.guiSettings.autoConnect) { try { log.info('Autoconnect the tunnel'); @@ -1571,21 +1573,9 @@ class ApplicationMain { } } - private updateAccountDataOnAccountChange(oldAccount?: string, newAccount?: string) { - if (oldAccount && !newAccount) { - this.accountDataCache.invalidate(); - } else if (!oldAccount && newAccount) { - this.accountDataCache.fetch(newAccount); - } else if (oldAccount && newAccount && oldAccount !== newAccount) { - this.accountDataCache.fetch(newAccount); - } - - this.setTrayContextMenu(); - } - private updateAccountData() { - if (this.connectedToDaemon && this.deviceConfig) { - this.accountDataCache.fetch(this.deviceConfig.accountToken); + if (this.connectedToDaemon && this.isLoggedIn()) { + this.accountDataCache.fetch(this.getAccountToken()!); } } @@ -1971,7 +1961,7 @@ class ApplicationMain { this.tray?.on('right-click', () => this.trayIconController?.popUpContextMenu( this.connectedToDaemon, - this.deviceConfig?.accountToken, + this.isLoggedIn(), this.tunnelState, ), ); @@ -2009,7 +1999,7 @@ class ApplicationMain { private setTrayContextMenu() { this.trayIconController?.setContextMenu( this.connectedToDaemon, - this.deviceConfig?.accountToken, + this.isLoggedIn(), this.tunnelState, ); } diff --git a/gui/src/main/tray-icon-controller.ts b/gui/src/main/tray-icon-controller.ts index 81af2e174e..723228eac6 100644 --- a/gui/src/main/tray-icon-controller.ts +++ b/gui/src/main/tray-icon-controller.ts @@ -5,7 +5,7 @@ import { sprintf } from 'sprintf-js'; import { promisify } from 'util'; import { connectEnabled, disconnectEnabled, reconnectEnabled } from '../shared/connect-helper'; -import { AccountToken, ILocation, TunnelState } from '../shared/daemon-rpc-types'; +import { ILocation, TunnelState } from '../shared/daemon-rpc-types'; import { messages, relayLocations } from '../shared/gettext'; import log from '../shared/logging'; import KeyframeAnimation from './keyframe-animation'; @@ -102,15 +102,9 @@ export default class TrayIconController { animation.play({ end: frame }); } - public setContextMenu( - connectedToDaemon: boolean, - accountToken: AccountToken | undefined, - tunnelState: TunnelState, - ) { + public setContextMenu(connectedToDaemon: boolean, loggedIn: boolean, tunnelState: TunnelState) { if (process.platform === 'linux') { - this.tray.setContextMenu( - this.createContextMenu(connectedToDaemon, accountToken, tunnelState), - ); + this.tray.setContextMenu(this.createContextMenu(connectedToDaemon, loggedIn, tunnelState)); } } @@ -119,14 +113,8 @@ export default class TrayIconController { this.tray?.setToolTip(tooltip); } - public popUpContextMenu( - connectedToDaemon: boolean, - accountToken: AccountToken | undefined, - tunnelState: TunnelState, - ) { - this.tray.popUpContextMenu( - this.createContextMenu(connectedToDaemon, accountToken, tunnelState), - ); + public popUpContextMenu(connectedToDaemon: boolean, loggedIn: boolean, tunnelState: TunnelState) { + this.tray.popUpContextMenu(this.createContextMenu(connectedToDaemon, loggedIn, tunnelState)); } private createTooltipText(connectedToDaemon: boolean, tunnelState: TunnelState): string { @@ -267,7 +255,7 @@ export default class TrayIconController { private createContextMenu( connectedToDaemon: boolean, - accountToken: AccountToken | undefined, + loggedIn: boolean, tunnelState: TunnelState, ) { const template: Electron.MenuItemConstructorOptions[] = [ @@ -281,13 +269,13 @@ export default class TrayIconController { { id: 'connect', label: messages.gettext('Connect'), - enabled: connectEnabled(connectedToDaemon, accountToken, tunnelState.state), + enabled: connectEnabled(connectedToDaemon, loggedIn, tunnelState.state), click: this.connect, }, { id: 'reconnect', label: messages.gettext('Reconnect'), - enabled: reconnectEnabled(connectedToDaemon, accountToken, tunnelState.state), + enabled: reconnectEnabled(connectedToDaemon, loggedIn, tunnelState.state), click: this.reconnect, }, { diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index d6911da317..886a83d8d7 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -7,11 +7,11 @@ import { AccountToken, BridgeSettings, BridgeState, + DeviceEvent, + DeviceState, IAccountData, IAppVersionInfo, IDevice, - IDeviceConfig, - IDeviceEvent, IDeviceRemoval, IDnsOptions, ILocation, @@ -100,8 +100,7 @@ export default class AppRenderer { private relayListPair!: IRelayListPair; private tunnelState!: TunnelState; private settings!: ISettings; - private deviceConfig?: IDeviceConfig; - private hasReceivedDeviceConfig = false; + private deviceState?: DeviceState; private guiSettings!: IGuiSettingsState; private loginState: LoginState = 'none'; private previousLoginState: LoginState = 'none'; @@ -136,9 +135,7 @@ export default class AppRenderer { }); IpcRendererEventChannel.account.listenDevice((deviceEvent) => { - const oldDeviceConfig = this.deviceConfig; - this.hasReceivedDeviceConfig = true; - this.handleAccountChange(deviceEvent, oldDeviceConfig?.accountToken); + this.handleDeviceEvent(deviceEvent); }); IpcRendererEventChannel.account.listenDevices((devices) => { @@ -213,12 +210,15 @@ export default class AppRenderer { this.setAccountExpiry(initialState.accountData?.expiry); this.setSettings(initialState.settings); this.setIsPerformingPostUpgrade(initialState.isPerformingPostUpgrade); - this.handleAccountChange( - { deviceConfig: initialState.deviceConfig }, - undefined, - initialState.navigationHistory !== undefined, - ); - this.hasReceivedDeviceConfig = initialState.hasReceivedDeviceConfig; + + if (initialState.deviceState) { + const deviceState = initialState.deviceState; + this.handleDeviceEvent( + { type: deviceState.type, deviceState } as DeviceEvent, + initialState.navigationHistory !== undefined, + ); + } + this.setAccountHistory(initialState.accountHistory); this.setTunnelState(initialState.tunnelState); this.updateBlockedState(initialState.tunnelState, initialState.settings.blockWhenDisconnected); @@ -363,8 +363,8 @@ export default class AppRenderer { IpcRendererEventChannel.account.updateData(); } - public getDevice = (): Promise<IDevice | undefined> => { - return IpcRendererEventChannel.account.getDevice(); + public getDeviceState = (): Promise<DeviceState> => { + return IpcRendererEventChannel.account.getDeviceState(); }; public fetchDevices = async (accountToken: AccountToken): Promise<Array<IDevice>> => { @@ -589,6 +589,10 @@ export default class AppRenderer { IpcRendererEventChannel.navigation.setScrollPositions(scrollPositions); } + private isLoggedIn(): boolean { + return this.deviceState?.type === 'logged in'; + } + // Make sure that the content height is correct and log if it isn't. This is mostly for debugging // purposes since there's a bug in Electron that causes the app height to be another value than // the one we have set. @@ -735,13 +739,13 @@ export default class AppRenderer { } private getNavigationBase(): RoutePath { - if (this.connectedToDaemon && this.hasReceivedDeviceConfig) { + if (this.connectedToDaemon && this.deviceState !== undefined) { const loginState = this.reduxStore.getState().account.status; const deviceRevoked = loginState.type === 'none' && loginState.deviceRevoked; if (deviceRevoked) { return RoutePath.deviceRevoked; - } else if (this.deviceConfig?.accountToken) { + } else if (this.isLoggedIn()) { return RoutePath.main; } else { return RoutePath.login; @@ -838,48 +842,54 @@ export default class AppRenderer { } } - private handleAccountChange( - newDeviceEvent: IDeviceEvent, - oldAccount?: string, - preventRedirectToConnect?: boolean, - ) { + private handleDeviceEvent(deviceEvent: DeviceEvent, preventRedirectToConnect?: boolean) { const reduxAccount = this.reduxActions.account; - this.deviceConfig = newDeviceEvent.deviceConfig; - const newAccount = newDeviceEvent.deviceConfig?.accountToken; - const newDevice = newDeviceEvent.deviceConfig?.device; + this.deviceState = deviceEvent.deviceState; - if (oldAccount && !newAccount) { - this.loginScheduler.cancel(); - if (!this.reduxStore.getState().account.loggingOut && newDeviceEvent.remote) { - reduxAccount.deviceRevoked(); - } else { - reduxAccount.loggedOut(); - } + switch (deviceEvent.type) { + case 'logged in': { + const accountToken = deviceEvent.deviceState.accountAndDevice.accountToken; + const device = deviceEvent.deviceState.accountAndDevice.device; - this.resetNavigation(); - } else if (newAccount !== undefined && newDevice !== undefined && oldAccount !== newAccount) { - switch (this.loginState) { - case 'none': - case 'logging in': - reduxAccount.loggedIn({ accountToken: newAccount, device: newDevice }); + switch (this.loginState) { + case 'none': + case 'logging in': + reduxAccount.loggedIn(accountToken, device); - if (this.previousLoginState === 'too many devices') { - this.resetNavigation(); - } else if (!preventRedirectToConnect) { - this.redirectToConnect(); - } - break; - case 'creating account': - reduxAccount.accountCreated( - { accountToken: newAccount, device: newDevice }, - new Date().toISOString(), - ); - break; + if (this.previousLoginState === 'too many devices') { + this.resetNavigation(); + } else if (!preventRedirectToConnect) { + this.redirectToConnect(); + } + break; + case 'creating account': + reduxAccount.accountCreated(accountToken, device, new Date().toISOString()); + break; + } + + if (this.loginState !== 'logging in' && this.loginState !== 'creating account') { + this.resetNavigation(); + } + break; } + case 'logged out': + this.loginScheduler.cancel(); + reduxAccount.loggedOut(); + this.resetNavigation(); + break; + case 'revoked': { + this.loginScheduler.cancel(); + + const oldAccountState = this.reduxStore.getState().account; + if (oldAccountState.loggingOut) { + reduxAccount.loggedOut(); + } else { + reduxAccount.deviceRevoked(); + } - if (this.loginState !== 'logging in' && this.loginState !== 'creating account') { this.resetNavigation(); + break; } } diff --git a/gui/src/renderer/components/Account.tsx b/gui/src/renderer/components/Account.tsx index af714273af..e0596a2b79 100644 --- a/gui/src/renderer/components/Account.tsx +++ b/gui/src/renderer/components/Account.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { formatDate, hasExpired } from '../../shared/account-expiry'; -import { AccountToken, IDevice } from '../../shared/daemon-rpc-types'; +import { AccountToken, DeviceState } from '../../shared/daemon-rpc-types'; import { messages } from '../../shared/gettext'; import { AccountContainer, @@ -39,7 +39,7 @@ interface IProps { onClose: () => void; onBuyMore: () => Promise<void>; updateAccountData: () => void; - getDevice: () => Promise<IDevice | undefined>; + getDeviceState: () => Promise<DeviceState | undefined>; } interface IState { @@ -189,10 +189,12 @@ export default class Account extends React.Component<IProps, IState> { this.setState({ logoutDialogState: 'checking-ports' }); this.props.prepareLogout(); - const device = await this.props.getDevice(); - if (device === undefined) { - this.onHideLogoutConfirmationDialog(); - } else if (device.ports !== undefined && device.ports.length > 0) { + const deviceState = await this.props.getDeviceState(); + if ( + deviceState?.type === 'logged in' && + deviceState.accountAndDevice.device?.ports !== undefined && + deviceState.accountAndDevice.device.ports.length > 0 + ) { this.setState({ logoutDialogState: 'confirm' }); } else { this.props.onLogout(); diff --git a/gui/src/renderer/containers/AccountPage.tsx b/gui/src/renderer/containers/AccountPage.tsx index a813b12002..a81676c48b 100644 --- a/gui/src/renderer/containers/AccountPage.tsx +++ b/gui/src/renderer/containers/AccountPage.tsx @@ -29,7 +29,7 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, props: IHistoryProps & IApp }, onBuyMore: () => props.app.openLinkWithAuth(links.purchase), updateAccountData: () => props.app.updateAccountData(), - getDevice: () => props.app.getDevice(), + getDeviceState: () => props.app.getDeviceState(), }; }; diff --git a/gui/src/renderer/redux/account/actions.ts b/gui/src/renderer/redux/account/actions.ts index ba9d524cc0..cfa672a407 100644 --- a/gui/src/renderer/redux/account/actions.ts +++ b/gui/src/renderer/redux/account/actions.ts @@ -1,4 +1,4 @@ -import { AccountToken, IDevice, IDeviceConfig } from '../../../shared/daemon-rpc-types'; +import { AccountToken, IDevice } from '../../../shared/daemon-rpc-types'; interface IStartLoginAction { type: 'START_LOGIN'; @@ -107,11 +107,11 @@ function startLogin(accountToken: AccountToken): IStartLoginAction { }; } -function loggedIn(deviceConfig: IDeviceConfig): ILoggedInAction { +function loggedIn(accountToken: AccountToken, device?: IDevice): ILoggedInAction { return { type: 'LOGGED_IN', - accountToken: deviceConfig.accountToken, - deviceName: deviceConfig.device?.name, + accountToken, + deviceName: device?.name, }; } @@ -172,11 +172,15 @@ function createAccountFailed(error: Error): ICreateAccountFailed { }; } -function accountCreated(deviceConfig: IDeviceConfig, expiry: string): IAccountCreated { +function accountCreated( + accountToken: AccountToken, + device: IDevice | undefined, + expiry: string, +): IAccountCreated { return { type: 'ACCOUNT_CREATED', - accountToken: deviceConfig.accountToken, - deviceName: deviceConfig.device?.name, + accountToken: accountToken, + deviceName: device?.name, expiry, }; } diff --git a/gui/src/shared/connect-helper.ts b/gui/src/shared/connect-helper.ts index b1421cd8ef..d5c563c7ca 100644 --- a/gui/src/shared/connect-helper.ts +++ b/gui/src/shared/connect-helper.ts @@ -1,28 +1,24 @@ -import { AccountToken, TunnelState } from './daemon-rpc-types'; +import { TunnelState } from './daemon-rpc-types'; export function connectEnabled( connectedToDaemon: boolean, - accountToken: AccountToken | undefined, + loggedIn: boolean, tunnelState: TunnelState['state'], ) { return ( connectedToDaemon && - accountToken !== undefined && - accountToken !== '' && + loggedIn && (tunnelState === 'disconnected' || tunnelState === 'disconnecting' || tunnelState === 'error') ); } export function reconnectEnabled( connectedToDaemon: boolean, - accountToken: AccountToken | undefined, + loggedIn: boolean, tunnelState: TunnelState['state'], ) { return ( - connectedToDaemon && - accountToken !== undefined && - accountToken !== '' && - (tunnelState === 'connected' || tunnelState === 'connecting') + connectedToDaemon && loggedIn && (tunnelState === 'connected' || tunnelState === 'connecting') ); } diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts index d1eab9cdce..aad35a01f4 100644 --- a/gui/src/shared/daemon-rpc-types.ts +++ b/gui/src/shared/daemon-rpc-types.ts @@ -114,7 +114,7 @@ export type DaemonEvent = | { settings: ISettings } | { relayList: IRelayList } | { appVersionInfo: IAppVersionInfo } - | { device: IDeviceEvent } + | { device: DeviceEvent } | { deviceRemoval: Array<IDevice> }; export interface ITunnelStateRelayInfo { @@ -333,16 +333,20 @@ export interface IAppVersionInfo { suggestedIsBeta?: boolean; } -export interface IDeviceEvent { - deviceConfig?: IDeviceConfig; - remote?: boolean; -} - -export interface IDeviceConfig { +export interface IAccountAndDevice { accountToken: AccountToken; device?: IDevice; } +export type LoggedInDeviceState = { type: 'logged in'; accountAndDevice: IAccountAndDevice }; +export type LoggedOutDeviceState = { type: 'logged out' | 'revoked' }; + +export type DeviceState = LoggedInDeviceState | LoggedOutDeviceState; + +export type DeviceEvent = + | { type: 'logged in' | 'updated' | 'rotated_key'; deviceState: LoggedInDeviceState } + | { type: 'logged out' | 'revoked'; deviceState: LoggedOutDeviceState }; + export interface IDevice { id: string; name: string; diff --git a/gui/src/shared/ipc-schema.ts b/gui/src/shared/ipc-schema.ts index e09d552c25..cbe29ee783 100644 --- a/gui/src/shared/ipc-schema.ts +++ b/gui/src/shared/ipc-schema.ts @@ -5,11 +5,11 @@ import { AccountToken, BridgeSettings, BridgeState, + DeviceEvent, + DeviceState, IAccountData, IAppVersionInfo, IDevice, - IDeviceConfig, - IDeviceEvent, IDeviceRemoval, IDnsOptions, ILocation, @@ -62,8 +62,7 @@ export interface IAppStateSnapshot { tunnelState: TunnelState; settings: ISettings; isPerformingPostUpgrade: boolean; - deviceConfig?: IDeviceConfig; - hasReceivedDeviceConfig: boolean; + deviceState?: DeviceState; relayListPair: IRelayListPair; currentVersion: ICurrentAppVersionInfo; upgradeVersion: IAppVersionInfo; @@ -182,7 +181,7 @@ export const ipcSchema = { }, account: { '': notifyRenderer<IAccountData | undefined>(), - device: notifyRenderer<IDeviceEvent>(), + device: notifyRenderer<DeviceEvent>(), devices: notifyRenderer<Array<IDevice>>(), create: invoke<void, string>(), login: invoke<AccountToken, void>(), @@ -190,7 +189,7 @@ export const ipcSchema = { getWwwAuthToken: invoke<void, string>(), submitVoucher: invoke<string, VoucherResponse>(), updateData: send<void>(), - getDevice: invoke<void, IDevice | undefined>(), + getDeviceState: invoke<void, DeviceState>(), listDevices: invoke<AccountToken, Array<IDevice>>(), removeDevice: invoke<IDeviceRemoval, void>(), }, |
