Context isolation for About, ScreenShare, Preferences

This commit is contained in:
Josh Perez 2021-09-16 11:52:56 -04:00 committed by GitHub
parent 59ca63cd2e
commit 43685d15c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 234 additions and 321 deletions

View File

@ -6,11 +6,7 @@
<meta
http-equiv="Content-Security-Policy"
content="default-src 'none';
child-src 'self';
connect-src 'self' https: wss:;
font-src 'self';
form-action 'self';
frame-src 'none';
img-src 'self' blob: data:;
media-src 'self' blob:;
object-src 'none';
@ -23,54 +19,9 @@
type="text/css"
/>
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
<style>
body {
display: flex;
justify-content: center;
align-items: center;
text-align: center;
overflow: hidden;
background-color: #3a76f0;
color: white;
font-size: 14px;
}
img {
margin-top: 1em;
}
a {
color: white;
}
</style>
</head>
<body>
<div class="module-splash-screen">
<div class="module-splash-screen__logo module-img--150"></div>
<div class="version"></div>
<div class="environment"></div>
<div>
<a href="https://signal.org">signal.org</a>
</div>
<br />
<div>
<a
class="acknowledgments"
href="https://github.com/signalapp/Signal-Desktop/blob/development/ACKNOWLEDGMENTS.md"
>Software Acknowledgments</a
>
</div>
<div>
<a class="privacy" href="https://signal.org/legal"
>Terms &amp; Privacy Policy</a
>
</div>
</div>
<script
type="text/javascript"
src="node_modules/jquery/dist/jquery.js"
></script>
<script type="text/javascript" src="js/about_start.js"></script>
<div id="app"></div>
<script type="application/javascript" src="ts/windows/init.js"></script>
</body>
</html>

View File

@ -1,28 +0,0 @@
// Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global window */
const { ipcRenderer } = require('electron');
const url = require('url');
const i18n = require('./js/modules/i18n');
const {
getEnvironment,
setEnvironment,
parseEnvironment,
} = require('./ts/environment');
const config = url.parse(window.location.toString(), true).query;
const { locale } = config;
const localeMessages = ipcRenderer.sendSync('locale-data');
setEnvironment(parseEnvironment(config.environment));
window.getEnvironment = getEnvironment;
window.getVersion = () => config.version;
window.getAppInstance = () => config.appInstance;
window.closeAbout = () => ipcRenderer.send('close-about');
window.i18n = i18n.setup(locale, localeMessages);
require('./ts/logging/set_up_renderer_logging').initialize();

View File

@ -1,30 +0,0 @@
// Copyright 2018-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global $: false */
// Add version
$('.version').text(`v${window.getVersion()}`);
// Add debugging metadata - environment if not production, app instance name
const states = [];
if (window.getEnvironment() !== 'production') {
states.push(window.getEnvironment());
}
if (window.getAppInstance()) {
states.push(window.getAppInstance());
}
$('.environment').text(states.join(' - '));
// Install the 'dismiss with escape key' handler
$(document).on('keydown', e => {
if (e.keyCode === 27) {
window.closeAbout();
}
});
// Localize the acknowledgment and privacy strings
$('.acknowledgments').text(window.i18n('softwareAcknowledgments'));
$('.privacy').text(window.i18n('privacyPolicy'));

22
main.js
View File

