Use synchronous IPC for passing config

This commit is contained in:
Fedor Indutny 2023-04-07 09:42:12 -07:00 committed by GitHub
parent 3e586be46a
commit bd41d7b216
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 87 additions and 97 deletions

View file

@ -402,79 +402,7 @@ async function prepareUrl(
url: URL, url: URL,
{ forCalling, forCamera }: PrepareUrlOptions = {} { forCalling, forCamera }: PrepareUrlOptions = {}
): Promise<string> { ): Promise<string> {
const theme = await getResolvedThemeSetting(); return setUrlSearchParams(url, { forCalling, forCamera }).href;
const directoryConfig = directoryConfigSchema.safeParse({
directoryUrl: config.get<string | null>('directoryUrl') || undefined,
directoryMRENCLAVE:
config.get<string | null>('directoryMRENCLAVE') || undefined,
});
if (!directoryConfig.success) {
throw new Error(
`prepareUrl: Failed to parse renderer directory config ${JSON.stringify(
directoryConfig.error.flatten()
)}`
);
}
const urlParams: RendererConfigType = {
name: packageJson.productName,
resolvedTranslationsLocale: getResolvedMessagesLocale().name,
preferredSystemLocales: getPreferredSystemLocales(),
version: app.getVersion(),
buildCreation: config.get<number>('buildCreation'),
buildExpiration: config.get<number>('buildExpiration'),
challengeUrl: config.get<string>('challengeUrl'),
serverUrl: config.get<string>('serverUrl'),
storageUrl: config.get<string>('storageUrl'),
updatesUrl: config.get<string>('updatesUrl'),
resourcesUrl: config.get<string>('resourcesUrl'),
artCreatorUrl: config.get<string>('artCreatorUrl'),
cdnUrl0: config.get<ConfigType>('cdn').get<string>('0'),
cdnUrl2: config.get<ConfigType>('cdn').get<string>('2'),
certificateAuthority: config.get<string>('certificateAuthority'),
environment: enableCI ? Environment.Production : getEnvironment(),
enableCI,
nodeVersion: process.versions.node,
hostname: os.hostname(),
appInstance: process.env.NODE_APP_INSTANCE || undefined,
proxyUrl: process.env.HTTPS_PROXY || process.env.https_proxy || undefined,
contentProxyUrl: config.get<string>('contentProxyUrl'),
sfuUrl: config.get('sfuUrl'),
reducedMotionSetting: animationSettings.prefersReducedMotion,
registrationChallengeUrl: config.get<string>('registrationChallengeUrl'),
serverPublicParams: config.get<string>('serverPublicParams'),
serverTrustRoot: config.get<string>('serverTrustRoot'),
theme,
appStartInitialSpellcheckSetting,
userDataPath: app.getPath('userData'),
homePath: app.getPath('home'),
crashDumpsPath: app.getPath('crashDumps'),
directoryConfig: directoryConfig.data,
// Only used by the main window
isMainWindowFullScreen: Boolean(mainWindow?.isFullScreen()),
isMainWindowMaximized: Boolean(mainWindow?.isMaximized()),
// Only for tests
argv: JSON.stringify(process.argv),
// Only for permission popup window
forCalling: Boolean(forCalling),
forCamera: Boolean(forCamera),
};
const parsed = rendererConfigSchema.safeParse(urlParams);
if (!parsed.success) {
throw new Error(
`prepareUrl: Failed to parse renderer config ${JSON.stringify(
parsed.error.flatten()
)}`
);
}
return setUrlSearchParams(url, { config: JSON.stringify(parsed.data) }).href;
} }
async function handleUrl(rawTarget: string) { async function handleUrl(rawTarget: string) {
@ -2287,6 +2215,78 @@ ipc.on('get-built-in-images', async () => {
} }
}); });
ipc.on('get-config', async event => {
const theme = await getResolvedThemeSetting();
const directoryConfig = directoryConfigSchema.safeParse({
directoryUrl: config.get<string | null>('directoryUrl') || undefined,
directoryMRENCLAVE:
config.get<string | null>('directoryMRENCLAVE') || undefined,
});
if (!directoryConfig.success) {
throw new Error(
`prepareUrl: Failed to parse renderer directory config ${JSON.stringify(
directoryConfig.error.flatten()
)}`
);
}
const parsed = rendererConfigSchema.safeParse({
name: packageJson.productName,
resolvedTranslationsLocale: getResolvedMessagesLocale().name,
preferredSystemLocales: getPreferredSystemLocales(),
version: app.getVersion(),
buildCreation: config.get<number>('buildCreation'),
buildExpiration: config.get<number>('buildExpiration'),
challengeUrl: config.get<string>('challengeUrl'),
serverUrl: config.get<string>('serverUrl'),
storageUrl: config.get<string>('storageUrl'),
updatesUrl: config.get<string>('updatesUrl'),
resourcesUrl: config.get<string>('resourcesUrl'),
artCreatorUrl: config.get<string>('artCreatorUrl'),
cdnUrl0: config.get<ConfigType>('cdn').get<string>('0'),
cdnUrl2: config.get<ConfigType>('cdn').get<string>('2'),
certificateAuthority: config.get<string>('certificateAuthority'),
environment: enableCI ? Environment.Production : getEnvironment(),
enableCI,
nodeVersion: process.versions.node,
hostname: os.hostname(),
appInstance: process.env.NODE_APP_INSTANCE || undefined,
proxyUrl: process.env.HTTPS_PROXY || process.env.https_proxy || undefined,
contentProxyUrl: config.get<string>('contentProxyUrl'),
sfuUrl: config.get('sfuUrl'),
reducedMotionSetting: animationSettings.prefersReducedMotion,
registrationChallengeUrl: config.get<string>('registrationChallengeUrl'),
serverPublicParams: config.get<string>('serverPublicParams'),
serverTrustRoot: config.get<string>('serverTrustRoot'),
theme,
appStartInitialSpellcheckSetting,
userDataPath: app.getPath('userData'),
homePath: app.getPath('home'),
crashDumpsPath: app.getPath('crashDumps'),
directoryConfig: directoryConfig.data,
// Only used by the main window
isMainWindowFullScreen: Boolean(mainWindow?.isFullScreen()),
isMainWindowMaximized: Boolean(mainWindow?.isMaximized()),
// Only for tests
argv: JSON.stringify(process.argv),
} satisfies RendererConfigType);
if (!parsed.success) {
throw new Error(
`prepareUrl: Failed to parse renderer config ${JSON.stringify(
parsed.error.flatten()
)}`
);
}
// eslint-disable-next-line no-param-reassign
event.returnValue = parsed.data;
});
// Ingested in preload.js via a sendSync call // Ingested in preload.js via a sendSync call
ipc.on('locale-data', event => { ipc.on('locale-data', event => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign

View file

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

View file

@ -44,8 +44,6 @@ describe('URL utilities', () => {
number: 123, number: 123,
true_bool: true, true_bool: true,
false_bool: false, false_bool: false,
null_value: null,
undefined_value: undefined,
array: ['ok', 'wow'], array: ['ok', 'wow'],
stringified: { toString: () => 'bar' }, stringified: { toString: () => 'bar' },
}; };
@ -67,8 +65,6 @@ describe('URL utilities', () => {
assert.strictEqual(newUrl.searchParams.get('number'), '123'); assert.strictEqual(newUrl.searchParams.get('number'), '123');
assert.strictEqual(newUrl.searchParams.get('true_bool'), 'true'); assert.strictEqual(newUrl.searchParams.get('true_bool'), 'true');
assert.strictEqual(newUrl.searchParams.get('false_bool'), 'false'); assert.strictEqual(newUrl.searchParams.get('false_bool'), 'false');
assert.strictEqual(newUrl.searchParams.get('null_value'), '');
assert.strictEqual(newUrl.searchParams.get('undefined_value'), '');
assert.strictEqual(newUrl.searchParams.get('array'), 'ok,wow'); assert.strictEqual(newUrl.searchParams.get('array'), 'ok,wow');
assert.strictEqual(newUrl.searchParams.get('stringified'), 'bar'); assert.strictEqual(newUrl.searchParams.get('stringified'), 'bar');
}); });

View file

@ -64,10 +64,6 @@ export const rendererConfigSchema = z.object({
// Only for tests // Only for tests
argv: configOptionalStringSchema, argv: configOptionalStringSchema,
// Only for permission popup window
forCalling: z.boolean(),
forCamera: z.boolean(),
}); });
export type RendererConfigType = z.infer<typeof rendererConfigSchema>; export type RendererConfigType = z.infer<typeof rendererConfigSchema>;

