From 198b1afe88a34dfa7e4b3902eafa51be797b8775 Mon Sep 17 00:00:00 2001 From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com> Date: Fri, 19 Jul 2024 15:52:07 -0400 Subject: [PATCH] [MM-59044] Add per-server permission check for screen sharing (#3097) --- i18n/en.json | 3 +++ src/main/permissionsManager.ts | 4 ++++ src/main/windows/callsWidgetWindow.test.js | 10 ++++++++++ src/main/windows/callsWidgetWindow.ts | 6 ++++++ src/renderer/components/NewServerModal.tsx | 10 ++++++++++ 5 files changed, 33 insertions(+) diff --git a/i18n/en.json b/i18n/en.json index 2ffb2d05..97393128 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -114,10 +114,12 @@ "main.permissionsManager.checkPermission.dialog.detail.media": "{appName} will use the microphone and camera for calls and voice messages. You can always change this later in your computer's settings.", "main.permissionsManager.checkPermission.dialog.detail.notifications": "{appName} will send you notifications for messages and calls. You can configure your notification preferences in Settings.", "main.permissionsManager.checkPermission.dialog.detail.openExternal": "{appName} will open the requested link in an external application. If you do not trust this link, or do not recognize it, click Deny. You can always change this later in your computer's settings.", + "main.permissionsManager.checkPermission.dialog.detail.screenShare": "{appName} will use this permission to share your screen for calls. You can always change this later in your computer's settings.", "main.permissionsManager.checkPermission.dialog.message.geolocation": "{appName} ({url}) would like to access your location.", "main.permissionsManager.checkPermission.dialog.message.media": "{appName} ({url}) would like to access the microphone and camera.", "main.permissionsManager.checkPermission.dialog.message.notifications": "{appName} ({url}) would like to send you notifications.", "main.permissionsManager.checkPermission.dialog.message.openExternal": "{appName} ({url}) would like permission to open the following URL: {externalURL}", + "main.permissionsManager.checkPermission.dialog.message.screenShare": "{appName} ({url}) would like to be able to view your screen.", "main.permissionsManager.checkPermission.dialog.title": "Permission Requested", "main.tray.tray.expired": "Session Expired: Please sign in to continue receiving notifications.", "main.tray.tray.mention": "You have been mentioned", @@ -170,6 +172,7 @@ "renderer.components.newServerModal.permissions.notifications": "Notifications", "renderer.components.newServerModal.permissions.notifications.mac": "You may also need to enable notifications in macOS for Mattermost. Click here to open the System Preferences.", "renderer.components.newServerModal.permissions.notifications.windows": "You may also need to enable notifications in Windows for Mattermost. Click here to open the Notification Settings.", + "renderer.components.newServerModal.permissions.screenShare": "Screen Share", "renderer.components.newServerModal.permissions.title": "Permissions", "renderer.components.newServerModal.serverDisplayName": "Server Display Name", "renderer.components.newServerModal.serverDisplayName.description": "The name of the server displayed on your desktop app tab bar.", diff --git a/src/main/permissionsManager.ts b/src/main/permissionsManager.ts index 8df6e046..5e5824c2 100644 --- a/src/main/permissionsManager.ts +++ b/src/main/permissionsManager.ts @@ -45,6 +45,7 @@ const supportedPermissionTypes = [ 'fullscreen', 'openExternal', 'clipboard-sanitized-write', + 'screenShare', ]; // permissions that require a dialog @@ -53,6 +54,7 @@ const authorizablePermissionTypes = [ 'geolocation', 'notifications', 'openExternal', + 'screenShare', ]; type PermissionsByOrigin = { @@ -239,10 +241,12 @@ t('main.permissionsManager.checkPermission.dialog.message.media'); t('main.permissionsManager.checkPermission.dialog.message.geolocation'); t('main.permissionsManager.checkPermission.dialog.message.notifications'); t('main.permissionsManager.checkPermission.dialog.message.openExternal'); +t('main.permissionsManager.checkPermission.dialog.message.screenShare'); t('main.permissionsManager.checkPermission.dialog.detail.media'); t('main.permissionsManager.checkPermission.dialog.detail.geolocation'); t('main.permissionsManager.checkPermission.dialog.detail.notifications'); t('main.permissionsManager.checkPermission.dialog.detail.openExternal'); +t('main.permissionsManager.checkPermission.dialog.detail.screenShare'); let permissionsManager = new PermissionsManager(permissionsJson); diff --git a/src/main/windows/callsWidgetWindow.test.js b/src/main/windows/callsWidgetWindow.test.js index 862d1c9a..af474770 100644 --- a/src/main/windows/callsWidgetWindow.test.js +++ b/src/main/windows/callsWidgetWindow.test.js @@ -17,6 +17,7 @@ import { CALLS_PLUGIN_ID, } from 'common/utils/constants'; import urlUtils from 'common/utils/url'; +import PermissionsManager from 'main/permissionsManager'; import { resetScreensharePermissionsMacOS, openScreensharePermissionsSettingsMacOS, @@ -56,6 +57,9 @@ jest.mock('common/utils/url', () => ({ getFormattedPathName: jest.fn(), parseURL: jest.fn(), })); +jest.mock('main/permissionsManager', () => ({ + doPermissionRequest: jest.fn(), +})); jest.mock('main/windows/mainWindow', () => ({ get: jest.fn(), focus: jest.fn(), @@ -599,6 +603,11 @@ describe('main/windows/callsWidgetWindow', () => { arr.push([`${item.name}_${view.name}`, { sendToRenderer: jest.fn(), webContentsId: index, + view: { + server: { + url: new URL('http://server-1.com'), + }, + }, }]); }); return arr; @@ -606,6 +615,7 @@ describe('main/windows/callsWidgetWindow', () => { const views = new Map(map); beforeEach(() => { + PermissionsManager.doPermissionRequest.mockReturnValue(Promise.resolve(true)); ViewManager.getViewByWebContentsId.mockImplementation((id) => [...views.values()].find((view) => view.webContentsId === id)); callsWidgetWindow.mainView = views.get('server-1_view-1'); }); diff --git a/src/main/windows/callsWidgetWindow.ts b/src/main/windows/callsWidgetWindow.ts index 60a8a2b4..11469ef3 100644 --- a/src/main/windows/callsWidgetWindow.ts +++ b/src/main/windows/callsWidgetWindow.ts @@ -27,6 +27,7 @@ import {Logger} from 'common/log'; import {CALLS_PLUGIN_ID, MINIMUM_CALLS_WIDGET_HEIGHT, MINIMUM_CALLS_WIDGET_WIDTH} from 'common/utils/constants'; import {getFormattedPathName, isCallsPopOutURL, parseURL} from 'common/utils/url'; import Utils from 'common/utils/util'; +import PermissionsManager from 'main/permissionsManager'; import { composeUserAgent, getLocalPreload, @@ -403,6 +404,11 @@ export class CallsWidgetWindow { } } + if (!await PermissionsManager.doPermissionRequest(view.webContentsId, 'screenShare', {requestingUrl: view.view.server.url.toString(), isMainFrame: false})) { + log.warn('screen share permissions disallowed', view.webContentsId, view.view.server.url.toString()); + return []; + } + const screenPermissionsErrArgs = ['screen-permissions', this.callID]; return desktopCapturer.getSources(opts).then((sources) => { diff --git a/src/renderer/components/NewServerModal.tsx b/src/renderer/components/NewServerModal.tsx index ce4fac64..67ff0d20 100644 --- a/src/renderer/components/NewServerModal.tsx +++ b/src/renderer/components/NewServerModal.tsx @@ -577,6 +577,16 @@ class NewServerModal extends React.PureComponent { defaultMessage='Location' /> + + + + }