diff --git a/src/main.js b/src/main.js index a9c28fab..7a9c1f6f 100644 --- a/src/main.js +++ b/src/main.js @@ -37,6 +37,7 @@ const appMenu = require('./main/menus/app'); const trayMenu = require('./main/menus/tray'); const downloadURL = require('./main/downloadURL'); const allowProtocolDialog = require('./main/allowProtocolDialog'); +const PermissionManager = require('./main/PermissionManager'); const permissionRequestHandler = require('./main/permissionRequestHandler'); const SpellChecker = require('./main/SpellChecker'); @@ -49,6 +50,7 @@ var mainWindow = null; let spellChecker = null; let deeplinkingUrl = null; let scheme = null; +let permissionManager = null; var argv = require('yargs').parse(process.argv.slice(1)); @@ -83,10 +85,11 @@ try { settings.writeFileSync(configFile, config); } } - ipcMain.on('update-config', () => { const configFile = app.getPath('userData') + '/config.json'; config = settings.readFileSync(configFile); + const trustedURLs = settings.mergeDefaultTeams(config.teams).map((team) => team.url); + permissionManager.setTrustedURLs(trustedURLs); ipcMain.emit('update-dict', true, config.spellCheckerLocale); }); @@ -583,7 +586,9 @@ app.on('ready', () => { ipcMain.emit('update-dict'); const permissionFile = path.join(app.getPath('userData'), 'permission.json'); - session.defaultSession.setPermissionRequestHandler(permissionRequestHandler(mainWindow, permissionFile)); + const trustedURLs = settings.mergeDefaultTeams(config.teams).map((team) => team.url); + permissionManager = new PermissionManager(permissionFile, trustedURLs); + session.defaultSession.setPermissionRequestHandler(permissionRequestHandler(mainWindow, permissionManager)); // Open the DevTools. // mainWindow.openDevTools(); diff --git a/src/main/PermissionManager.js b/src/main/PermissionManager.js new file mode 100644 index 00000000..9f9aed8f --- /dev/null +++ b/src/main/PermissionManager.js @@ -0,0 +1,73 @@ +const fs = require('fs'); +const utils = require('../utils/util'); + +const PERMISSION_GRANTED = 'granted'; +const PERMISSION_DENIED = 'denied'; + +class PermissionManager { + constructor(file, trustedURLs = []) { + this.file = file; + this.setTrustedURLs(trustedURLs); + if (fs.existsSync(file)) { + try { + this.permissions = JSON.parse(fs.readFileSync(this.file, 'utf-8')); + } catch (err) { + console.error(err); + this.permissions = {}; + } + } else { + this.permissions = {}; + } + } + + writeFileSync() { + fs.writeFileSync(this.file, JSON.stringify(this.permissions, null, ' ')); + } + + grant(origin, permission) { + if (!this.permissions[origin]) { + this.permissions[origin] = {}; + } + this.permissions[origin][permission] = PERMISSION_GRANTED; + this.writeFileSync(); + } + + deny(origin, permission) { + if (!this.permissions[origin]) { + this.permissions[origin] = {}; + } + this.permissions[origin][permission] = PERMISSION_DENIED; + this.writeFileSync(); + } + + clear(origin, permission) { + delete this.permissions[origin][permission]; + } + + isGranted(origin, permission) { + if (this.trustedOrigins[origin] === true) { + return true; + } + if (this.permissions[origin]) { + return this.permissions[origin][permission] === PERMISSION_GRANTED; + } + return false; + } + + isDenied(origin, permission) { + if (this.permissions[origin]) { + return this.permissions[origin][permission] === PERMISSION_DENIED; + } + return false; + } + + setTrustedURLs(trustedURLs) { + this.trustedOrigins = {}; + for (const url of trustedURLs) { + const origin = utils.getDomain(url); + this.trustedOrigins[origin] = true; + } + } +} + +module.exports = PermissionManager; diff --git a/src/main/permissionRequestHandler.js b/src/main/permissionRequestHandler.js index c70a19d5..6edeffd9 100644 --- a/src/main/permissionRequestHandler.js +++ b/src/main/permissionRequestHandler.js @@ -1,63 +1,5 @@ const {ipcMain} = require('electron'); const {URL} = require('url'); -const fs = require('fs'); - -const PERMISSION_GRANTED = 'granted'; -const PERMISSION_DENIED = 'denied'; - -class PermissionManager { - constructor(file) { - this.file = file; - if (fs.existsSync(file)) { - try { - this.permissions = JSON.parse(fs.readFileSync(this.file, 'utf-8')); - } catch (err) { - console.error(err); - this.permissions = {}; - } - } else { - this.permissions = {}; - } - } - - writeFileSync() { - fs.writeFileSync(this.file, JSON.stringify(this.permissions, null, ' ')); - } - - grant(origin, permission) { - if (!this.permissions[origin]) { - this.permissions[origin] = {}; - } - this.permissions[origin][permission] = PERMISSION_GRANTED; - this.writeFileSync(); - } - - deny(origin, permission) { - if (!this.permissions[origin]) { - this.permissions[origin] = {}; - } - this.permissions[origin][permission] = PERMISSION_DENIED; - this.writeFileSync(); - } - - clear(origin, permission) { - delete this.permissions[origin][permission]; - } - - isGranted(origin, permission) { - if (this.permissions[origin]) { - return this.permissions[origin][permission] === PERMISSION_GRANTED; - } - return false; - } - - isDenied(origin, permission) { - if (this.permissions[origin]) { - return this.permissions[origin][permission] === PERMISSION_DENIED; - } - return false; - } -} function dequeueRequests(requestQueue, permissionManager, origin, permission, status) { switch (status) { @@ -88,8 +30,7 @@ function dequeueRequests(requestQueue, permissionManager, origin, permission, st } } -function permissionRequestHandler(mainWindow, permissionFile) { - const permissionManager = new PermissionManager(permissionFile); +function permissionRequestHandler(mainWindow, permissionManager) { const requestQueue = []; ipcMain.on('update-permission', (event, origin, permission, status) => { dequeueRequests(requestQueue, permissionManager, origin, permission, status); @@ -114,6 +55,4 @@ function permissionRequestHandler(mainWindow, permissionFile) { }; } -permissionRequestHandler.PermissionManager = PermissionManager; - module.exports = permissionRequestHandler; diff --git a/src/utils/util.js b/src/utils/util.js index 6475bcfe..4c756682 100644 --- a/src/utils/util.js +++ b/src/utils/util.js @@ -1,10 +1,8 @@ -const {URL} = require('url'); +const url = require('url'); -export function getDomain(url) { - try { - const objectUrl = new URL(url); - return objectUrl.origin; - } catch (e) { - return null; - } +function getDomain(inputURL) { + const parsedURL = url.parse(inputURL); + return `${parsedURL.protocol}//${parsedURL.host}`; } + +module.exports = {getDomain}; diff --git a/test/specs/permisson_test.js b/test/specs/permisson_test.js index 0ec0fcb0..a5b4320c 100644 --- a/test/specs/permisson_test.js +++ b/test/specs/permisson_test.js @@ -3,7 +3,7 @@ const fs = require('fs'); const path = require('path'); const env = require('../modules/environment'); -const {PermissionManager} = require('../../src/main/permissionRequestHandler'); +const PermissionManager = require('../../src/main/PermissionManager'); const permissionFile = path.join(env.userDataDir, 'permission.json'); @@ -77,4 +77,11 @@ describe('PermissionManager', function() { manager.isDenied('origin', 'permission').should.be.true; manager.isGranted('origin_another', 'permission_another').should.be.true; }); + + it('should allow permissions for trusted URLs', function() { + fs.writeFileSync(permissionFile, JSON.stringify({})); + const manager = new PermissionManager(permissionFile, ['https://example.com', 'https://example2.com/2']); + manager.isGranted('https://example.com', 'notifications').should.be.true; + manager.isGranted('https://example2.com', 'test').should.be.true; + }); });