View file

@ -1,8 +1,6 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import { mapValues } from 'lodash';
export function maybeParseUrl(value: string): undefined | URL { export function maybeParseUrl(value: string): undefined | URL {
if (typeof value === 'string') { if (typeof value === 'string') {
try { try {
@ -20,9 +18,13 @@ export function setUrlSearchParams(
searchParams: Readonly<Record<string, unknown>> searchParams: Readonly<Record<string, unknown>>
): URL { ): URL {
const result = cloneUrl(url); const result = cloneUrl(url);
result.search = new URLSearchParams( result.search = '';
mapValues(searchParams, stringifySearchParamValue) for (const [key, value] of Object.entries(searchParams)) {
).toString(); if (value == null) {
continue;
}
result.searchParams.append(key, String(value));
}
return result; return result;
} }
@ -30,10 +32,6 @@ function cloneUrl(url: Readonly<URL>): URL {
return new URL(url.href); return new URL(url.href);
} }
function stringifySearchParamValue(value: unknown): string {
return value == null ? '' : String(value);
}
export function urlPathFromComponents( export function urlPathFromComponents(
components: ReadonlyArray<string> components: ReadonlyArray<string>
): string { ): string {

View file

@ -25,7 +25,9 @@ contextBridge.exposeInMainWorld(
contextBridge.exposeInMainWorld('SignalContext', { contextBridge.exposeInMainWorld('SignalContext', {
...SignalContext, ...SignalContext,
renderWindow: () => { renderWindow: () => {
const { forCalling, forCamera } = SignalContext.config; const params = new URLSearchParams(document.location.search);
const forCalling = params.get('forCalling') === 'true';
const forCamera = params.get('forCamera') === 'true';
let message; let message;
if (forCalling) { if (forCalling) {