diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-11-03 02:02:09 +0100 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2022-03-14 13:58:44 +0100 |
| commit | 46fa74ad03658ad0afa9dc984565b7f10106af94 (patch) | |
| tree | e271c92db8c2f06db457548f3ebb95ef97a4ab09 /gui/src | |
| parent | 7c23c00a45d4a9342c69211d23ef8f8fd634725a (diff) | |
| download | mullvadvpn-46fa74ad03658ad0afa9dc984565b7f10106af94.tar.xz mullvadvpn-46fa74ad03658ad0afa9dc984565b7f10106af94.zip | |
Replace account token in settings event with device event
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/main/daemon-rpc.ts | 14 | ||||
| -rw-r--r-- | gui/src/main/index.ts | 49 | ||||
| -rw-r--r-- | gui/src/renderer/app.tsx | 64 | ||||
| -rw-r--r-- | gui/src/renderer/components/ExpiredAccountAddTime.tsx | 6 | ||||
| -rw-r--r-- | gui/src/renderer/redux/account/actions.ts | 32 | ||||
| -rw-r--r-- | gui/src/renderer/redux/account/reducers.ts | 13 | ||||
| -rw-r--r-- | gui/src/shared/daemon-rpc-types.ts | 14 | ||||
| -rw-r--r-- | gui/src/shared/ipc-schema.ts | 3 |
8 files changed, 144 insertions, 51 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts index e0c3c8bf60..eab5559ad3 100644 --- a/gui/src/main/daemon-rpc.ts +++ b/gui/src/main/daemon-rpc.ts @@ -46,6 +46,7 @@ import { VoucherResponse, TunnelProtocol, IDnsOptions, + IDeviceConfig, } from '../shared/daemon-rpc-types'; import log from '../shared/logging'; @@ -1107,6 +1108,11 @@ function convertFromDaemonEvent(data: grpcTypes.DaemonEvent): DaemonEvent { }; } + const deviceConfig = data.getDevice(); + if (deviceConfig !== undefined) { + return { deviceConfig: convertFromDeviceConfig(deviceConfig) }; + } + return { appVersionInfo: data.getVersionInfo()!.toObject(), }; @@ -1307,6 +1313,14 @@ function convertToTransportProtocol(protocol: RelayProtocol): grpcTypes.Transpor } } +function convertFromDeviceConfig(deviceEvent: grpcTypes.DeviceEvent): IDeviceConfig { + const deviceConfig = deviceEvent.getDevice(); + return { + accountToken: deviceConfig?.getAccountToken(), + device: deviceConfig?.getDevice()?.toObject(), + }; +} + function ensureExists<T>(value: T | undefined, errorMessage: string): T { if (value) { return value; diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts index 774343b7aa..07afda535c 100644 --- a/gui/src/main/index.ts +++ b/gui/src/main/index.ts @@ -27,6 +27,7 @@ import { DaemonEvent, IAccountData, IAppVersionInfo, + IDeviceConfig, IDnsOptions, IRelayList, ISettings, @@ -141,7 +142,6 @@ class ApplicationMain { private tunnelStateFallbackScheduler = new Scheduler(); private settings: ISettings = { - accountToken: undefined, allowLan: false, autoConnect: false, blockWhenDisconnected: false, @@ -197,6 +197,7 @@ class ApplicationMain { }, }, }; + private deviceConfig: IDeviceConfig = { accountToken: undefined, device: undefined }; private guiSettings = new GuiSettings(); private tunnelStateExpectation?: Expectation; @@ -696,7 +697,7 @@ class ApplicationMain { } // show window when account is not set - if (!this.settings.accountToken) { + if (!this.deviceConfig.accountToken) { this.windowController?.show(); } }; @@ -767,6 +768,8 @@ class ApplicationMain { ); } else if ('appVersionInfo' in daemonEvent) { this.setLatestVersion(daemonEvent.appVersionInfo); + } else if ('deviceConfig' in daemonEvent) { + this.setDeviceConfig(daemonEvent.deviceConfig); } }, (error: Error) => { @@ -782,7 +785,11 @@ class ApplicationMain { private connectTunnel = async (): Promise<void> => { if ( - connectEnabled(this.connectedToDaemon, this.settings.accountToken, this.tunnelState.state) + connectEnabled( + this.connectedToDaemon, + this.deviceConfig?.accountToken, + this.tunnelState.state, + ) ) { this.setOptimisticTunnelState('connecting'); await this.daemonRpc.connectTunnel(); @@ -791,7 +798,11 @@ class ApplicationMain { private reconnectTunnel = async (): Promise<void> => { if ( - reconnectEnabled(this.connectedToDaemon, this.settings.accountToken, this.tunnelState.state) + reconnectEnabled( + this.connectedToDaemon, + this.deviceConfig?.accountToken, + this.tunnelState.state, + ) ) { this.setOptimisticTunnelState('connecting'); await this.daemonRpc.reconnectTunnel(); @@ -881,13 +892,6 @@ class ApplicationMain { this.updateTrayIcon(this.tunnelState, newSettings.blockWhenDisconnected); - // make sure to invalidate the account data cache when account tokens change - this.updateAccountDataOnAccountChange(oldSettings.accountToken, newSettings.accountToken); - - if (oldSettings.accountToken !== newSettings.accountToken) { - void this.updateAccountHistory(); - } - if (oldSettings.showBetaReleases !== newSettings.showBetaReleases) { this.setLatestVersion(this.upgradeVersion); } @@ -1091,6 +1095,16 @@ class ApplicationMain { } } + private setDeviceConfig(deviceConfig: IDeviceConfig) { + const oldDeviceConfig = this.deviceConfig; + this.deviceConfig = deviceConfig; + + // make sure to invalidate the account data cache when account tokens change + this.updateAccountDataOnAccountChange(oldDeviceConfig.accountToken, deviceConfig.accountToken); + + void this.updateAccountHistory(); + } + private trayIconType(tunnelState: TunnelState, blockWhenDisconnected: boolean): TrayIconType { switch (tunnelState.state) { case 'connected': @@ -1172,6 +1186,7 @@ class ApplicationMain { accountHistory: this.accountHistory, tunnelState: this.tunnelState, settings: this.settings, + deviceConfig: this.deviceConfig, relayListPair: { relays: this.processRelaysForPresentation(this.relays, this.settings.relaySettings), bridges: this.processBridgesForPresentation(this.relays, this.settings.bridgeState), @@ -1261,7 +1276,7 @@ class ApplicationMain { IpcMainEventChannel.account.handleLogout(() => this.logout()); IpcMainEventChannel.account.handleGetWwwAuthToken(() => this.daemonRpc.getWwwAuthToken()); IpcMainEventChannel.account.handleSubmitVoucher(async (voucherCode: string) => { - const currentAccountToken = this.settings.accountToken; + const currentAccountToken = this.deviceConfig.accountToken; const response = await this.daemonRpc.submitVoucher(voucherCode); if (currentAccountToken) { @@ -1453,7 +1468,7 @@ class ApplicationMain { if (process.env.NODE_ENV === 'development') { log.info('Skip autoconnect in development'); } else if ( - this.settings.accountToken && + this.deviceConfig.accountToken && (!this.accountData || !hasExpired(this.accountData.expiry)) ) { if (this.guiSettings.autoConnect) { @@ -1515,8 +1530,8 @@ class ApplicationMain { } private updateAccountData() { - if (this.connectedToDaemon && this.settings.accountToken) { - this.accountDataCache.fetch(this.settings.accountToken); + if (this.connectedToDaemon && this.deviceConfig.accountToken) { + this.accountDataCache.fetch(this.deviceConfig.accountToken); } } @@ -1901,7 +1916,7 @@ class ApplicationMain { this.tray?.on('right-click', () => this.trayIconController?.popUpContextMenu( this.connectedToDaemon, - this.settings.accountToken, + this.deviceConfig?.accountToken, this.tunnelState, ), ); @@ -1939,7 +1954,7 @@ class ApplicationMain { private setTrayContextMenu() { this.trayIconController?.setContextMenu( this.connectedToDaemon, - this.settings.accountToken, + this.deviceConfig?.accountToken, this.tunnelState, ); } diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index 8abb47af79..ff46b76f1a 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -31,6 +31,7 @@ import { BridgeState, IAccountData, IAppVersionInfo, + IDeviceConfig, IDnsOptions, ILocation, ISettings, @@ -92,8 +93,9 @@ export default class AppRenderer { private relayListPair!: IRelayListPair; private tunnelState!: TunnelState; private settings!: ISettings; + private deviceConfig!: IDeviceConfig; private guiSettings!: IGuiSettingsState; - private doingLogin = false; + private loginState: 'none' | 'logging in' | 'creating account' = 'none'; private loginScheduler = new Scheduler(); private connectedToDaemon = false; private getLocationPromise?: Promise<ILocation>; @@ -120,6 +122,12 @@ export default class AppRenderer { this.setAccountExpiry(newAccountData?.expiry); }); + IpcRendererEventChannel.account.listenDevice((deviceConfig: IDeviceConfig) => { + const oldDeviceConfig = this.deviceConfig; + this.deviceConfig = deviceConfig; + this.handleAccountChange(deviceConfig, oldDeviceConfig.accountToken); + }); + IpcRendererEventChannel.accountHistory.listen((newAccountHistory?: AccountToken) => { this.setAccountHistory(newAccountHistory); }); @@ -130,10 +138,7 @@ export default class AppRenderer { }); IpcRendererEventChannel.settings.listen((newSettings: ISettings) => { - const oldSettings = this.settings; - this.setSettings(newSettings); - this.handleAccountChange(oldSettings.accountToken, newSettings.accountToken); this.updateBlockedState(this.tunnelState, newSettings.blockWhenDisconnected); }); @@ -190,7 +195,7 @@ export default class AppRenderer { this.setAccountExpiry(initialState.accountData?.expiry); this.setSettings(initialState.settings); - this.handleAccountChange(undefined, initialState.settings.accountToken); + this.handleAccountChange(initialState.deviceConfig, undefined); this.setAccountHistory(initialState.accountHistory); this.setTunnelState(initialState.tunnelState); this.updateBlockedState(initialState.tunnelState, initialState.settings.blockWhenDisconnected); @@ -227,7 +232,7 @@ export default class AppRenderer { const navigationBase = this.getNavigationBase( initialState.isConnected, - initialState.settings.accountToken, + initialState.deviceConfig.accountToken, ); this.history = new History(navigationBase); } @@ -258,12 +263,10 @@ export default class AppRenderer { log.info('Logging in'); - this.doingLogin = true; + this.loginState = 'logging in'; try { await IpcRendererEventChannel.account.login(accountToken); - actions.account.updateAccountToken(accountToken); - actions.account.loggedIn(); this.redirectToConnect(); } catch (e) { const error = e as Error; @@ -285,12 +288,10 @@ export default class AppRenderer { const actions = this.reduxActions; actions.account.startCreateAccount(); - this.doingLogin = true; + this.loginState = 'creating account'; try { - const accountToken = await IpcRendererEventChannel.account.create(); - const accountExpiry = new Date().toISOString(); - actions.account.accountCreated(accountToken, accountExpiry); + await IpcRendererEventChannel.account.create(); this.redirectToConnect(); } catch (e) { const error = e as Error; @@ -612,7 +613,10 @@ export default class AppRenderer { private resetNavigation() { if (this.history) { const pathname = this.history.location.pathname; - const nextPath = this.getNavigationBase(this.connectedToDaemon, this.settings.accountToken); + const nextPath = this.getNavigationBase( + this.connectedToDaemon, + this.deviceConfig.accountToken, + ); // First level contains the possible next locations and the second level contains the possible // current locations. @@ -733,22 +737,44 @@ export default class AppRenderer { } } - private handleAccountChange(oldAccount?: string, newAccount?: string) { + private handleAccountChange(newDeviceConfig: IDeviceConfig, oldAccount?: string) { const reduxAccount = this.reduxActions.account; + const newAccount = newDeviceConfig.accountToken; + if (oldAccount && !newAccount) { this.loginScheduler.cancel(); reduxAccount.loggedOut(); this.resetNavigation(); - } else if (newAccount && oldAccount !== newAccount && !this.doingLogin) { - reduxAccount.updateAccountToken(newAccount); - reduxAccount.loggedIn(); + } else if ( + newDeviceConfig.accountToken !== undefined && + newDeviceConfig.device !== undefined && + oldAccount !== newAccount + ) { + switch (this.loginState) { + case 'none': + case 'logging in': + reduxAccount.loggedIn({ + accountToken: newDeviceConfig.accountToken, + device: newDeviceConfig.device, + }); + break; + case 'creating account': + reduxAccount.accountCreated( + { + accountToken: newDeviceConfig.accountToken, + device: newDeviceConfig.device, + }, + new Date().toISOString(), + ); + break; + } this.resetNavigation(); } - this.doingLogin = false; + this.loginState = 'none'; } private setLocation(location: Partial<ILocation>) { diff --git a/gui/src/renderer/components/ExpiredAccountAddTime.tsx b/gui/src/renderer/components/ExpiredAccountAddTime.tsx index fa98b1df59..47939b8c65 100644 --- a/gui/src/renderer/components/ExpiredAccountAddTime.tsx +++ b/gui/src/renderer/components/ExpiredAccountAddTime.tsx @@ -273,7 +273,7 @@ function HeaderBar() { } function useFinishedCallback() { - const { loggedIn } = useActions(account); + const { accountSetupFinished } = useActions(account); const history = useHistory(); const isNewAccount = useSelector( @@ -283,11 +283,11 @@ function useFinishedCallback() { const callback = useCallback(() => { // Changes login method from "new_account" to "existing_account" if (isNewAccount) { - loggedIn(); + accountSetupFinished(); } history.reset(RoutePath.main, undefined, transitions.push); - }, [isNewAccount, loggedIn, history]); + }, [isNewAccount, accountSetupFinished, history]); return callback; } diff --git a/gui/src/renderer/redux/account/actions.ts b/gui/src/renderer/redux/account/actions.ts index b8fbe94d39..ebc63e322c 100644 --- a/gui/src/renderer/redux/account/actions.ts +++ b/gui/src/renderer/redux/account/actions.ts @@ -1,4 +1,4 @@ -import { AccountToken } from '../../../shared/daemon-rpc-types'; +import { AccountToken, IDeviceConfig } from '../../../shared/daemon-rpc-types'; interface IStartLoginAction { type: 'START_LOGIN'; @@ -7,6 +7,8 @@ interface IStartLoginAction { interface ILoggedInAction { type: 'LOGGED_IN'; + accountToken: AccountToken; + deviceName: string; } interface ILoginFailedAction { @@ -33,13 +35,18 @@ interface ICreateAccountFailed { interface IAccountCreated { type: 'ACCOUNT_CREATED'; - token: AccountToken; + accountToken: AccountToken; + deviceName: string; expiry: string; } +interface IAccountSetupFinished { + type: 'ACCOUNT_SETUP_FINISHED'; +} + interface IUpdateAccountTokenAction { type: 'UPDATE_ACCOUNT_TOKEN'; - token: AccountToken; + accountToken: AccountToken; } interface IUpdateAccountHistoryAction { @@ -61,6 +68,7 @@ export type AccountAction = | IStartCreateAccount | ICreateAccountFailed | IAccountCreated + | IAccountSetupFinished | IUpdateAccountTokenAction | IUpdateAccountHistoryAction | IUpdateAccountExpiryAction; @@ -72,9 +80,11 @@ function startLogin(accountToken: AccountToken): IStartLoginAction { }; } -function loggedIn(): ILoggedInAction { +function loggedIn(deviceConfig: Required<IDeviceConfig>): ILoggedInAction { return { type: 'LOGGED_IN', + accountToken: deviceConfig.accountToken, + deviceName: deviceConfig.device.name, }; } @@ -110,18 +120,23 @@ function createAccountFailed(error: Error): ICreateAccountFailed { }; } -function accountCreated(token: AccountToken, expiry: string): IAccountCreated { +function accountCreated(deviceConfig: Required<IDeviceConfig>, expiry: string): IAccountCreated { return { type: 'ACCOUNT_CREATED', - token, + accountToken: deviceConfig.accountToken, + deviceName: deviceConfig.device.name, expiry, }; } -function updateAccountToken(token: AccountToken): IUpdateAccountTokenAction { +function accountSetupFinished(): IAccountSetupFinished { + return { type: 'ACCOUNT_SETUP_FINISHED' }; +} + +function updateAccountToken(accountToken: AccountToken): IUpdateAccountTokenAction { return { type: 'UPDATE_ACCOUNT_TOKEN', - token, + accountToken, }; } @@ -148,6 +163,7 @@ export default { startCreateAccount, createAccountFailed, accountCreated, + accountSetupFinished, updateAccountToken, updateAccountHistory, updateAccountExpiry, diff --git a/gui/src/renderer/redux/account/reducers.ts b/gui/src/renderer/redux/account/reducers.ts index 53bc55db1b..39b3a1a525 100644 --- a/gui/src/renderer/redux/account/reducers.ts +++ b/gui/src/renderer/redux/account/reducers.ts @@ -8,6 +8,7 @@ export type LoginState = | { type: 'failed'; method: LoginMethod; error: Error }; export interface IAccountReduxState { accountToken?: AccountToken; + deviceName?: string; accountHistory?: AccountToken; expiry?: string; // ISO8601 status: LoginState; @@ -15,6 +16,7 @@ export interface IAccountReduxState { const initialState: IAccountReduxState = { accountToken: undefined, + deviceName: undefined, accountHistory: undefined, expiry: undefined, status: { type: 'none' }, @@ -35,6 +37,8 @@ export default function ( return { ...state, status: { type: 'ok', method: 'existing_account' }, + accountToken: action.accountToken, + deviceName: action.deviceName, }; case 'LOGIN_FAILED': return { @@ -68,13 +72,18 @@ export default function ( return { ...state, status: { type: 'ok', method: 'new_account' }, - accountToken: action.token, + accountToken: action.accountToken, + deviceName: action.deviceName, expiry: action.expiry, }; + case 'ACCOUNT_SETUP_FINISHED': + return { + status: { type: 'ok', method: 'existing_account' }, + }; case 'UPDATE_ACCOUNT_TOKEN': return { ...state, - accountToken: action.token, + accountToken: action.accountToken, }; case 'UPDATE_ACCOUNT_HISTORY': return { diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts index a45bdada4d..3b0f7774d3 100644 --- a/gui/src/shared/daemon-rpc-types.ts +++ b/gui/src/shared/daemon-rpc-types.ts @@ -104,7 +104,8 @@ export type DaemonEvent = | { tunnelState: TunnelState } | { settings: ISettings } | { relayList: IRelayList } - | { appVersionInfo: IAppVersionInfo }; + | { appVersionInfo: IAppVersionInfo } + | { deviceConfig: IDeviceConfig }; export interface ITunnelStateRelayInfo { endpoint: ITunnelEndpoint; @@ -320,8 +321,17 @@ export interface IAppVersionInfo { suggestedIsBeta?: boolean; } -export interface ISettings { +export interface IDeviceConfig { accountToken?: AccountToken; + device?: IDevice; +} + +export interface IDevice { + id: string; + name: string; +} + +export interface ISettings { allowLan: boolean; autoConnect: boolean; blockWhenDisconnected: boolean; diff --git a/gui/src/shared/ipc-schema.ts b/gui/src/shared/ipc-schema.ts index a6d41298ce..6b3082cdd7 100644 --- a/gui/src/shared/ipc-schema.ts +++ b/gui/src/shared/ipc-schema.ts @@ -6,6 +6,7 @@ import { BridgeState, IAccountData, IAppVersionInfo, + IDeviceConfig, IDnsOptions, ILocation, IRelayList, @@ -50,6 +51,7 @@ export interface IAppStateSnapshot { accountHistory?: AccountToken; tunnelState: TunnelState; settings: ISettings; + deviceConfig: IDeviceConfig; relayListPair: IRelayListPair; currentVersion: ICurrentAppVersionInfo; upgradeVersion: IAppVersionInfo; @@ -163,6 +165,7 @@ export const ipcSchema = { }, account: { '': notifyRenderer<IAccountData | undefined>(), + device: notifyRenderer<IDeviceConfig>(), create: invoke<void, string>(), login: invoke<AccountToken, void>(), logout: invoke<void, void>(), |