@ -824,8 +824,14 @@ function showScreenShareWindow(sourceName) {
...defaultWebPrefs,
nodeIntegration: false,
nodeIntegrationInWorker: false,
contextIsolation: false,
preload: path.join(__dirname, 'screenShare_preload.js'),
contextIsolation: true,
preload: path.join(
__dirname,
'ts',
'windows',
'screenShare',
'preload.js'
),
},
x: Math.floor(display.size.width / 2) - width / 2,
y: 24,
@ -847,6 +853,9 @@ function showScreenShareWindow(sourceName) {
'render-screen-sharing-controller',
sourceName
);
if (config.get('openDevTools')) {
screenShareWindow.webContents.openDevTools();
}
});
}
@ -869,8 +878,8 @@ function showAbout() {
...defaultWebPrefs,
nodeIntegration: false,
nodeIntegrationInWorker: false,
contextIsolation: false,
preload: path.join(__dirname, 'about_preload.js'),
contextIsolation: true,
preload: path.join(__dirname, 'ts', 'windows', 'about', 'preload.js'),
nativeWindowOpen: true,
},
};
@ -887,6 +896,9 @@ function showAbout() {
aboutWindow.once('ready-to-show', () => {
aboutWindow.show();
if (config.get('openDevTools')) {
aboutWindow.webContents.openDevTools();
}
});
}
@ -911,7 +923,7 @@ function showSettingsWindow() {
...defaultWebPrefs,
nodeIntegration: false,
nodeIntegrationInWorker: false,
contextIsolation: false,
contextIsolation: true,
enableRemoteModule: true,
preload: path.join(__dirname, 'ts', 'windows', 'settings', 'preload.js'),
nativeWindowOpen: true,

View File

@ -416,8 +416,6 @@
"app/*",
"preload.bundle.js",
"preload_utils.js",
"about_preload.js",
"screenShare_preload.js",
"permissions_popup_preload.js",
"debug_log_preload.js",
"main.js",

View File

@ -22,9 +22,5 @@
</head>
<body>
<div id="app"></div>
<script
type="application/javascript"
src="ts/windows/screenShare.js"
></script>
</body>
</html>

View File

@ -1,62 +0,0 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global window */
const React = require('react');
const ReactDOM = require('react-dom');
const url = require('url');
const { ipcRenderer } = require('electron');
// It is important to call this as early as possible
require('./ts/windows/context');
const i18n = require('./js/modules/i18n');
const {
getEnvironment,
setEnvironment,
parseEnvironment,
} = require('./ts/environment');
const {
CallingScreenSharingController,
} = require('./ts/components/CallingScreenSharingController');
const config = url.parse(window.location.toString(), true).query;
const { locale } = config;
const localeMessages = ipcRenderer.sendSync('locale-data');
setEnvironment(parseEnvironment(config.environment));
window.React = React;
window.ReactDOM = ReactDOM;
window.getAppInstance = () => config.appInstance;
window.getEnvironment = getEnvironment;
window.getVersion = () => config.version;
window.i18n = i18n.setup(locale, localeMessages);
let renderComponent;
window.registerScreenShareControllerRenderer = f => {
renderComponent = f;
};
function renderScreenSharingController(event, presentedSourceName) {
if (!renderComponent) {
setTimeout(renderScreenSharingController, 100);
return;
}
const props = {
i18n: window.i18n,
onCloseController: () => ipcRenderer.send('close-screen-share-controller'),
onStopSharing: () => ipcRenderer.send('stop-screen-share'),
presentedSourceName,
};
renderComponent(CallingScreenSharingController, props);
}
ipcRenderer.once(
'render-screen-sharing-controller',
renderScreenSharingController
);
require('./ts/logging/set_up_renderer_logging').initialize();

View File

@ -22,9 +22,6 @@
</head>
<body>
<div id="app"></div>
<script
type="application/javascript"
src="ts/windows/settings/init.js"
></script>
<script type="application/javascript" src="ts/windows/init.js"></script>
</body>
</html>

View File

@ -0,0 +1,22 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
.About {
align-items: center;
background-color: $color-ultramarine-icon;
color: $color-white;
display: flex;
font-size: 14px;
height: 100vh;
justify-content: center;
overflow: hidden;
text-align: center;
img {
margin-top: 1em;
}
a {
color: $color-white;
}
}

View File

@ -26,6 +26,7 @@
@import 'options';
// New style: components
@import './components/About.scss';
@import './components/AddGroupMembersModal.scss';
@import './components/AnnouncementsOnlyGroupBanner.scss';
@import './components/App.scss';

63
ts/components/About.tsx Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useEffect } from 'react';
import { LocalizerType } from '../types/Util';
export type PropsType = {
closeAbout: () => unknown;
environment: string;
i18n: LocalizerType;
version: string;
};
export const About = ({
closeAbout,
i18n,
environment,
version,
}: PropsType): JSX.Element => {
useEffect(() => {
const handler = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
closeAbout();
event.preventDefault();
event.stopPropagation();
}
};
document.addEventListener('keydown', handler);
return () => {
document.removeEventListener('keydown', handler);
};
}, [closeAbout]);
return (
<div className="About">
<div className="module-splash-screen">
<div className="module-splash-screen__logo module-img--150" />
<div className="version">{version}</div>
<div className="environment">{environment}</div>
<div>
<a href="https://signal.org">signal.org</a>
</div>
<br />
<div>
<a
className="acknowledgments"
href="https://github.com/signalapp/Signal-Desktop/blob/development/ACKNOWLEDGMENTS.md"
>
{i18n('softwareAcknowledgments')}
</a>
</div>
<div>
<a className="privacy" href="https://signal.org/legal">
{i18n('privacyPolicy')}
</a>
</div>
</div>
</div>
);
};

