summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-11-03 02:02:09 +0100
committerOskar Nyberg <oskar@mullvad.net>2022-03-14 13:58:44 +0100
commit46fa74ad03658ad0afa9dc984565b7f10106af94 (patch)
treee271c92db8c2f06db457548f3ebb95ef97a4ab09 /gui/src
parent7c23c00a45d4a9342c69211d23ef8f8fd634725a (diff)
downloadmullvadvpn-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.ts14
-rw-r--r--gui/src/main/index.ts49
-rw-r--r--gui/src/renderer/app.tsx64
-rw-r--r--gui/src/renderer/components/ExpiredAccountAddTime.tsx6
-rw-r--r--gui/src/renderer/redux/account/actions.ts32
-rw-r--r--gui/src/renderer/redux/account/reducers.ts13
-rw-r--r--gui/src/shared/daemon-rpc-types.ts14
-rw-r--r--gui/src/shared/ipc-schema.ts3
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>(),