summaryrefslogtreecommitdiffhomepage
path: root/app/lib
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2018-06-20 14:43:51 +0200
committerAndrej Mihajlov <and@mullvad.net>2018-07-03 13:37:54 +0200
commit67e82627564f8e4a2d8da4bcf5f0fd00867876bc (patch)
tree814494d59045d8b3f02cb310dc7728aa818be509 /app/lib
parentbe096ee87bb1256b67c3b24b61be77d523aff9cc (diff)
downloadmullvadvpn-67e82627564f8e4a2d8da4bcf5f0fd00867876bc.tar.xz
mullvadvpn-67e82627564f8e4a2d8da4bcf5f0fd00867876bc.zip
Move RPC file related stuff into RpcAddressFile
Diffstat (limited to 'app/lib')
-rw-r--r--app/lib/backend.js23
-rw-r--r--app/lib/rpc-address-file.js120
-rw-r--r--app/lib/rpc-file-security.js36
3 files changed, 124 insertions, 55 deletions
diff --git a/app/lib/backend.js b/app/lib/backend.js
index b24b495449..39521d8edb 100644
--- a/app/lib/backend.js
+++ b/app/lib/backend.js
@@ -8,6 +8,7 @@ import connectionActions from '../redux/connection/actions';
import settingsActions from '../redux/settings/actions';
import { push } from 'react-router-redux';
+import type { RpcCredentials } from './rpc-address-file';
import type { ReduxStore } from '../redux/store';
import type { AccountToken, BackendState, RelaySettingsUpdate } from './ipc-facade';
import type { ConnectionState } from '../redux/connection/reducers';
@@ -74,32 +75,16 @@ export class UnknownError extends Error {
}
}
-export type IpcCredentials = {
- connectionString: string,
- sharedSecret: string,
-};
-export function parseIpcCredentials(data: string): ?IpcCredentials {
- const [connectionString, sharedSecret] = data.split('\n', 2);
- if (connectionString && sharedSecret !== undefined) {
- return {
- connectionString,
- sharedSecret,
- };
- } else {
- return null;
- }
-}
-
/**
* Backend implementation
*/
export class Backend {
_ipc: IpcFacade;
- _credentials: ?IpcCredentials;
+ _credentials: ?RpcCredentials;
_authenticationPromise: ?Promise<void>;
_store: ReduxStore;
- constructor(store: ReduxStore, credentials?: IpcCredentials, ipc: ?IpcFacade) {
+ constructor(store: ReduxStore, credentials?: RpcCredentials, ipc: ?IpcFacade) {
this._store = store;
this._credentials = credentials;
@@ -116,7 +101,7 @@ export class Backend {
}
}
- setCredentials(credentials: IpcCredentials) {
+ setCredentials(credentials: RpcCredentials) {
log.debug('Got connection info to backend', credentials.connectionString);
this._credentials = credentials;
diff --git a/app/lib/rpc-address-file.js b/app/lib/rpc-address-file.js
new file mode 100644
index 0000000000..5185ddc749
--- /dev/null
+++ b/app/lib/rpc-address-file.js
@@ -0,0 +1,120 @@
+// @flow
+
+import fs from 'fs';
+import path from 'path';
+import { promisify } from 'util';
+import { getSystemTemporaryDirectory } from './tempdir';
+
+const fsReadFileAsync = promisify(fs.readFile);
+
+const POLL_INTERVAL = 200;
+
+const appDirectoryName = 'Mullvad VPN';
+
+export type RpcCredentials = {
+ connectionString: string,
+ sharedSecret: string,
+};
+
+export class RpcAddressFile {
+ _filePath: string;
+ _pollIntervalId: ?IntervalID;
+ _pollPromise: ?Promise<void>;
+
+ constructor() {
+ this._filePath = getRpcAddressFilePath();
+ }
+
+ get filePath(): string {
+ return this._filePath;
+ }
+
+ poll(): Promise<void> {
+ let promise = this._pollPromise;
+
+ if (!promise) {
+ promise = new Promise((resolve, _reject) => {
+ const timer = setInterval(() => {
+ fs.exists(this._filePath, (exists) => {
+ if (exists) {
+ clearInterval(timer);
+ resolve();
+
+ this._pollPromise = null;
+ }
+ });
+ }, POLL_INTERVAL);
+ });
+
+ this._pollPromise = promise;
+ }
+
+ return promise;
+ }
+
+ isTrusted() {
+ const filePath = this._filePath;
+ switch (process.platform) {
+ case 'win32':
+ return isOwnedByLocalSystem(filePath);
+ case 'darwin':
+ case 'linux':
+ return isOwnedAndOnlyWritableByRoot(filePath);
+ default:
+ throw new Error(`Unknown platform: ${process.platform}`);
+ }
+ }
+
+ async waitUntilExists(): Promise<RpcCredentials> {
+ const data = await fsReadFileAsync(this._filePath, 'utf8');
+ const [connectionString, sharedSecret] = data.split('\n', 2);
+
+ if (connectionString && sharedSecret !== undefined) {
+ return {
+ connectionString,
+ sharedSecret,
+ };
+ } else {
+ throw new Error('Cannot parse the RPC address file');
+ }
+ }
+}
+
+function getRpcAddressFilePath() {
+ const rpcAddressFileName = '.mullvad_rpc_address';
+
+ switch (process.platform) {
+ case 'win32': {
+ // Windows: %ALLUSERSPROFILE%\{appname}
+ const programDataDirectory = process.env.ALLUSERSPROFILE;
+ if (programDataDirectory) {
+ const appDataDirectory = path.join(programDataDirectory, appDirectoryName);
+ return path.join(appDataDirectory, rpcAddressFileName);
+ } else {
+ throw new Error('Missing %ALLUSERSPROFILE% environment variable');
+ }
+ }
+ default:
+ return path.join(getSystemTemporaryDirectory(), rpcAddressFileName);
+ }
+}
+
+function isOwnedAndOnlyWritableByRoot(path: string): boolean {
+ const stat = fs.statSync(path);
+ const isOwnedByRoot = stat.uid === 0;
+ const isOnlyWritableByOwner = (stat.mode & parseInt('022', 8)) === 0;
+
+ return isOwnedByRoot && isOnlyWritableByOwner;
+}
+
+function isOwnedByLocalSystem(path: string): boolean {
+ // $FlowFixMe: this module is only available on Windows
+ const winsec = require('windows-security');
+ const ownerSid = winsec.getFileOwnerSid(path, null);
+ const isWellKnownSid = winsec.isWellKnownSid(
+ ownerSid,
+ winsec.WellKnownSid.BuiltinAdministratorsSid,
+ );
+
+ return isWellKnownSid;
+}
diff --git a/app/lib/rpc-file-security.js b/app/lib/rpc-file-security.js
deleted file mode 100644
index fa88111c02..0000000000
--- a/app/lib/rpc-file-security.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// @flow
-
-import fs from 'fs';
-
-export function canTrustRpcAddressFile(path: string): boolean {
- const platform = process.platform;
- switch (platform) {
- case 'win32':
- return isOwnedByLocalSystem(path);
- case 'darwin':
- case 'linux':
- return isOwnedAndOnlyWritableByRoot(path);
- default:
- throw new Error(`Unknown platform: ${platform}`);
- }
-}
-
-function isOwnedAndOnlyWritableByRoot(path: string): boolean {
- const stat = fs.statSync(path);
- const isOwnedByRoot = stat.uid === 0;
- const isOnlyWritableByOwner = (stat.mode & parseInt('022', 8)) === 0;
-
- return isOwnedByRoot && isOnlyWritableByOwner;
-}
-
-function isOwnedByLocalSystem(path: string): boolean {
- // $FlowFixMe: this module is only available on Windows
- const winsec = require('windows-security');
- const ownerSid = winsec.getFileOwnerSid(path, null);
- const isWellKnownSid = winsec.isWellKnownSid(
- ownerSid,
- winsec.WellKnownSid.BuiltinAdministratorsSid,
- );
-
- return isWellKnownSid;
-}