summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2020-02-26 16:06:59 +0100
committerOskar Nyberg <oskar@mullvad.net>2020-04-06 17:44:45 +0200
commitdab4202bea4b5cfe9121cee513b61a3fb45bbb19 (patch)
tree567b38a65a41a48c0f0262e4605502a9446d5de1 /gui/src
parent6157a809ad6eb5cdb06b7fcaea9549b3f100f07a (diff)
downloadmullvadvpn-dab4202bea4b5cfe9121cee513b61a3fb45bbb19.tar.xz
mullvadvpn-dab4202bea4b5cfe9121cee513b61a3fb45bbb19.zip
Add submitVoucher call
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/main/daemon-rpc.ts25
-rw-r--r--gui/src/main/index.ts3
-rw-r--r--gui/src/renderer/app.tsx4
-rw-r--r--gui/src/shared/daemon-rpc-types.ts9
-rw-r--r--gui/src/shared/ipc-event-channel.ts6
5 files changed, 47 insertions, 0 deletions
diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts
index 02b9deceec..5db6f621c2 100644
--- a/gui/src/main/daemon-rpc.ts
+++ b/gui/src/main/daemon-rpc.ts
@@ -12,6 +12,8 @@ import {
KeygenEvent,
RelaySettingsUpdate,
TunnelState,
+ VoucherErrorCode,
+ VoucherResponse,
} from '../shared/daemon-rpc-types';
import { CommunicationError, InvalidAccountError, NoDaemonError } from './errors';
import JsonRpcClient, {
@@ -227,6 +229,10 @@ const accountDataSchema = partialObject({
expiry: string,
});
+const voucherResponseSchema = partialObject({
+ new_expiry: string,
+});
+
const tunnelStateSchema = oneOf(
object({
state: enumeration('disconnecting'),
@@ -443,6 +449,25 @@ export class DaemonRpc {
}
}
+ public async submitVoucher(voucherCode: string): Promise<VoucherResponse> {
+ try {
+ const response = await this.transport.send('submit_voucher', voucherCode);
+ const new_expiry = validate(voucherResponseSchema, response).new_expiry;
+ return { type: 'success', new_expiry };
+ } catch (error) {
+ if (error instanceof JsonRpcRemoteError) {
+ switch (error.code) {
+ case VoucherErrorCode.Invalid:
+ return { type: 'invalid' };
+ case VoucherErrorCode.AlreadyUsed:
+ return { type: 'already_used' };
+ }
+ }
+ }
+
+ return { type: 'error' };
+ }
+
public async getRelayLocations(): Promise<IRelayList> {
const response = await this.transport.send('get_relay_locations');
try {
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index 28956d8c88..2c3d71e628 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -995,6 +995,9 @@ class ApplicationMain {
IpcMainEventChannel.account.handleLogin((token: AccountToken) => this.login(token));
IpcMainEventChannel.account.handleLogout(() => this.logout());
IpcMainEventChannel.account.handleWwwAuthToken(() => this.daemonRpc.getWwwAuthToken());
+ IpcMainEventChannel.account.handleSubmitVoucher((voucherCode: string) =>
+ this.daemonRpc.submitVoucher(voucherCode),
+ );
IpcMainEventChannel.accountHistory.handleRemoveItem(async (token: AccountToken) => {
await this.daemonRpc.removeAccountFromHistory(token);
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index f47e4c58bf..6d6c2ecccb 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -272,6 +272,10 @@ export default class AppRenderer {
}
}
+ public async submitVoucher(voucherCode: string) {
+ return IpcRendererEventChannel.account.submitVoucher(voucherCode);
+ }
+
public async connectTunnel(): Promise<void> {
const state = this.tunnelState.state;
diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts
index ac1e7584f6..661250c5f5 100644
--- a/gui/src/shared/daemon-rpc-types.ts
+++ b/gui/src/shared/daemon-rpc-types.ts
@@ -320,6 +320,15 @@ export interface ISocketAddress {
port: number;
}
+export type VoucherResponse =
+ | { type: 'success'; new_expiry: string }
+ | { type: 'invalid' | 'already_used' | 'error' };
+
+export enum VoucherErrorCode {
+ Invalid = -400,
+ AlreadyUsed = -401,
+}
+
export function parseSocketAddress(socketAddrStr: string): ISocketAddress {
const re = new RegExp(/(.+):(\d+)$/);
const matches = socketAddrStr.match(re);
diff --git a/gui/src/shared/ipc-event-channel.ts b/gui/src/shared/ipc-event-channel.ts
index 48f7b71bdc..b6e788e72e 100644
--- a/gui/src/shared/ipc-event-channel.ts
+++ b/gui/src/shared/ipc-event-channel.ts
@@ -18,6 +18,7 @@ import {
KeygenEvent,
RelaySettingsUpdate,
TunnelState,
+ VoucherResponse,
} from './daemon-rpc-types';
export interface IAppStateSnapshot {
@@ -110,6 +111,7 @@ interface IAccountHandlers extends ISender<IAccountData | undefined> {
handleLogin(fn: (token: AccountToken) => Promise<void>): void;
handleLogout(fn: () => Promise<void>): void;
handleWwwAuthToken(fn: () => Promise<string>): void;
+ handleSubmitVoucher(fn: (voucherCode: string) => Promise<VoucherResponse>): void;
}
interface IAccountMethods extends IReceiver<IAccountData | undefined> {
@@ -117,6 +119,7 @@ interface IAccountMethods extends IReceiver<IAccountData | undefined> {
login(token: AccountToken): Promise<void>;
logout(): Promise<void>;
getWwwAuthToken(): Promise<string>;
+ submitVoucher(voucherCode: string): Promise<VoucherResponse>;
}
interface IAccountHistoryHandlers extends ISender<AccountToken[]> {
@@ -193,6 +196,7 @@ const DO_LOGIN = 'do-login';
const DO_LOGOUT = 'do-logout';
const DO_GET_WWW_AUTH_TOKEN = 'do-get-www-auth-token';
const ACCOUNT_DATA_CHANGED = 'account-data-changed';
+const REDEEM_VOUCHER = 'redeem-voucher';
const AUTO_START_CHANGED = 'auto-start-changed';
const SET_AUTO_START = 'set-auto-start';
@@ -287,6 +291,7 @@ export class IpcRendererEventChannel {
login: requestSender(DO_LOGIN),
logout: requestSender(DO_LOGOUT),
getWwwAuthToken: requestSender(DO_GET_WWW_AUTH_TOKEN),
+ submitVoucher: requestSender(REDEEM_VOUCHER),
};
public static accountHistory: IAccountHistoryMethods = {
@@ -383,6 +388,7 @@ export class IpcMainEventChannel {
handleLogin: requestHandler(DO_LOGIN),
handleLogout: requestHandler(DO_LOGOUT),
handleWwwAuthToken: requestHandler(DO_GET_WWW_AUTH_TOKEN),
+ handleSubmitVoucher: requestHandler<VoucherResponse>(REDEEM_VOUCHER),
};
public static accountHistory: IAccountHistoryHandlers = {