mirror of https://github.com/electron/electron
102 lines
3.4 KiB
TypeScript
102 lines
3.4 KiB
TypeScript
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
|
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
|
|
|
import { EventEmitter } from 'events';
|
|
|
|
interface PreloadContext {
|
|
loadedModules: Map<string, any>;
|
|
loadableModules: Map<string, any>;
|
|
|
|
/** Process object to pass into preloads. */
|
|
process: NodeJS.Process;
|
|
|
|
createPreloadScript: (src: string) => Function
|
|
|
|
/** Globals to be exposed to preload context. */
|
|
exposeGlobals: any;
|
|
}
|
|
|
|
export function createPreloadProcessObject (): NodeJS.Process {
|
|
const preloadProcess: NodeJS.Process = new EventEmitter() as any;
|
|
|
|
preloadProcess.getProcessMemoryInfo = () => {
|
|
return ipcRendererInternal.invoke<Electron.ProcessMemoryInfo>(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO);
|
|
};
|
|
|
|
Object.defineProperty(preloadProcess, 'noDeprecation', {
|
|
get () {
|
|
return process.noDeprecation;
|
|
},
|
|
set (value) {
|
|
process.noDeprecation = value;
|
|
}
|
|
});
|
|
|
|
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
|
|
|
|
// Similar to nodes --expose-internals flag, this exposes _linkedBinding so
|
|
// that tests can call it to get access to some test only bindings
|
|
if (hasSwitch('unsafely-expose-electron-internals-for-testing')) {
|
|
preloadProcess._linkedBinding = process._linkedBinding;
|
|
}
|
|
|
|
return preloadProcess;
|
|
}
|
|
|
|
// This is the `require` function that will be visible to the preload script
|
|
function preloadRequire (context: PreloadContext, module: string) {
|
|
if (context.loadedModules.has(module)) {
|
|
return context.loadedModules.get(module);
|
|
}
|
|
if (context.loadableModules.has(module)) {
|
|
const loadedModule = context.loadableModules.get(module)!();
|
|
context.loadedModules.set(module, loadedModule);
|
|
return loadedModule;
|
|
}
|
|
throw new Error(`module not found: ${module}`);
|
|
}
|
|
|
|
// Wrap the script into a function executed in global scope. It won't have
|
|
// access to the current scope, so we'll expose a few objects as arguments:
|
|
//
|
|
// - `require`: The `preloadRequire` function
|
|
// - `process`: The `preloadProcess` object
|
|
// - `Buffer`: Shim of `Buffer` implementation
|
|
// - `global`: The window object, which is aliased to `global` by webpack.
|
|
function runPreloadScript (context: PreloadContext, preloadSrc: string) {
|
|
const globalVariables = [];
|
|
const fnParameters = [];
|
|
for (const [key, value] of Object.entries(context.exposeGlobals)) {
|
|
globalVariables.push(key);
|
|
fnParameters.push(value);
|
|
}
|
|
const preloadWrapperSrc = `(function(require, process, exports, module, ${globalVariables.join(', ')}) {
|
|
${preloadSrc}
|
|
})`;
|
|
|
|
// eval in window scope
|
|
const preloadFn = context.createPreloadScript(preloadWrapperSrc);
|
|
const exports = {};
|
|
|
|
preloadFn(preloadRequire.bind(null, context), context.process, exports, { exports }, ...fnParameters);
|
|
}
|
|
|
|
/**
|
|
* Execute preload scripts within a sandboxed process.
|
|
*/
|
|
export function executeSandboxedPreloadScripts (context: PreloadContext, preloadScripts: ElectronInternal.PreloadScript[]) {
|
|
for (const { filePath, contents, error } of preloadScripts) {
|
|
try {
|
|
if (contents) {
|
|
runPreloadScript(context, contents);
|
|
} else if (error) {
|
|
throw error;
|
|
}
|
|
} catch (error) {
|
|
console.error(`Unable to load preload script: ${filePath}`);
|
|
console.error(error);
|
|
ipcRendererInternal.send(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, filePath, error);
|
|
}
|
|
}
|
|
}
|