aboutsummaryrefslogtreecommitdiffstats
path: root/src/electron
diff options
context:
space:
mode:
Diffstat (limited to 'src/electron')
-rw-r--r--src/electron/Settings.js10
-rw-r--r--src/electron/ipc-api/appIndicator.js4
-rw-r--r--src/electron/ipc-api/download.js4
-rw-r--r--src/electron/ipc-api/localServer.js14
-rw-r--r--src/electron/macOSPermissions.js67
-rw-r--r--src/electron/webview-ime-focus.js4
6 files changed, 49 insertions, 54 deletions
diff --git a/src/electron/Settings.js b/src/electron/Settings.js
index 2f3f8261a..3e11bb175 100644
--- a/src/electron/Settings.js
+++ b/src/electron/Settings.js
@@ -1,8 +1,6 @@
1import { observable, toJS } from 'mobx'; 1import { observable, toJS } from 'mobx';
2import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra'; 2import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra';
3import path from 'path'; 3import { userDataPath } from '../environment';
4
5import { SETTINGS_PATH } from '../environment';
6 4
7const debug = require('debug')('Ferdi:Settings'); 5const debug = require('debug')('Ferdi:Settings');
8 6
@@ -47,17 +45,17 @@ export default class Settings {
47 45
48 _hydrate() { 46 _hydrate() {
49 this.store = this._merge(readJsonSync(this.settingsFile)); 47 this.store = this._merge(readJsonSync(this.settingsFile));
50 debug('Hydrate store', this.type, toJS(this.store)); 48 debug('Hydrate store', this.type, this.allSerialized);
51 } 49 }
52 50
53 _writeFile() { 51 _writeFile() {
54 outputJsonSync(this.settingsFile, this.store, { 52 outputJsonSync(this.settingsFile, this.store, {
55 spaces: 2, 53 spaces: 2,
56 }); 54 });
57 debug('Write settings file', this.type, toJS(this.store)); 55 debug('Write settings file', this.type, this.allSerialized);
58 } 56 }
59 57
60 get settingsFile() { 58 get settingsFile() {
61 return path.join(SETTINGS_PATH, `${this.type === 'app' ? 'settings' : this.type}.json`); 59 return userDataPath('config', `${this.type === 'app' ? 'settings' : this.type}.json`);
62 } 60 }
63} 61}
diff --git a/src/electron/ipc-api/appIndicator.js b/src/electron/ipc-api/appIndicator.js
index 0691e5170..c6c261d0f 100644
--- a/src/electron/ipc-api/appIndicator.js
+++ b/src/electron/ipc-api/appIndicator.js
@@ -1,5 +1,5 @@
1import { app, ipcMain } from 'electron'; 1import { app, ipcMain } from 'electron';
2import path from 'path'; 2import { join } from 'path';
3import { autorun } from 'mobx'; 3import { autorun } from 'mobx';
4import { isMac, isWindows, isLinux } from '../../environment'; 4import { isMac, isWindows, isLinux } from '../../environment';
5 5
@@ -9,7 +9,7 @@ const FILE_EXTENSION = isWindows ? 'ico' : 'png';
9let isTrayIconEnabled; 9let isTrayIconEnabled;
10 10
11function getAsset(type, asset) { 11function getAsset(type, asset) {
12 return path.join( 12 return join(
13 __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`, 13 __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`,
14 ); 14 );
15} 15}
diff --git a/src/electron/ipc-api/download.js b/src/electron/ipc-api/download.js
index 7f8718924..ba261ba1e 100644
--- a/src/electron/ipc-api/download.js
+++ b/src/electron/ipc-api/download.js
@@ -1,7 +1,7 @@
1import { ipcMain, dialog, BrowserWindow } from 'electron'; 1import { ipcMain, dialog, BrowserWindow } from 'electron';
2import { download } from 'electron-dl'; 2import { download } from 'electron-dl';
3import mime from 'mime-types'; 3import mime from 'mime-types';
4import fs from 'fs-extra'; 4import { writeFileSync } from 'fs-extra';
5 5
6const debug = require('debug')('Ferdi:ipcApi:download'); 6const debug = require('debug')('Ferdi:ipcApi:download');
7 7
@@ -37,7 +37,7 @@ export default (params) => {
37 if (saveDialog.canceled) return; 37 if (saveDialog.canceled) return;
38 38
39 const binaryImage = decodeBase64Image(content); 39 const binaryImage = decodeBase64Image(content);
40 fs.writeFileSync(saveDialog.filePath, binaryImage, 'binary'); 40 writeFileSync(saveDialog.filePath, binaryImage, 'binary');
41 41
42 debug('File blob saved to', saveDialog.filePath); 42 debug('File blob saved to', saveDialog.filePath);
43 } catch (err) { 43 } catch (err) {
diff --git a/src/electron/ipc-api/localServer.js b/src/electron/ipc-api/localServer.js
index 9b800fdf6..591e70504 100644
--- a/src/electron/ipc-api/localServer.js
+++ b/src/electron/ipc-api/localServer.js
@@ -1,9 +1,9 @@
1import { ipcMain, app } from 'electron'; 1import { ipcMain } from 'electron';
2import net from 'net'; 2import net from 'net';
3import { LOCAL_HOSTNAME, LOCAL_PORT } from '../../config';
4import { userDataPath } from '../../environment';
3import startServer from '../../internal-server/start'; 5import startServer from '../../internal-server/start';
4 6
5const DEFAULT_PORT = 45569;
6
7const portInUse = function (port) { 7const portInUse = function (port) {
8 return new Promise((resolve) => { 8 return new Promise((resolve) => {
9 const server = net.createServer((socket) => { 9 const server = net.createServer((socket) => {
@@ -11,7 +11,7 @@ const portInUse = function (port) {
11 socket.pipe(socket); 11 socket.pipe(socket);
12 }); 12 });
13 13
14 server.listen(port, '127.0.0.1'); 14 server.listen(port, LOCAL_HOSTNAME);
15 server.on('error', () => { 15 server.on('error', () => {
16 resolve(true); 16 resolve(true);
17 }); 17 });
@@ -28,15 +28,15 @@ export default (params) => {
28 ipcMain.on('startLocalServer', () => { 28 ipcMain.on('startLocalServer', () => {
29 if (!localServerStarted) { 29 if (!localServerStarted) {
30 // Find next unused port for server 30 // Find next unused port for server
31 let port = DEFAULT_PORT; 31 let port = LOCAL_PORT;
32 (async () => { 32 (async () => {
33 // eslint-disable-next-line no-await-in-loop 33 // eslint-disable-next-line no-await-in-loop
34 while ((await portInUse(port)) && port < DEFAULT_PORT + 10) { 34 while ((await portInUse(port)) && port < LOCAL_PORT + 10) {
35 port += 1; 35 port += 1;
36 } 36 }
37 console.log('Starting local server on port', port); 37 console.log('Starting local server on port', port);
38 38
39 startServer(app.getPath('userData'), port); 39 startServer(userDataPath(), port);
40 40
41 params.mainWindow.webContents.send('localServerPort', { 41 params.mainWindow.webContents.send('localServerPort', {
42 port, 42 port,
diff --git a/src/electron/macOSPermissions.js b/src/electron/macOSPermissions.js
index 940b16c6e..887af2903 100644
--- a/src/electron/macOSPermissions.js
+++ b/src/electron/macOSPermissions.js
@@ -1,83 +1,80 @@
1import { app, systemPreferences, dialog } from 'electron'; 1import { systemPreferences, dialog } from 'electron';
2import fs from 'fs'; 2import { pathExistsSync, mkdirSync, writeFileSync } from 'fs-extra';
3import macosVersion from 'macos-version'; 3import macosVersion from 'macos-version';
4import path from 'path'; 4import { dirname } from 'path';
5import { isMac } from '../environment'; 5import { askForScreenCaptureAccess } from 'node-mac-permissions';
6 6import { userDataPath } from '../environment';
7let askForScreenCaptureAccess;
8if (isMac) {
9 // eslint-disable-next-line global-require
10 askForScreenCaptureAccess = require('node-mac-permissions').askForScreenCaptureAccess;
11}
12 7
13const debug = require('debug')('Ferdi:macOSPermissions'); 8const debug = require('debug')('Ferdi:macOSPermissions');
14 9
15const permissionExists = macosVersion.isGreaterThanOrEqualTo('10.15'); 10const isExplicitScreenCapturePermissionReqd = macosVersion.isGreaterThanOrEqualTo('10.15');
16const filePath = path.join(app.getPath('userData'), '.has-app-requested-screen-capture-permissions'); 11debug(`Should check explicitly for screen-capture permissions: ${isExplicitScreenCapturePermissionReqd}`);
17 12
18function hasPromptedForPermission() { 13const filePath = userDataPath('.has-app-requested-screen-capture-permissions');
19 if (!permissionExists) {
20 return false;
21 }
22 14
23 if (filePath && fs.existsSync(filePath)) { 15function hasPromptedForScreenCapturePermission() {
24 return true; 16 if (!isExplicitScreenCapturePermissionReqd) {
17 return false;
25 } 18 }
26 19
27 return false; 20 debug('Checking if status file exists');
21 return filePath && pathExistsSync(filePath);
28} 22}
29 23
30function hasScreenCapturePermission() { 24function hasScreenCapturePermissionAlreadyBeenGranted() {
31 if (!permissionExists) { 25 if (!isExplicitScreenCapturePermissionReqd) {
32 return true; 26 return true;
33 } 27 }
34 28
35 const screenCaptureStatus = systemPreferences.getMediaAccessStatus('screen'); 29 const screenCaptureStatus = systemPreferences.getMediaAccessStatus('screen');
30 debug(`screen-capture permissions status: ${screenCaptureStatus}`);
36 return screenCaptureStatus === 'granted'; 31 return screenCaptureStatus === 'granted';
37} 32}
38 33
39function createStatusFile() { 34function createStatusFile() {
40 try { 35 try {
41 fs.writeFileSync(filePath, ''); 36 writeFileSync(filePath, '');
42 } catch (error) { 37 } catch (error) {
43 if (error.code === 'ENOENT') { 38 if (error.code === 'ENOENT') {
44 fs.mkdirSync(path.dirname(filePath)); 39 mkdirSync(dirname(filePath));
45 fs.writeFileSync(filePath, ''); 40 writeFileSync(filePath, '');
46 } 41 }
47 42
48 throw error; 43 throw error;
49 } 44 }
50} 45}
51 46
52export default async function (mainWindow) { 47export const askFormacOSPermissions = async mainWindow => {
53 debug('Checking camera & microphone permissions'); 48 debug('Checking camera & microphone permissions');
54 systemPreferences.askForMediaAccess('camera'); 49 systemPreferences.askForMediaAccess('camera');
55 systemPreferences.askForMediaAccess('microphone'); 50 systemPreferences.askForMediaAccess('microphone');
56 51
57 if (!hasPromptedForPermission() && !hasScreenCapturePermission()) { 52 if (hasScreenCapturePermissionAlreadyBeenGranted()) {
53 debug('Already obtained screen-capture permissions - writing status file');
54 createStatusFile();
55 return;
56 }
57
58 if (!hasPromptedForScreenCapturePermission()) {
58 debug('Checking screen capture permissions'); 59 debug('Checking screen capture permissions');
59 60
60 const { response } = await dialog.showMessageBox(mainWindow, { 61 const { response } = await dialog.showMessageBox(mainWindow, {
61 type: 'info', 62 type: 'info',
62 message: 'Enable Screen Sharing', 63 message: 'Enable Screen Sharing',
63 detail: 'To enable screen sharing for some services, Ferdi needs the permission to record your screen.', 64 detail:
64 buttons: [ 65 'To enable screen sharing for some services, Ferdi needs the permission to record your screen.',
65 'Allow screen sharing', 66 buttons: ['Allow screen sharing', 'No', 'Ask me later'],
66 'No',
67 'Ask me later',
68 ],
69 defaultId: 0, 67 defaultId: 0,
70 cancelId: 2, 68 cancelId: 2,
71 }); 69 });
72 70
73 console.log('result', response);
74 if (response === 0) { 71 if (response === 0) {
75 debug('Asking for access'); 72 debug('Asking for access');
76 askForScreenCaptureAccess(); 73 askForScreenCaptureAccess();
77 createStatusFile(); 74 createStatusFile();
78 } else if (response === 1) { 75 } else if (response === 1) {
79 debug('Don\'t ask again'); 76 debug("Don't ask again");
80 createStatusFile(); 77 createStatusFile();
81 } 78 }
82 } 79 }
83} 80};
diff --git a/src/electron/webview-ime-focus.js b/src/electron/webview-ime-focus.js
index b9421eb06..e187ee0b4 100644
--- a/src/electron/webview-ime-focus.js
+++ b/src/electron/webview-ime-focus.js
@@ -1,5 +1,5 @@
1const { webContents } = require('@electron/remote'); 1import { webContents } from '@electron/remote';
2const { releaseDocumentFocus } = require('./webview-ime-focus-helpers'); 2import { releaseDocumentFocus } from './webview-ime-focus-helpers';
3 3
4function giveWebviewDocumentFocus(element) { 4function giveWebviewDocumentFocus(element) {
5 releaseDocumentFocus(); 5 releaseDocumentFocus();