View File

@ -106,46 +106,6 @@
"updated": "2018-09-18T19:19:27.699Z",
"reasonDetail": "Very limited in what HTML can be injected - dark/light options specify colors for the light/dark parts of QRCode"
},
{
"rule": "jQuery-$(",
"path": "js/about_start.js",
"line": "$('.version').text(`v${window.getVersion()}`);",
"reasonCategory": "usageTrusted",
"updated": "2018-09-19T21:59:32.770Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/about_start.js",
"line": "$('.environment').text(states.join(' - '));",
"reasonCategory": "usageTrusted",
"updated": "2018-09-19T21:59:32.770Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/about_start.js",
"line": "$(document).on('keydown', e => {",
"reasonCategory": "usageTrusted",
"updated": "2018-09-19T21:59:32.770Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/about_start.js",
"line": "$('.acknowledgments').text(window.i18n('softwareAcknowledgments'));",
"reasonCategory": "usageTrusted",
"updated": "2020-09-16T14:49:26.520Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/about_start.js",
"line": "$('.privacy').text(window.i18n('privacyPolicy'));",
"reasonCategory": "usageTrusted",
"updated": "2020-09-16T14:49:26.520Z",
"reasonDetail": "Protected from arbitrary input"
},
{
"rule": "jQuery-$(",
"path": "js/debug_log_start.js",
@ -13944,4 +13904,4 @@
"reasonCategory": "usageTrusted",
"updated": "2021-07-22T03:00:34.561Z"
}
]
]

27
ts/window.d.ts vendored
View File

