Files
Desktop/ts/windows/main/start.preload.ts
2026-01-16 16:20:36 -05:00

181 lines
5.8 KiB
TypeScript

// Copyright 2017 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { fabric } from 'fabric';
import lodash from 'lodash';
import { contextBridge } from 'electron';
import { createLogger } from '../../logging/log.std.js';
import '../context.preload.js';
// Connect websocket early
import '../../textsecure/preconnect.preload.js';
import './phase0-devtools.node.js';
import './phase1-ipc.preload.js';
import '../preload.preload.js';
import './phase2-dependencies.preload.js';
import './phase3-post-signal.preload.js';
import './phase4-test.preload.js';
import type {
CdsLookupOptionsType,
GetIceServersResultType,
} from '../../textsecure/WebAPI.preload.js';
import { cdsLookup, getSocketStatus } from '../../textsecure/WebAPI.preload.js';
import type { FeatureFlagType } from '../../window.d.ts';
import type { StorageAccessType } from '../../types/Storage.d.ts';
import { calling } from '../../services/calling.preload.js';
import { Environment, getEnvironment } from '../../environment.std.js';
import { isProduction } from '../../util/version.std.js';
import { benchmarkConversationOpen } from '../../CI/benchmarkConversationOpen.preload.js';
import { itemStorage } from '../../textsecure/Storage.preload.js';
import { IMAGE_PNG } from '../../types/MIME.std.js';
const { has } = lodash;
const log = createLogger('start');
window.addEventListener('contextmenu', e => {
const node = e.target as Element | null;
const isEditable = Boolean(
node?.closest('textarea, input, [contenteditable="plaintext-only"]')
);
const isLink = Boolean(node?.closest('a'));
const isImage = Boolean(node?.closest('.Lightbox img'));
const hasSelection = Boolean(window.getSelection()?.toString());
if (!isEditable && !hasSelection && !isLink && !isImage) {
e.preventDefault();
}
});
if (window.SignalContext.config.proxyUrl) {
log.info('Using provided proxy url');
}
if (
!isProduction(window.SignalContext.getVersion()) ||
window.SignalContext.config.devTools
) {
const SignalDebug = {
cdsLookup: (options: CdsLookupOptionsType) => cdsLookup(options),
getSelectedConversation: () => {
const conversationId =
window.reduxStore.getState().conversations.selectedConversationId;
return window.ConversationController.get(conversationId)?.attributes;
},
archiveSessionsForCurrentConversation: async () => {
const conversationId =
window.reduxStore.getState().conversations.selectedConversationId;
await window.ConversationController.archiveSessionsForConversation(
conversationId
);
},
getConversation: (id: string) => window.ConversationController.get(id),
getMessageById: (id: string) => window.MessageCache.getById(id)?.attributes,
getMessageBySentAt: async (timestamp: number) => {
const message = await window.MessageCache.findBySentAt(
timestamp,
() => true
);
return message?.attributes;
},
getReduxState: () => window.reduxStore.getState(),
getSfuUrl: () => calling._sfuUrl,
getIceServerOverride: () => calling._iceServerOverride,
getSocketStatus: () => getSocketStatus(),
getStorageItem: (name: keyof StorageAccessType) => itemStorage.get(name),
putStorageItem: <K extends keyof StorageAccessType>(
name: K,
value: StorageAccessType[K]
) => itemStorage.put(name, value),
setFlag: (name: keyof FeatureFlagType, value: boolean) => {
if (!has(window.Flags, name)) {
return;
}
window.Flags[name] = value;
},
setSfuUrl: (url: string) => {
calling._sfuUrl = url;
},
setIceServerOverride: (
override: GetIceServersResultType | string | undefined
) => {
if (typeof override === 'string') {
if (!/(turn|turns|stun):.*/.test(override)) {
log.warn(
'Override url should be prefixed with `turn:`, `turns:`, or `stun:` else override may not work'
);
}
}
calling._iceServerOverride = override;
},
sendViewOnceImageInSelectedConversation: async () => {
const conversationId =
window.reduxStore.getState().conversations.selectedConversationId;
const conversation = window.ConversationController.get(conversationId);
if (!conversation) {
throw new Error('No conversation selected');
}
const canvas = new fabric.StaticCanvas(null, {
width: 100,
height: 100,
backgroundColor: '#3b82f6',
});
const dataURL = canvas.toDataURL({ format: 'png' });
const base64Data = dataURL.split(',')[1];
const data = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));
await conversation.enqueueMessageForSend(
{
body: undefined,
attachments: [
{
contentType: IMAGE_PNG,
size: data.byteLength,
data,
},
],
isViewOnce: true,
},
{}
);
log.info('Sent view-once test image');
},
...(window.SignalContext.config.ciMode === 'benchmark'
? {
benchmarkConversationOpen,
}
: {}),
};
contextBridge.exposeInMainWorld('SignalDebug', SignalDebug);
}
if (getEnvironment() === Environment.Test) {
contextBridge.exposeInMainWorld('RETRY_DELAY', window.RETRY_DELAY);
contextBridge.exposeInMainWorld('assert', window.assert);
contextBridge.exposeInMainWorld('testUtilities', window.testUtilities);
}
// See ts/logging/log.ts
if (getEnvironment() !== Environment.PackagedApp) {
const debug = (...args: Array<string>) => {
localStorage.setItem('debug', args.join(','));
};
contextBridge.exposeInMainWorld('debug', debug);
}
if (window.SignalContext.config.ciMode === 'full') {
contextBridge.exposeInMainWorld('SignalCI', window.SignalCI);
}
contextBridge.exposeInMainWorld('showDebugLog', window.IPC.showDebugLog);
contextBridge.exposeInMainWorld('startApp', window.startApp);