From 4591b56f7f7c1b9a8f857e37714f15ff78c0e4a8 Mon Sep 17 00:00:00 2001 From: Josh Perez <60019601+josh-signal@users.noreply.github.com> Date: Tue, 14 Mar 2023 11:55:31 -0400 Subject: [PATCH] Enables sandbox on about window --- .eslintignore | 2 + .gitignore | 2 + .prettierignore | 2 + about.html | 4 + app/main.ts | 7 +- package.json | 2 + scripts/esbuild.js | 15 ++++ ts/background.ts | 2 +- ts/components/About.tsx | 14 +-- ts/components/Tooltip.tsx | 3 +- .../InlineNotificationWrapper.tsx | 3 +- ts/context/activeWindowService.ts | 12 +++ ts/context/config.ts | 12 +++ ts/context/environment.ts | 15 ++++ ts/context/i18n.ts | 22 +++++ .../waitForSettingsChange.ts | 0 ts/services/ActiveWindowService.ts | 36 +++++++- .../InteractionMode.ts} | 10 ++- ts/state/getInitialState.ts | 3 +- .../services/ActiveWindowService_test.ts | 32 +++---- ts/util/lint/linter.ts | 2 + ts/window.d.ts | 10 +++ ts/windows/about/app.tsx | 24 +++++ ts/windows/about/preload.ts | 87 ++++++++++++------- ts/windows/context.ts | 30 ++----- ts/windows/init.ts | 2 +- ts/windows/settings/preload.ts | 2 +- 27 files changed, 262 insertions(+), 93 deletions(-) create mode 100644 ts/context/activeWindowService.ts create mode 100644 ts/context/config.ts create mode 100644 ts/context/environment.ts create mode 100644 ts/context/i18n.ts rename ts/{windows => context}/waitForSettingsChange.ts (100%) rename ts/{windows/startInteractionMode.ts => services/InteractionMode.ts} (89%) create mode 100644 ts/windows/about/app.tsx diff --git a/.eslintignore b/.eslintignore index c6631e5f6873..1ec3c5e12a98 100644 --- a/.eslintignore +++ b/.eslintignore @@ -28,3 +28,5 @@ sticker-creator/**/*.js .eslintrc.js webpack.config.ts preload.bundle.* +about.browser.bundle.* +about.preload.bundle.* diff --git a/.gitignore b/.gitignore index 881b436355cd..1a0e01389ffe 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,8 @@ libtextsecure/components.js stylesheets/*.css /storybook-static/ preload.bundle.* +about.browser.bundle.* +about.preload.bundle.* ts/sql/mainWorker.bundle.js.LICENSE.txt # React / TypeScript diff --git a/.prettierignore b/.prettierignore index c4bdad39484e..d404a3229150 100644 --- a/.prettierignore +++ b/.prettierignore @@ -43,3 +43,5 @@ js/WebAudioRecorderMp3.js stylesheets/_intlTelInput.scss preload.bundle.* +about.browser.bundle.* +about.preload.bundle.* diff --git a/about.html b/about.html index 81185ccefdf5..e5e5e921d3dd 100644 --- a/about.html +++ b/about.html @@ -30,5 +30,9 @@
+ diff --git a/app/main.ts b/app/main.ts index 595a5ef81ee2..fdd964905a74 100644 --- a/app/main.ts +++ b/app/main.ts @@ -1253,7 +1253,7 @@ async function showAbout() { nodeIntegrationInWorker: false, sandbox: false, contextIsolation: true, - preload: join(__dirname, '../ts/windows/about/preload.js'), + preload: join(__dirname, '../about.preload.bundle.js'), nativeWindowOpen: true, }, }; @@ -2357,6 +2357,11 @@ ipc.on('locale-data', event => { 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 => { // eslint-disable-next-line no-param-reassign event.returnValue = userConfig.get('key'); diff --git a/package.json b/package.json index 92046b5b86ca..5a18d98046fd 100644 --- a/package.json +++ b/package.json @@ -462,6 +462,8 @@ "app/*", "preload.bundle.js", "preload_utils.js", + "about.preload.bundle.js", + "about.browser.bundle.js", "main.js", "images/**", "fonts/**", diff --git a/scripts/esbuild.js b/scripts/esbuild.js index d506969b6156..064df944aa6d 100644 --- a/scripts/esbuild.js +++ b/scripts/esbuild.js @@ -98,3 +98,18 @@ main().catch(error => { console.error(error.stack); 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'), +}); diff --git a/ts/background.ts b/ts/background.ts index 4bc5714c56c6..9f6fb95e07da 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -148,7 +148,7 @@ import { deleteAllLogs } from './util/deleteAllLogs'; import { ToastCaptchaFailed } from './components/ToastCaptchaFailed'; import { ToastCaptchaSolved } from './components/ToastCaptchaSolved'; import { showToast } from './util/showToast'; -import { startInteractionMode } from './windows/startInteractionMode'; +import { startInteractionMode } from './services/InteractionMode'; import type { MainWindowStatsType } from './windows/context'; import { ReactionSource } from './reactions/ReactionSource'; import { singleProtoJobQueue } from './jobs/singleProtoJobQueue'; diff --git a/ts/components/About.tsx b/ts/components/About.tsx index 9b297fa6b7f0..4346dc06bc1d 100644 --- a/ts/components/About.tsx +++ b/ts/components/About.tsx @@ -3,28 +3,28 @@ import React from 'react'; +import type { ExecuteMenuRoleType } from './TitleBarContainer'; import type { LocalizerType } from '../types/Util'; +import { TitleBarContainer } from './TitleBarContainer'; import { useEscapeHandling } from '../hooks/useEscapeHandling'; import { useTheme } from '../hooks/useTheme'; -import { TitleBarContainer } from './TitleBarContainer'; -import type { ExecuteMenuRoleType } from './TitleBarContainer'; export type PropsType = { closeAbout: () => unknown; environment: string; + executeMenuRole: ExecuteMenuRoleType; + hasCustomTitleBar: boolean; i18n: LocalizerType; version: string; - hasCustomTitleBar: boolean; - executeMenuRole: ExecuteMenuRoleType; }; export function About({ closeAbout, - i18n, environment, - version, - hasCustomTitleBar, executeMenuRole, + hasCustomTitleBar, + i18n, + version, }: PropsType): JSX.Element { useEscapeHandling(closeAbout); diff --git a/ts/components/Tooltip.tsx b/ts/components/Tooltip.tsx index 1783e46ae337..4f16732eae80 100644 --- a/ts/components/Tooltip.tsx +++ b/ts/components/Tooltip.tsx @@ -10,6 +10,7 @@ import type { Theme } from '../util/theme'; import { themeClassName } from '../util/theme'; import { refMerger } from '../util/refMerger'; import { offsetDistanceModifier } from '../util/popperUtil'; +import { getInteractionMode } from '../services/InteractionMode'; type EventWrapperPropsType = { children: React.ReactNode; @@ -35,7 +36,7 @@ const TooltipEventWrapper = React.forwardRef< }, [onHoverChanged]); const onFocus = React.useCallback(() => { - if (window.getInteractionMode() === 'keyboard') { + if (getInteractionMode() === 'keyboard') { on(); } }, [on]); diff --git a/ts/components/conversation/InlineNotificationWrapper.tsx b/ts/components/conversation/InlineNotificationWrapper.tsx index b63f8a282196..fa82f09c3b07 100644 --- a/ts/components/conversation/InlineNotificationWrapper.tsx +++ b/ts/components/conversation/InlineNotificationWrapper.tsx @@ -2,6 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import React from 'react'; +import { getInteractionMode } from '../../services/InteractionMode'; export type PropsType = { id: string; @@ -22,7 +23,7 @@ export class InlineNotificationWrapper extends React.Component { }; public handleFocus = (): void => { - if (window.getInteractionMode() === 'keyboard') { + if (getInteractionMode() === 'keyboard') { this.setSelected(); } }; diff --git a/ts/context/activeWindowService.ts b/ts/context/activeWindowService.ts new file mode 100644 index 000000000000..0e5dc866733c --- /dev/null +++ b/ts/context/activeWindowService.ts @@ -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 }; diff --git a/ts/context/config.ts b/ts/context/config.ts new file mode 100644 index 000000000000..c67f20adf4c1 --- /dev/null +++ b/ts/context/config.ts @@ -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 }; diff --git a/ts/context/environment.ts b/ts/context/environment.ts new file mode 100644 index 000000000000..7171edebcaf4 --- /dev/null +++ b/ts/context/environment.ts @@ -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 }; diff --git a/ts/context/i18n.ts b/ts/context/i18n.ts new file mode 100644 index 000000000000..edf36636c287 --- /dev/null +++ b/ts/context/i18n.ts @@ -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 }; diff --git a/ts/windows/waitForSettingsChange.ts b/ts/context/waitForSettingsChange.ts similarity index 100% rename from ts/windows/waitForSettingsChange.ts rename to ts/context/waitForSettingsChange.ts diff --git a/ts/services/ActiveWindowService.ts b/ts/services/ActiveWindowService.ts index a63420e3318b..402502ff2e15 100644 --- a/ts/services/ActiveWindowService.ts +++ b/ts/services/ActiveWindowService.ts @@ -16,7 +16,7 @@ const ACTIVE_EVENTS = [ 'wheel', ]; -export class ActiveWindowService { +class ActiveWindowService { // 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. 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); + }, + }; +} diff --git a/ts/windows/startInteractionMode.ts b/ts/services/InteractionMode.ts similarity index 89% rename from ts/windows/startInteractionMode.ts rename to ts/services/InteractionMode.ts index 68f266f2a96a..d3b015d72539 100644 --- a/ts/windows/startInteractionMode.ts +++ b/ts/services/InteractionMode.ts @@ -1,8 +1,10 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only +type InteractionModeType = 'mouse' | 'keyboard'; + let initialized = false; -let interactionMode: 'mouse' | 'keyboard' = 'mouse'; +let interactionMode: InteractionModeType = 'mouse'; export function startInteractionMode(): void { if (initialized) { @@ -66,6 +68,8 @@ export function startInteractionMode(): void { ); document.addEventListener('wheel', window.enterMouseMode, true); document.addEventListener('mousedown', window.enterMouseMode, true); - - window.getInteractionMode = () => interactionMode; +} + +export function getInteractionMode(): InteractionModeType { + return interactionMode; } diff --git a/ts/state/getInitialState.ts b/ts/state/getInitialState.ts index 4d0ce96139f6..6c74879e4edc 100644 --- a/ts/state/getInitialState.ts +++ b/ts/state/getInitialState.ts @@ -36,6 +36,7 @@ import { UUIDKind } from '../types/UUID'; import { getEmojiReducerState as emojis } from '../util/loadRecentEmojis'; import { getInitialState as stickers } from '../types/Stickers'; import { getThemeType } from '../util/getThemeType'; +import { getInteractionMode } from '../services/InteractionMode'; export function getInitialState({ badges, @@ -137,7 +138,7 @@ export function getInitialState({ ...user(), attachmentsPath: window.BasePaths.attachments, i18n: window.i18n, - interactionMode: window.getInteractionMode(), + interactionMode: getInteractionMode(), isMainWindowFullScreen: mainWindowStats.isFullScreen, isMainWindowMaximized: mainWindowStats.isMaximized, localeMessages: window.SignalContext.localeMessages, diff --git a/ts/test-electron/services/ActiveWindowService_test.ts b/ts/test-electron/services/ActiveWindowService_test.ts index d73b312ca73a..8d89e15e21b7 100644 --- a/ts/test-electron/services/ActiveWindowService_test.ts +++ b/ts/test-electron/services/ActiveWindowService_test.ts @@ -5,7 +5,7 @@ import { assert } from 'chai'; import * as sinon from 'sinon'; import { EventEmitter } from 'events'; -import { ActiveWindowService } from '../../services/ActiveWindowService'; +import { getActiveWindowService } from '../../services/ActiveWindowService'; describe('ActiveWindowService', () => { const fakeIpcEvent = {}; @@ -23,16 +23,17 @@ describe('ActiveWindowService', () => { } it('is inactive at the start', () => { - const service = new ActiveWindowService(); - service.initialize(createFakeDocument(), new EventEmitter()); + const service = getActiveWindowService( + createFakeDocument(), + new EventEmitter() + ); assert.isFalse(service.isActive()); }); it('becomes active after focusing', () => { const fakeIpc = new EventEmitter(); - const service = new ActiveWindowService(); - service.initialize(createFakeDocument(), fakeIpc); + const service = getActiveWindowService(createFakeDocument(), fakeIpc); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); @@ -41,8 +42,7 @@ describe('ActiveWindowService', () => { it('becomes inactive after 15 seconds without interaction', function test() { const fakeIpc = new EventEmitter(); - const service = new ActiveWindowService(); - service.initialize(createFakeDocument(), fakeIpc); + const service = getActiveWindowService(createFakeDocument(), fakeIpc); 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() { const fakeDocument = createFakeDocument(); const fakeIpc = new EventEmitter(); - const service = new ActiveWindowService(); - service.initialize(fakeDocument, fakeIpc); + const service = getActiveWindowService(fakeDocument, fakeIpc); fakeIpc.emit('set-window-focus', fakeIpcEvent, false); @@ -73,8 +72,7 @@ describe('ActiveWindowService', () => { it(`stays active if focused and receiving ${eventName} events`, function test() { const fakeDocument = createFakeDocument(); const fakeIpc = new EventEmitter(); - const service = new ActiveWindowService(); - service.initialize(fakeDocument, fakeIpc); + const service = getActiveWindowService(fakeDocument, fakeIpc); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); @@ -94,8 +92,7 @@ describe('ActiveWindowService', () => { it('calls callbacks when going from unfocused to focused', () => { const fakeIpc = new EventEmitter(); - const service = new ActiveWindowService(); - service.initialize(createFakeDocument(), fakeIpc); + const service = getActiveWindowService(createFakeDocument(), fakeIpc); const callback = sinon.stub(); service.registerForActive(callback); @@ -108,8 +105,7 @@ describe('ActiveWindowService', () => { it('calls callbacks when receiving a click event after being focused', function test() { const fakeDocument = createFakeDocument(); const fakeIpc = new EventEmitter(); - const service = new ActiveWindowService(); - service.initialize(fakeDocument, fakeIpc); + const service = getActiveWindowService(fakeDocument, fakeIpc); 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() { const fakeIpc = new EventEmitter(); - const service = new ActiveWindowService(); - service.initialize(createFakeDocument(), fakeIpc); + const service = getActiveWindowService(createFakeDocument(), fakeIpc); const callback = sinon.stub(); service.registerForActive(callback); @@ -150,8 +145,7 @@ describe('ActiveWindowService', () => { it('can remove callbacks', () => { const fakeDocument = createFakeDocument(); const fakeIpc = new EventEmitter(); - const service = new ActiveWindowService(); - service.initialize(fakeDocument, fakeIpc); + const service = getActiveWindowService(fakeDocument, fakeIpc); const callback = sinon.stub(); service.registerForActive(callback); diff --git a/ts/util/lint/linter.ts b/ts/util/lint/linter.ts index b78c3dbe5a86..d4ed74b7c218 100644 --- a/ts/util/lint/linter.ts +++ b/ts/util/lint/linter.ts @@ -24,6 +24,8 @@ const excludedFilesRegexp = RegExp( [ '^release/', '^preload.bundle.js(LICENSE.txt|map)?', + '^about.browser.bundle.js(LICENSE.txt|map)?', + '^about.preload.bundle.js(LICENSE.txt|map)?', '^storybook-static/', // Non-distributed files diff --git a/ts/window.d.ts b/ts/window.d.ts index 7cfabbe4d95d..ec0bf80d6ee9 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -3,6 +3,7 @@ // 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 * as Backbone from 'backbone'; import type PQueue from 'p-queue/dist'; @@ -101,7 +102,16 @@ export type FeatureFlagType = { GV2_MIGRATION_DISABLE_INVITE: boolean; }; +type AboutWindowType = { + environmentText: string; + executeMenuRole: (role: MenuItemConstructorOptions['role']) => Promise; + hasCustomTitleBar: boolean; + i18n: LocalizerType; + version: string; +}; + export type SignalCoreType = { + AboutWindow?: AboutWindowType; Crypto: typeof Crypto; Curve: typeof Curve; Data: typeof Data; diff --git a/ts/windows/about/app.tsx b/ts/windows/about/app.tsx new file mode 100644 index 000000000000..5964e7d2c4e4 --- /dev/null +++ b/ts/windows/about/app.tsx @@ -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( + AboutWindow.executeMenuRole('close')} + environment={AboutWindow.environmentText} + executeMenuRole={AboutWindow.executeMenuRole} + hasCustomTitleBar={AboutWindow.hasCustomTitleBar} + i18n={AboutWindow.i18n} + version={AboutWindow.version} + />, + document.getElementById('app') +); diff --git a/ts/windows/about/preload.ts b/ts/windows/about/preload.ts index 9ebf2f2816aa..ee31c2150ad3 100644 --- a/ts/windows/about/preload.ts +++ b/ts/windows/about/preload.ts @@ -1,42 +1,63 @@ // Copyright 2018 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React from 'react'; -import ReactDOM from 'react-dom'; -import { contextBridge } from 'electron'; +import type { MenuItemConstructorOptions } from 'electron'; +import { contextBridge, ipcRenderer } 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'; -import { About } from '../../components/About'; +async function executeMenuRole( + role: MenuItemConstructorOptions['role'] +): Promise { + await ipcRenderer.invoke('executeMenuRole', role); +} -contextBridge.exposeInMainWorld('SignalContext', { - ...SignalContext, - renderWindow: () => { - const environmentText: Array = [SignalContext.getEnvironment()]; +const environments: Array = [environment]; - const appInstance = SignalContext.getAppInstance(); - if (appInstance) { - environmentText.push(appInstance); - } +if (config.appInstance) { + environments.push(String(config.appInstance)); +} - let platform = ''; - if (process.platform === 'darwin') { - if (process.arch === 'arm64') { - platform = ` (${SignalContext.i18n('appleSilicon')})`; - } else { - platform = ' (Intel)'; - } - } +let platform = ''; +if (process.platform === 'darwin') { + if (process.arch === 'arm64') { + platform = ` (${i18n('appleSilicon')})`; + } else { + platform = ' (Intel)'; + } +} - ReactDOM.render( - React.createElement(About, { - closeAbout: () => SignalContext.executeMenuRole('close'), - environment: `${environmentText.join(' - ')}${platform}`, - i18n: SignalContext.i18n, - version: SignalContext.getVersion(), - hasCustomTitleBar: SignalContext.OS.hasCustomTitleBar(), - executeMenuRole: SignalContext.executeMenuRole, - }), - document.getElementById('app') - ); +const environmentText = `${environments.join(' - ')}${platform}`; +const hasCustomTitleBar = ipcRenderer.sendSync('getHasCustomTitleBar'); + +const Signal = { + AboutWindow: { + environmentText, + executeMenuRole, + hasCustomTitleBar, + i18n, + 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); diff --git a/ts/windows/context.ts b/ts/windows/context.ts index 9fb404c41665..82587506f787 100644 --- a/ts/windows/context.ts +++ b/ts/windows/context.ts @@ -12,13 +12,15 @@ import type { LocaleMessagesType } from '../types/I18N'; import type { NativeThemeType } from '../context/createNativeThemeListener'; import type { SettingType } from '../util/preload'; import type { RendererConfigType } from '../types/RendererConfig'; -import { ActiveWindowService } from '../services/ActiveWindowService'; import { Bytes } from '../context/Bytes'; import { Crypto } from '../context/Crypto'; 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 { getEnvironment, parseEnvironment, @@ -27,7 +29,7 @@ import { import { strictAssert } from '../util/assert'; import { createSetting } from '../util/preload'; 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 { isWindows, @@ -37,24 +39,6 @@ import { getClassName, } 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'); setEnvironment(parseEnvironment(config.environment)); @@ -74,7 +58,7 @@ export type SignalContextType = { nativeThemeListener: NativeThemeType; setIsCallActive: (isCallActive: boolean) => unknown; - activeWindowService: typeof activeWindowService; + activeWindowService: ActiveWindowServiceType; Settings: { themeSetting: SettingType; waitForChange: () => Promise; @@ -128,7 +112,7 @@ export const SignalContext: SignalContextType = { getPath: (name: 'userData' | 'home'): string => { return String(config[`${name}Path`]); }, - i18n: setupI18n(resolvedTranslationsLocale, localeMessages), + i18n, localeMessages, log: window.SignalContext.log, nativeThemeListener: createNativeThemeListener(ipcRenderer, window), diff --git a/ts/windows/init.ts b/ts/windows/init.ts index f2109b85d36d..413980ab2423 100644 --- a/ts/windows/init.ts +++ b/ts/windows/init.ts @@ -8,6 +8,6 @@ if (window.SignalContext.OS.hasCustomTitleBar()) { if (window.SignalContext.renderWindow) { window.SignalContext.renderWindow(); -} else { +} else if (window.SignalContext.log) { window.SignalContext.log.error('renderWindow is undefined!'); } diff --git a/ts/windows/settings/preload.ts b/ts/windows/settings/preload.ts index 235d846aa393..90a4b2b878db 100644 --- a/ts/windows/settings/preload.ts +++ b/ts/windows/settings/preload.ts @@ -16,7 +16,7 @@ import { import { awaitObject } from '../../util/awaitObject'; import { DurationInSeconds } from '../../util/durations'; import { createSetting, createCallback } from '../../util/preload'; -import { startInteractionMode } from '../startInteractionMode'; +import { startInteractionMode } from '../../services/InteractionMode'; function doneRendering() { ipcRenderer.send('settings-done-rendering');