@ -85,10 +85,6 @@ import { ConversationModel } from './models/conversations';
import { combineNames } from './util';
import { BatcherType } from './util/batcher';
import { AttachmentList } from './components/conversation/AttachmentList';
import {
CallingScreenSharingController,
PropsType as CallingScreenSharingControllerProps,
} from './components/CallingScreenSharingController';
import { CaptionEditor } from './components/CaptionEditor';
import { ChatColorPicker } from './components/ChatColorPicker';
import { ConfirmationDialog } from './components/ConfirmationDialog';
@ -166,13 +162,6 @@ declare global {
WhatIsThis: WhatIsThis;
registerScreenShareControllerRenderer: (
f: (
component: typeof CallingScreenSharingController,
props: CallingScreenSharingControllerProps
) => void
) => void;
addSetupMenuItems: () => void;
attachmentDownloadQueue: Array<MessageModel> | undefined;
startupProcessingQueue: StartupQueue | undefined;
@ -497,16 +486,14 @@ declare global {
RETRY_DELAY: boolean;
// These elements are only available in the Settings window
SignalModule: {
registerReactRenderer: (
f: <P extends {}>(
component: FunctionComponent<P> | ComponentClass<P>,
props?: (Attributes & P) | null
) => void
) => void;
SignalWindow: {
config: string;
getAppInstance: () => string | undefined;
getEnvironment: () => string;
getVersion: () => string;
i18n: LocalizerType;
renderWindow: () => void;
};
renderPreferences: () => unknown;
}
// We want to extend `Error`, so we need an interface.

View File

@ -0,0 +1,34 @@
// Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import ReactDOM from 'react-dom';
import { contextBridge, ipcRenderer } from 'electron';
// It is important to call this as early as possible
import '../context';
import { SignalWindow } from '../configure';
import { About } from '../../components/About';
contextBridge.exposeInMainWorld('SignalWindow', {
...SignalWindow,
renderWindow: () => {
const environmentText: Array<string> = [SignalWindow.getEnvironment()];
const appInstance = SignalWindow.getAppInstance();
if (appInstance) {
environmentText.push(appInstance);
}
ReactDOM.render(
React.createElement(About, {
closeAbout: () => ipcRenderer.send('close-about'),
environment: environmentText.join(' - '),
i18n: SignalWindow.i18n,
version: SignalWindow.getVersion(),
}),
document.getElementById('app')
);
},
});

30
ts/windows/configure.ts Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import url from 'url';
import { ipcRenderer } from 'electron';
import i18n from '../../js/modules/i18n';
import {
getEnvironment,
parseEnvironment,
setEnvironment,
} from '../environment';
import { strictAssert } from '../util/assert';
const config = url.parse(window.location.toString(), true).query;
const { locale } = config;
strictAssert(locale, 'locale could not be parsed from config');
strictAssert(typeof locale === 'string', 'locale is not a string');
const localeMessages = ipcRenderer.sendSync('locale-data');
setEnvironment(parseEnvironment(config.environment));
export const SignalWindow = {
config,
getAppInstance: (): string | undefined =>
config.appInstance ? String(config.appInstance) : undefined,
getEnvironment,
getVersion: (): string => String(config.version),
i18n: i18n.setup(locale, localeMessages),
};

4
ts/windows/init.ts Normal file
View File

@ -0,0 +1,4 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
window.SignalWindow.renderWindow();

View File

@ -1,11 +0,0 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
// This needs to use window.React & window.ReactDOM since it's
// not commonJS compatible.
window.registerScreenShareControllerRenderer((Component, props) => {
window.ReactDOM.render(
window.React.createElement(Component, props),
document.getElementById('app')
);
});

View File

@ -0,0 +1,31 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import ReactDOM from 'react-dom';
import { contextBridge, ipcRenderer } from 'electron';
// It is important to call this as early as possible
import '../context';
import { SignalWindow } from '../configure';
import { CallingScreenSharingController } from '../../components/CallingScreenSharingController';
contextBridge.exposeInMainWorld('SignalWindow', SignalWindow);
function renderScreenSharingController(presentedSourceName: string): void {
ReactDOM.render(
React.createElement(CallingScreenSharingController, {
i18n: SignalWindow.i18n,
onCloseController: () =>
ipcRenderer.send('close-screen-share-controller'),
onStopSharing: () => ipcRenderer.send('stop-screen-share'),
presentedSourceName,
}),
document.getElementById('app')
);
}
ipcRenderer.once('render-screen-sharing-controller', (_, name: string) => {
renderScreenSharingController(name);
});

View File

@ -1,13 +0,0 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
// This needs to use window.React & window.ReactDOM since it's
// not commonJS compatible.
window.SignalModule.registerReactRenderer((Component, props) => {
window.ReactDOM.render(
window.React.createElement(Component, props),
document.getElementById('app')
);
});
window.renderPreferences();

View File

@ -1,20 +1,17 @@
// Copyright 2018-2021 Signal Messenger, LLC
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import ReactDOM from 'react-dom';
import url from 'url';
import { ipcRenderer } from 'electron';
import { contextBridge, ipcRenderer } from 'electron';
import { initialize as initializeLogging } from '../../logging/set_up_renderer_logging';
// It is important to call this as early as possible
import '../context';
import { SignalWindow } from '../configure';
import * as Settings from '../../types/Settings';
import i18n from '../../../js/modules/i18n';
import {
Preferences,
PropsType as PreferencesPropsType,
} from '../../components/Preferences';
import { Preferences } from '../../components/Preferences';
import {
SystemTraySetting,
parseSystemTraySetting,
@ -22,27 +19,7 @@ import {
} from '../../types/SystemTraySetting';
import { awaitObject } from '../../util/awaitObject';
import { createSetting, createCallback } from '../../util/preload';
import {
getEnvironment,
setEnvironment,
parseEnvironment,
} from '../../environment';
import { initialize as initializeLogging } from '../../logging/set_up_renderer_logging';
import { strictAssert } from '../../util/assert';
const config = url.parse(window.location.toString(), true).query;
const { locale } = config;
strictAssert(locale, 'locale could not be parsed from config');
strictAssert(typeof locale === 'string', 'locale is not a string');
const localeMessages = ipcRenderer.sendSync('locale-data');
setEnvironment(parseEnvironment(config.environment));
window.React = React;
window.ReactDOM = ReactDOM;
window.getEnvironment = getEnvironment;
window.getVersion = () => String(config.version);
window.i18n = i18n.setup(locale, localeMessages);
function doneRendering() {
ipcRenderer.send('settings-done-rendering');
}
@ -130,16 +107,6 @@ const ipcSetGlobalDefaultConversationColor = createCallback(
const DEFAULT_NOTIFICATION_SETTING = 'message';
let renderComponent: (
component: typeof Preferences,
props: PreferencesPropsType
) => void;
window.SignalModule = {
registerReactRenderer: f => {
renderComponent = f;
},
};
function getSystemTraySettingValues(
systemTraySetting: SystemTraySetting
): {
@ -161,11 +128,6 @@ function getSystemTraySettingValues(
}
const renderPreferences = async () => {
if (!renderComponent) {
setTimeout(window.renderPreferences, 100);
return;
}
const {
blockedCount,
deviceName,
@ -300,7 +262,7 @@ const renderPreferences = async () => {
editCustomColor: ipcEditCustomColor,
getConversationsWithCustomColor: ipcGetConversationsWithCustomColor,
initialSpellCheckSetting:
config.appStartInitialSpellcheckSetting === 'true',
SignalWindow.config.appStartInitialSpellcheckSetting === 'true',
makeSyncRequest: ipcMakeSyncRequest,
removeCustomColor: ipcRemoveCustomColor,
removeCustomColorOnConversations: ipcRemoveCustomColorOnConversations,
@ -316,7 +278,9 @@ const renderPreferences = async () => {
isNotificationAttentionSupported: Settings.isDrawAttentionSupported(),
isPhoneNumberSharingSupported,
isSyncSupported: !isSyncNotSupported,
isSystemTraySupported: Settings.isSystemTraySupported(window.getVersion()),
isSystemTraySupported: Settings.isSystemTraySupported(
SignalWindow.getVersion()
),
// Change handlers
onAudioNotificationsChange: reRender(settingAudioNotification.setValue),
@ -381,7 +345,7 @@ const renderPreferences = async () => {
// rerender.
onZoomFactorChange: settingZoomFactor.setValue,
i18n: window.i18n,
i18n: SignalWindow.i18n,
};
function reRender<Value>(f: (value: Value) => Promise<Value>) {
@ -391,10 +355,17 @@ const renderPreferences = async () => {
};
}
renderComponent(Preferences, props);
ReactDOM.render(
React.createElement(Preferences, props),
document.getElementById('app')
);
};
window.renderPreferences = renderPreferences;
initializeLogging();
ipcRenderer.on('render', () => renderPreferences());
contextBridge.exposeInMainWorld('SignalWindow', {
...SignalWindow,
renderWindow: renderPreferences,
});
initializeLogging();