Enables sandbox on about window

This commit is contained in:
Josh Perez 2023-03-14 11:55:31 -04:00 committed by GitHub
parent 58691b2f5e
commit 4591b56f7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 262 additions and 93 deletions

View file

@ -28,3 +28,5 @@ sticker-creator/**/*.js
.eslintrc.js .eslintrc.js
webpack.config.ts webpack.config.ts
preload.bundle.* preload.bundle.*
about.browser.bundle.*
about.preload.bundle.*

2
.gitignore vendored
View file

@ -26,6 +26,8 @@ libtextsecure/components.js
stylesheets/*.css stylesheets/*.css
/storybook-static/ /storybook-static/
preload.bundle.* preload.bundle.*
about.browser.bundle.*
about.preload.bundle.*
ts/sql/mainWorker.bundle.js.LICENSE.txt ts/sql/mainWorker.bundle.js.LICENSE.txt
# React / TypeScript # React / TypeScript

View file

@ -43,3 +43,5 @@ js/WebAudioRecorderMp3.js
stylesheets/_intlTelInput.scss stylesheets/_intlTelInput.scss
preload.bundle.* preload.bundle.*
about.browser.bundle.*
about.preload.bundle.*

View file

@ -30,5 +30,9 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="application/javascript" src="ts/windows/init.js"></script> <script type="application/javascript" src="ts/windows/init.js"></script>
<script
type="application/javascript"
src="about.browser.bundle.js"
></script>
</body> </body>
</html> </html>

View file

@ -1253,7 +1253,7 @@ async function showAbout() {
nodeIntegrationInWorker: false, nodeIntegrationInWorker: false,
sandbox: false, sandbox: false,
contextIsolation: true, contextIsolation: true,
preload: join(__dirname, '../ts/windows/about/preload.js'), preload: join(__dirname, '../about.preload.bundle.js'),
nativeWindowOpen: true, nativeWindowOpen: true,
}, },
}; };
@ -2357,6 +2357,11 @@ ipc.on('locale-data', event => {
event.returnValue = getResolvedMessagesLocale().messages; event.returnValue = getResolvedMessagesLocale().messages;
}); });
ipc.on('getHasCustomTitleBar', event => {
// eslint-disable-next-line no-param-reassign
event.returnValue = OS.hasCustomTitleBar();
});
ipc.on('user-config-key', event => { ipc.on('user-config-key', event => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
event.returnValue = userConfig.get('key'); event.returnValue = userConfig.get('key');

View file

@ -462,6 +462,8 @@
"app/*", "app/*",
"preload.bundle.js", "preload.bundle.js",
"preload_utils.js", "preload_utils.js",
"about.preload.bundle.js",
"about.browser.bundle.js",
"main.js", "main.js",
"images/**", "images/**",
"fonts/**", "fonts/**",

View file

@ -98,3 +98,18 @@ main().catch(error => {
console.error(error.stack); console.error(error.stack);
process.exit(1); process.exit(1);
}); });
// About bundle
esbuild.build({
...bundleDefaults,
mainFields: ['browser', 'main'],
entryPoints: [path.join(ROOT_DIR, 'ts', 'windows', 'about', 'app.tsx')],
outfile: path.join(ROOT_DIR, 'about.browser.bundle.js'),
});
esbuild.build({
...bundleDefaults,
mainFields: ['browser', 'main'],
entryPoints: [path.join(ROOT_DIR, 'ts', 'windows', 'about', 'preload.ts')],
outfile: path.join(ROOT_DIR, 'about.preload.bundle.js'),
});

View file

@ -148,7 +148,7 @@ import { deleteAllLogs } from './util/deleteAllLogs';
import { ToastCaptchaFailed } from './components/ToastCaptchaFailed'; import { ToastCaptchaFailed } from './components/ToastCaptchaFailed';
import { ToastCaptchaSolved } from './components/ToastCaptchaSolved'; import { ToastCaptchaSolved } from './components/ToastCaptchaSolved';
import { showToast } from './util/showToast'; import { showToast } from './util/showToast';
import { startInteractionMode } from './windows/startInteractionMode'; import { startInteractionMode } from './services/InteractionMode';
import type { MainWindowStatsType } from './windows/context'; import type { MainWindowStatsType } from './windows/context';
import { ReactionSource } from './reactions/ReactionSource'; import { ReactionSource } from './reactions/ReactionSource';
import { singleProtoJobQueue } from './jobs/singleProtoJobQueue'; import { singleProtoJobQueue } from './jobs/singleProtoJobQueue';

View file

@ -3,28 +3,28 @@
import React from 'react'; import React from 'react';
import type { ExecuteMenuRoleType } from './TitleBarContainer';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import { TitleBarContainer } from './TitleBarContainer';
import { useEscapeHandling } from '../hooks/useEscapeHandling'; import { useEscapeHandling } from '../hooks/useEscapeHandling';
import { useTheme } from '../hooks/useTheme'; import { useTheme } from '../hooks/useTheme';
import { TitleBarContainer } from './TitleBarContainer';
import type { ExecuteMenuRoleType } from './TitleBarContainer';
export type PropsType = { export type PropsType = {
closeAbout: () => unknown; closeAbout: () => unknown;
environment: string; environment: string;
executeMenuRole: ExecuteMenuRoleType;
hasCustomTitleBar: boolean;
i18n: LocalizerType; i18n: LocalizerType;
version: string; version: string;
hasCustomTitleBar: boolean;
executeMenuRole: ExecuteMenuRoleType;
}; };
export function About({ export function About({
closeAbout, closeAbout,
i18n,
environment, environment,
version,
hasCustomTitleBar,
executeMenuRole, executeMenuRole,
hasCustomTitleBar,
i18n,
version,
}: PropsType): JSX.Element { }: PropsType): JSX.Element {
useEscapeHandling(closeAbout); useEscapeHandling(closeAbout);

View file

@ -10,6 +10,7 @@ import type { Theme } from '../util/theme';
import { themeClassName } from '../util/theme'; import { themeClassName } from '../util/theme';
import { refMerger } from '../util/refMerger'; import { refMerger } from '../util/refMerger';
import { offsetDistanceModifier } from '../util/popperUtil'; import { offsetDistanceModifier } from '../util/popperUtil';
import { getInteractionMode } from '../services/InteractionMode';
type EventWrapperPropsType = { type EventWrapperPropsType = {
children: React.ReactNode; children: React.ReactNode;
@ -35,7 +36,7 @@ const TooltipEventWrapper = React.forwardRef<
}, [onHoverChanged]); }, [onHoverChanged]);
const onFocus = React.useCallback(() => { const onFocus = React.useCallback(() => {
if (window.getInteractionMode() === 'keyboard') { if (getInteractionMode() === 'keyboard') {
on(); on();
} }
}, [on]); }, [on]);

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import React from 'react'; import React from 'react';
import { getInteractionMode } from '../../services/InteractionMode';
export type PropsType = { export type PropsType = {
id: string; id: string;
@ -22,7 +23,7 @@ export class InlineNotificationWrapper extends React.Component<PropsType> {
}; };
public handleFocus = (): void => { public handleFocus = (): void => {
if (window.getInteractionMode() === 'keyboard') { if (getInteractionMode() === 'keyboard') {
this.setSelected(); this.setSelected();
} }
}; };

View file

@ -0,0 +1,12 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { ipcRenderer } from 'electron';
import { getActiveWindowService } from '../services/ActiveWindowService';
const activeWindowService = getActiveWindowService(
window.document,
ipcRenderer
);
export { activeWindowService };

12
ts/context/config.ts Normal file
View file

@ -0,0 +1,12 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { RendererConfigType } from '../types/RendererConfig';
import { strictAssert } from '../util/assert';
const params = new URLSearchParams(document.location.search);
const configParam = params.get('config');
strictAssert(typeof configParam === 'string', 'config is not a string');
const config: RendererConfigType = JSON.parse(configParam);
export { config };

15
ts/context/environment.ts Normal file
View file

@ -0,0 +1,15 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { config } from './config';
import {
getEnvironment,
parseEnvironment,
setEnvironment,
} from '../environment';
setEnvironment(parseEnvironment(config.environment));
const environment = getEnvironment();
export { environment };

22
ts/context/i18n.ts Normal file
View file

@ -0,0 +1,22 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { ipcRenderer } from 'electron';
import { config } from './config';
import { setupI18n } from '../util/setupI18n';
import { strictAssert } from '../util/assert';
const { resolvedTranslationsLocale } = config;
strictAssert(
resolvedTranslationsLocale,
'locale could not be parsed from config'
);
strictAssert(
typeof resolvedTranslationsLocale === 'string',
'locale is not a string'
);
const localeMessages = ipcRenderer.sendSync('locale-data');
const i18n = setupI18n(resolvedTranslationsLocale, localeMessages);
export { i18n };

View file

@ -16,7 +16,7 @@ const ACTIVE_EVENTS = [
'wheel', 'wheel',
]; ];
export class ActiveWindowService { class ActiveWindowService {
// This starting value might be wrong but we should get an update from the main process // This starting value might be wrong but we should get an update from the main process
// soon. We'd rather report that the window is inactive so we can show notifications. // soon. We'd rather report that the window is inactive so we can show notifications.
private isInitialized = false; private isInitialized = false;
@ -113,3 +113,37 @@ export class ActiveWindowService {
} }
} }
} }
export type ActiveWindowServiceType = {
isActive(): boolean;
registerForActive(callback: () => void): void;
unregisterForActive(callback: () => void): void;
registerForChange(callback: (isActive: boolean) => void): void;
unregisterForChange(callback: (isActive: boolean) => void): void;
};
export function getActiveWindowService(
document: EventTarget,
ipc: NodeJS.EventEmitter
): ActiveWindowServiceType {
const activeWindowService = new ActiveWindowService();
activeWindowService.initialize(document, ipc);
return {
isActive(): boolean {
return activeWindowService.isActive();
},
registerForActive(callback: () => void): void {
return activeWindowService.registerForActive(callback);
},
unregisterForActive(callback: () => void): void {
return activeWindowService.unregisterForActive(callback);
},
registerForChange(callback: (isActive: boolean) => void): void {
return activeWindowService.registerForChange(callback);
},
unregisterForChange(callback: (isActive: boolean) => void): void {
return activeWindowService.unregisterForChange(callback);
},
};
}

View file

@ -1,8 +1,10 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
type InteractionModeType = 'mouse' | 'keyboard';
let initialized = false; let initialized = false;
let interactionMode: 'mouse' | 'keyboard' = 'mouse'; let interactionMode: InteractionModeType = 'mouse';
export function startInteractionMode(): void { export function startInteractionMode(): void {
if (initialized) { if (initialized) {
@ -66,6 +68,8 @@ export function startInteractionMode(): void {
); );
document.addEventListener('wheel', window.enterMouseMode, true); document.addEventListener('wheel', window.enterMouseMode, true);
document.addEventListener('mousedown', window.enterMouseMode, true); document.addEventListener('mousedown', window.enterMouseMode, true);
}
window.getInteractionMode = () => interactionMode;
export function getInteractionMode(): InteractionModeType {
return interactionMode;
} }

View file

@ -36,6 +36,7 @@ import { UUIDKind } from '../types/UUID';
import { getEmojiReducerState as emojis } from '../util/loadRecentEmojis'; import { getEmojiReducerState as emojis } from '../util/loadRecentEmojis';
import { getInitialState as stickers } from '../types/Stickers'; import { getInitialState as stickers } from '../types/Stickers';
import { getThemeType } from '../util/getThemeType'; import { getThemeType } from '../util/getThemeType';
import { getInteractionMode } from '../services/InteractionMode';
export function getInitialState({ export function getInitialState({
badges, badges,
@ -137,7 +138,7 @@ export function getInitialState({
...user(), ...user(),
attachmentsPath: window.BasePaths.attachments, attachmentsPath: window.BasePaths.attachments,
i18n: window.i18n, i18n: window.i18n,
interactionMode: window.getInteractionMode(), interactionMode: getInteractionMode(),
isMainWindowFullScreen: mainWindowStats.isFullScreen, isMainWindowFullScreen: mainWindowStats.isFullScreen,
isMainWindowMaximized: mainWindowStats.isMaximized, isMainWindowMaximized: mainWindowStats.isMaximized,
localeMessages: window.SignalContext.localeMessages, localeMessages: window.SignalContext.localeMessages,

View file

@ -5,7 +5,7 @@ import { assert } from 'chai';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { ActiveWindowService } from '../../services/ActiveWindowService'; import { getActiveWindowService } from '../../services/ActiveWindowService';
describe('ActiveWindowService', () => { describe('ActiveWindowService', () => {
const fakeIpcEvent = {}; const fakeIpcEvent = {};
@ -23,16 +23,17 @@ describe('ActiveWindowService', () => {
} }
it('is inactive at the start', () => { it('is inactive at the start', () => {
const service = new ActiveWindowService(); const service = getActiveWindowService(
service.initialize(createFakeDocument(), new EventEmitter()); createFakeDocument(),
new EventEmitter()
);
assert.isFalse(service.isActive()); assert.isFalse(service.isActive());
}); });
it('becomes active after focusing', () => { it('becomes active after focusing', () => {
const fakeIpc = new EventEmitter(); const fakeIpc = new EventEmitter();
const service = new ActiveWindowService(); const service = getActiveWindowService(createFakeDocument(), fakeIpc);
service.initialize(createFakeDocument(), fakeIpc);
fakeIpc.emit('set-window-focus', fakeIpcEvent, true); fakeIpc.emit('set-window-focus', fakeIpcEvent, true);
@ -41,8 +42,7 @@ describe('ActiveWindowService', () => {
it('becomes inactive after 15 seconds without interaction', function test() { it('becomes inactive after 15 seconds without interaction', function test() {
const fakeIpc = new EventEmitter(); const fakeIpc = new EventEmitter();
const service = new ActiveWindowService(); const service = getActiveWindowService(createFakeDocument(), fakeIpc);
service.initialize(createFakeDocument(), fakeIpc);
fakeIpc.emit('set-window-focus', fakeIpcEvent, true); fakeIpc.emit('set-window-focus', fakeIpcEvent, true);
@ -61,8 +61,7 @@ describe('ActiveWindowService', () => {
it(`is inactive even in the face of ${eventName} events if unfocused`, function test() { it(`is inactive even in the face of ${eventName} events if unfocused`, function test() {
const fakeDocument = createFakeDocument(); const fakeDocument = createFakeDocument();
const fakeIpc = new EventEmitter(); const fakeIpc = new EventEmitter();
const service = new ActiveWindowService(); const service = getActiveWindowService(fakeDocument, fakeIpc);
service.initialize(fakeDocument, fakeIpc);
fakeIpc.emit('set-window-focus', fakeIpcEvent, false); fakeIpc.emit('set-window-focus', fakeIpcEvent, false);
@ -73,8 +72,7 @@ describe('ActiveWindowService', () => {
it(`stays active if focused and receiving ${eventName} events`, function test() { it(`stays active if focused and receiving ${eventName} events`, function test() {
const fakeDocument = createFakeDocument(); const fakeDocument = createFakeDocument();
const fakeIpc = new EventEmitter(); const fakeIpc = new EventEmitter();
const service = new ActiveWindowService(); const service = getActiveWindowService(fakeDocument, fakeIpc);
service.initialize(fakeDocument, fakeIpc);
fakeIpc.emit('set-window-focus', fakeIpcEvent, true); fakeIpc.emit('set-window-focus', fakeIpcEvent, true);
@ -94,8 +92,7 @@ describe('ActiveWindowService', () => {
it('calls callbacks when going from unfocused to focused', () => { it('calls callbacks when going from unfocused to focused', () => {
const fakeIpc = new EventEmitter(); const fakeIpc = new EventEmitter();
const service = new ActiveWindowService(); const service = getActiveWindowService(createFakeDocument(), fakeIpc);
service.initialize(createFakeDocument(), fakeIpc);
const callback = sinon.stub(); const callback = sinon.stub();
service.registerForActive(callback); service.registerForActive(callback);
@ -108,8 +105,7 @@ describe('ActiveWindowService', () => {
it('calls callbacks when receiving a click event after being focused', function test() { it('calls callbacks when receiving a click event after being focused', function test() {
const fakeDocument = createFakeDocument(); const fakeDocument = createFakeDocument();
const fakeIpc = new EventEmitter(); const fakeIpc = new EventEmitter();
const service = new ActiveWindowService(); const service = getActiveWindowService(fakeDocument, fakeIpc);
service.initialize(fakeDocument, fakeIpc);
fakeIpc.emit('set-window-focus', fakeIpcEvent, true); fakeIpc.emit('set-window-focus', fakeIpcEvent, true);
@ -125,8 +121,7 @@ describe('ActiveWindowService', () => {
it('only calls callbacks every 5 seconds; it is throttled', function test() { it('only calls callbacks every 5 seconds; it is throttled', function test() {
const fakeIpc = new EventEmitter(); const fakeIpc = new EventEmitter();
const service = new ActiveWindowService(); const service = getActiveWindowService(createFakeDocument(), fakeIpc);
service.initialize(createFakeDocument(), fakeIpc);
const callback = sinon.stub(); const callback = sinon.stub();
service.registerForActive(callback); service.registerForActive(callback);
@ -150,8 +145,7 @@ describe('ActiveWindowService', () => {
it('can remove callbacks', () => { it('can remove callbacks', () => {
const fakeDocument = createFakeDocument(); const fakeDocument = createFakeDocument();
const fakeIpc = new EventEmitter(); const fakeIpc = new EventEmitter();
const service = new ActiveWindowService(); const service = getActiveWindowService(fakeDocument, fakeIpc);
service.initialize(fakeDocument, fakeIpc);
const callback = sinon.stub(); const callback = sinon.stub();
service.registerForActive(callback); service.registerForActive(callback);

View file

@ -24,6 +24,8 @@ const excludedFilesRegexp = RegExp(
[ [
'^release/', '^release/',
'^preload.bundle.js(LICENSE.txt|map)?', '^preload.bundle.js(LICENSE.txt|map)?',
'^about.browser.bundle.js(LICENSE.txt|map)?',
'^about.preload.bundle.js(LICENSE.txt|map)?',
'^storybook-static/', '^storybook-static/',
// Non-distributed files // Non-distributed files

10
ts/window.d.ts vendored
View file

@ -3,6 +3,7 @@
// Captures the globals put in place by preload.js, background.js and others // Captures the globals put in place by preload.js, background.js and others
import type { MenuItemConstructorOptions } from 'electron';
import type { Store } from 'redux'; import type { Store } from 'redux';
import type * as Backbone from 'backbone'; import type * as Backbone from 'backbone';
import type PQueue from 'p-queue/dist'; import type PQueue from 'p-queue/dist';
@ -101,7 +102,16 @@ export type FeatureFlagType = {
GV2_MIGRATION_DISABLE_INVITE: boolean; GV2_MIGRATION_DISABLE_INVITE: boolean;
}; };
type AboutWindowType = {
environmentText: string;
executeMenuRole: (role: MenuItemConstructorOptions['role']) => Promise<void>;
hasCustomTitleBar: boolean;
i18n: LocalizerType;
version: string;
};
export type SignalCoreType = { export type SignalCoreType = {
AboutWindow?: AboutWindowType;
Crypto: typeof Crypto; Crypto: typeof Crypto;
Curve: typeof Curve; Curve: typeof Curve;
Data: typeof Data; Data: typeof Data;

24
ts/windows/about/app.tsx Normal file
View file

@ -0,0 +1,24 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import ReactDOM from 'react-dom';
import { About } from '../../components/About';
import { strictAssert } from '../../util/assert';
const { AboutWindow } = window.Signal;
strictAssert(AboutWindow, 'window values not provided');
ReactDOM.render(
<About
closeAbout={() => AboutWindow.executeMenuRole('close')}
environment={AboutWindow.environmentText}
executeMenuRole={AboutWindow.executeMenuRole}
hasCustomTitleBar={AboutWindow.hasCustomTitleBar}
i18n={AboutWindow.i18n}
version={AboutWindow.version}
/>,
document.getElementById('app')
);

View file

@ -1,42 +1,63 @@
// Copyright 2018 Signal Messenger, LLC // Copyright 2018 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import React from 'react'; import type { MenuItemConstructorOptions } from 'electron';
import ReactDOM from 'react-dom'; import { contextBridge, ipcRenderer } from 'electron';
import { contextBridge } from 'electron'; import { activeWindowService } from '../../context/activeWindowService';
import { config } from '../../context/config';
import { createNativeThemeListener } from '../../context/createNativeThemeListener';
import { createSetting } from '../../util/preload';
import { environment } from '../../context/environment';
import { getClassName } from '../../OS';
import { i18n } from '../../context/i18n';
import { waitForSettingsChange } from '../../context/waitForSettingsChange';
import { SignalContext } from '../context'; async function executeMenuRole(
import { About } from '../../components/About'; role: MenuItemConstructorOptions['role']
): Promise<void> {
await ipcRenderer.invoke('executeMenuRole', role);
}
contextBridge.exposeInMainWorld('SignalContext', { const environments: Array<string> = [environment];
...SignalContext,
renderWindow: () => {
const environmentText: Array<string> = [SignalContext.getEnvironment()];
const appInstance = SignalContext.getAppInstance(); if (config.appInstance) {
if (appInstance) { environments.push(String(config.appInstance));
environmentText.push(appInstance); }
}
let platform = ''; let platform = '';
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
if (process.arch === 'arm64') { if (process.arch === 'arm64') {
platform = ` (${SignalContext.i18n('appleSilicon')})`; platform = ` (${i18n('appleSilicon')})`;
} else { } else {
platform = ' (Intel)'; platform = ' (Intel)';
} }
} }
ReactDOM.render( const environmentText = `${environments.join(' - ')}${platform}`;
React.createElement(About, { const hasCustomTitleBar = ipcRenderer.sendSync('getHasCustomTitleBar');
closeAbout: () => SignalContext.executeMenuRole('close'),
environment: `${environmentText.join(' - ')}${platform}`, const Signal = {
i18n: SignalContext.i18n, AboutWindow: {
version: SignalContext.getVersion(), environmentText,
hasCustomTitleBar: SignalContext.OS.hasCustomTitleBar(), executeMenuRole,
executeMenuRole: SignalContext.executeMenuRole, hasCustomTitleBar,
}), i18n,
document.getElementById('app') version: String(config.version),
);
}, },
}); };
contextBridge.exposeInMainWorld('Signal', Signal);
// TODO DESKTOP-5054
const SignalContext = {
activeWindowService,
OS: {
getClassName,
hasCustomTitleBar: () => hasCustomTitleBar,
},
Settings: {
themeSetting: createSetting('themeSetting', { setter: false }),
waitForChange: waitForSettingsChange,
},
nativeThemeListener: createNativeThemeListener(ipcRenderer, window),
};
contextBridge.exposeInMainWorld('SignalContext', SignalContext);

View file

@ -12,13 +12,15 @@ import type { LocaleMessagesType } from '../types/I18N';
import type { NativeThemeType } from '../context/createNativeThemeListener'; import type { NativeThemeType } from '../context/createNativeThemeListener';
import type { SettingType } from '../util/preload'; import type { SettingType } from '../util/preload';
import type { RendererConfigType } from '../types/RendererConfig'; import type { RendererConfigType } from '../types/RendererConfig';
import { ActiveWindowService } from '../services/ActiveWindowService';
import { Bytes } from '../context/Bytes'; import { Bytes } from '../context/Bytes';
import { Crypto } from '../context/Crypto'; import { Crypto } from '../context/Crypto';
import { Timers } from '../context/Timers'; import { Timers } from '../context/Timers';
import { setupI18n } from '../util/setupI18n'; import type { ActiveWindowServiceType } from '../services/ActiveWindowService';
import { config } from '../context/config';
import { i18n } from '../context/i18n';
import { activeWindowService } from '../context/activeWindowService';
import { import {
getEnvironment, getEnvironment,
parseEnvironment, parseEnvironment,
@ -27,7 +29,7 @@ import {
import { strictAssert } from '../util/assert'; import { strictAssert } from '../util/assert';
import { createSetting } from '../util/preload'; import { createSetting } from '../util/preload';
import { initialize as initializeLogging } from '../logging/set_up_renderer_logging'; import { initialize as initializeLogging } from '../logging/set_up_renderer_logging';
import { waitForSettingsChange } from './waitForSettingsChange'; import { waitForSettingsChange } from '../context/waitForSettingsChange';
import { createNativeThemeListener } from '../context/createNativeThemeListener'; import { createNativeThemeListener } from '../context/createNativeThemeListener';
import { import {
isWindows, isWindows,
@ -37,24 +39,6 @@ import {
getClassName, getClassName,
} from '../OS'; } from '../OS';
const activeWindowService = new ActiveWindowService();
activeWindowService.initialize(window.document, ipcRenderer);
const params = new URLSearchParams(document.location.search);
const configParam = params.get('config');
strictAssert(typeof configParam === 'string', 'config is not a string');
const config: RendererConfigType = JSON.parse(configParam);
const { resolvedTranslationsLocale } = config;
strictAssert(
resolvedTranslationsLocale,
'locale could not be parsed from config'
);
strictAssert(
typeof resolvedTranslationsLocale === 'string',
'locale is not a string'
);
const localeMessages = ipcRenderer.sendSync('locale-data'); const localeMessages = ipcRenderer.sendSync('locale-data');
setEnvironment(parseEnvironment(config.environment)); setEnvironment(parseEnvironment(config.environment));
@ -74,7 +58,7 @@ export type SignalContextType = {
nativeThemeListener: NativeThemeType; nativeThemeListener: NativeThemeType;
setIsCallActive: (isCallActive: boolean) => unknown; setIsCallActive: (isCallActive: boolean) => unknown;
activeWindowService: typeof activeWindowService; activeWindowService: ActiveWindowServiceType;
Settings: { Settings: {
themeSetting: SettingType<IPCEventsValuesType['themeSetting']>; themeSetting: SettingType<IPCEventsValuesType['themeSetting']>;
waitForChange: () => Promise<void>; waitForChange: () => Promise<void>;
@ -128,7 +112,7 @@ export const SignalContext: SignalContextType = {
getPath: (name: 'userData' | 'home'): string => { getPath: (name: 'userData' | 'home'): string => {
return String(config[`${name}Path`]); return String(config[`${name}Path`]);
}, },
i18n: setupI18n(resolvedTranslationsLocale, localeMessages), i18n,
localeMessages, localeMessages,
log: window.SignalContext.log, log: window.SignalContext.log,
nativeThemeListener: createNativeThemeListener(ipcRenderer, window), nativeThemeListener: createNativeThemeListener(ipcRenderer, window),

View file

@ -8,6 +8,6 @@ if (window.SignalContext.OS.hasCustomTitleBar()) {
if (window.SignalContext.renderWindow) { if (window.SignalContext.renderWindow) {
window.SignalContext.renderWindow(); window.SignalContext.renderWindow();
} else { } else if (window.SignalContext.log) {
window.SignalContext.log.error('renderWindow is undefined!'); window.SignalContext.log.error('renderWindow is undefined!');
} }

View file

@ -16,7 +16,7 @@ import {
import { awaitObject } from '../../util/awaitObject'; import { awaitObject } from '../../util/awaitObject';
import { DurationInSeconds } from '../../util/durations'; import { DurationInSeconds } from '../../util/durations';
import { createSetting, createCallback } from '../../util/preload'; import { createSetting, createCallback } from '../../util/preload';
import { startInteractionMode } from '../startInteractionMode'; import { startInteractionMode } from '../../services/InteractionMode';
function doneRendering() { function doneRendering() {
ipcRenderer.send('settings-done-rendering'); ipcRenderer.send('settings-done-rendering');