[MM-54465] Add Permissions Manager, require manual interaction to approve use of microphone and camera, to send notifications, and to use location per server (#2832)
This commit is contained in:
@@ -6,11 +6,9 @@ import path from 'path';
|
||||
import {app, session} from 'electron';
|
||||
|
||||
import Config from 'common/config';
|
||||
import {parseURL, isTrustedURL} from 'common/utils/url';
|
||||
|
||||
import parseArgs from 'main/ParseArgs';
|
||||
import ViewManager from 'main/views/viewManager';
|
||||
import MainWindow from 'main/windows/mainWindow';
|
||||
|
||||
import {initialize} from './initialize';
|
||||
import {clearAppCache, getDeeplinkingURL, wasUpdated} from './utils';
|
||||
@@ -107,11 +105,6 @@ jest.mock('common/config', () => ({
|
||||
initRegistry: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('common/utils/url', () => ({
|
||||
parseURL: jest.fn(),
|
||||
isTrustedURL: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('main/allowProtocolDialog', () => ({
|
||||
init: jest.fn(),
|
||||
}));
|
||||
@@ -169,9 +162,7 @@ jest.mock('main/UserActivityMonitor', () => ({
|
||||
on: jest.fn(),
|
||||
startMonitoring: jest.fn(),
|
||||
}));
|
||||
jest.mock('main/windows/callsWidgetWindow', () => ({
|
||||
isCallsWidget: jest.fn(),
|
||||
}));
|
||||
jest.mock('main/windows/callsWidgetWindow', () => ({}));
|
||||
jest.mock('main/views/viewManager', () => ({
|
||||
getViewByWebContentsId: jest.fn(),
|
||||
handleDeepLink: jest.fn(),
|
||||
@@ -277,46 +268,5 @@ describe('main/app/initialize', () => {
|
||||
|
||||
expect(ViewManager.handleDeepLink).toHaveBeenCalledWith('mattermost://server-1.com');
|
||||
});
|
||||
|
||||
it('should allow permission requests for supported types from trusted URLs', async () => {
|
||||
ViewManager.getViewByWebContentsId.mockReturnValue({
|
||||
view: {
|
||||
server: {
|
||||
url: new URL('http://server-1.com'),
|
||||
},
|
||||
},
|
||||
});
|
||||
parseURL.mockImplementation((url) => new URL(url));
|
||||
isTrustedURL.mockImplementation((url) => url.toString() === 'http://server-1.com/');
|
||||
|
||||
let callback = jest.fn();
|
||||
session.defaultSession.setPermissionRequestHandler.mockImplementation((cb) => {
|
||||
cb({id: 1, getURL: () => 'http://server-1.com'}, 'bad-permission', callback);
|
||||
});
|
||||
await initialize();
|
||||
expect(callback).toHaveBeenCalledWith(false);
|
||||
|
||||
callback = jest.fn();
|
||||
MainWindow.get.mockReturnValue({webContents: {id: 1}});
|
||||
session.defaultSession.setPermissionRequestHandler.mockImplementation((cb) => {
|
||||
cb({id: 1, getURL: () => 'http://server-1.com'}, 'openExternal', callback);
|
||||
});
|
||||
await initialize();
|
||||
expect(callback).toHaveBeenCalledWith(true);
|
||||
|
||||
callback = jest.fn();
|
||||
session.defaultSession.setPermissionRequestHandler.mockImplementation((cb) => {
|
||||
cb({id: 2, getURL: () => 'http://server-1.com'}, 'openExternal', callback);
|
||||
});
|
||||
await initialize();
|
||||
expect(callback).toHaveBeenCalledWith(true);
|
||||
|
||||
callback = jest.fn();
|
||||
session.defaultSession.setPermissionRequestHandler.mockImplementation((cb) => {
|
||||
cb({id: 2, getURL: () => 'http://server-2.com'}, 'openExternal', callback);
|
||||
});
|
||||
await initialize();
|
||||
expect(callback).toHaveBeenCalledWith(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -32,7 +32,6 @@ import {
|
||||
TOGGLE_SECURE_INPUT,
|
||||
} from 'common/communication';
|
||||
import Config from 'common/config';
|
||||
import {isTrustedURL, parseURL} from 'common/utils/url';
|
||||
import {Logger} from 'common/log';
|
||||
|
||||
import AllowProtocolDialog from 'main/allowProtocolDialog';
|
||||
@@ -47,12 +46,12 @@ import CriticalErrorHandler from 'main/CriticalErrorHandler';
|
||||
import downloadsManager from 'main/downloadsManager';
|
||||
import i18nManager from 'main/i18nManager';
|
||||
import parseArgs from 'main/ParseArgs';
|
||||
import PermissionsManager from 'main/permissionsManager';
|
||||
import ServerManager from 'common/servers/serverManager';
|
||||
import TrustedOriginsStore from 'main/trustedOrigins';
|
||||
import Tray from 'main/tray/tray';
|
||||
import UserActivityMonitor from 'main/UserActivityMonitor';
|
||||
import ViewManager from 'main/views/viewManager';
|
||||
import CallsWidgetWindow from 'main/windows/callsWidgetWindow';
|
||||
import MainWindow from 'main/windows/mainWindow';
|
||||
|
||||
import {protocols} from '../../../electron-builder.json';
|
||||
@@ -392,56 +391,9 @@ async function initializeAfterAppReady() {
|
||||
|
||||
ipcMain.emit('update-dict');
|
||||
|
||||
// supported permission types
|
||||
const supportedPermissionTypes = [
|
||||
'media',
|
||||
'geolocation',
|
||||
'notifications',
|
||||
'fullscreen',
|
||||
'openExternal',
|
||||
'clipboard-sanitized-write',
|
||||
];
|
||||
|
||||
// handle permission requests
|
||||
// - approve if a supported permission type and the request comes from the renderer or one of the defined servers
|
||||
defaultSession.setPermissionRequestHandler((webContents, permission, callback) => {
|
||||
log.debug('permission requested', webContents.getURL(), permission);
|
||||
|
||||
// is the requested permission type supported?
|
||||
if (!supportedPermissionTypes.includes(permission)) {
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// is the request coming from the renderer?
|
||||
const mainWindow = MainWindow.get();
|
||||
if (mainWindow && webContents.id === mainWindow.webContents.id) {
|
||||
callback(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CallsWidgetWindow.isCallsWidget(webContents.id)) {
|
||||
callback(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const requestingURL = webContents.getURL();
|
||||
const serverURL = ViewManager.getViewByWebContentsId(webContents.id)?.view.server.url;
|
||||
|
||||
if (!serverURL) {
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedURL = parseURL(requestingURL);
|
||||
if (!parsedURL) {
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// is the requesting url trusted?
|
||||
callback(isTrustedURL(parsedURL, serverURL));
|
||||
});
|
||||
defaultSession.setPermissionRequestHandler(PermissionsManager.handlePermissionRequest);
|
||||
|
||||
if (wasUpdated(AppVersionManager.lastAppVersion)) {
|
||||
clearAppCache();
|
||||
|
Reference in New Issue
Block a user