added all files to project

This commit is contained in:
2022-03-10 10:36:59 +01:00
parent 09dd957b33
commit 46a936d7de
25351 changed files with 3883356 additions and 0 deletions
@@ -0,0 +1 @@
export declare const getElectronBinding: typeof process.electronBinding;
+15
View File
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getElectronBinding = void 0;
const getElectronBinding = (name) => {
if (process._linkedBinding) {
return process._linkedBinding('electron_common_' + name);
}
else if (process.electronBinding) {
return process.electronBinding(name);
}
else {
return null;
}
};
exports.getElectronBinding = getElectronBinding;
+18
View File
@@ -0,0 +1,18 @@
export declare const enum IPC_MESSAGES {
BROWSER_REQUIRE = "REMOTE_BROWSER_REQUIRE",
BROWSER_GET_BUILTIN = "REMOTE_BROWSER_GET_BUILTIN",
BROWSER_GET_GLOBAL = "REMOTE_BROWSER_GET_GLOBAL",
BROWSER_GET_CURRENT_WINDOW = "REMOTE_BROWSER_GET_CURRENT_WINDOW",
BROWSER_GET_CURRENT_WEB_CONTENTS = "REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS",
BROWSER_CONSTRUCTOR = "REMOTE_BROWSER_CONSTRUCTOR",
BROWSER_FUNCTION_CALL = "REMOTE_BROWSER_FUNCTION_CALL",
BROWSER_MEMBER_CONSTRUCTOR = "REMOTE_BROWSER_MEMBER_CONSTRUCTOR",
BROWSER_MEMBER_CALL = "REMOTE_BROWSER_MEMBER_CALL",
BROWSER_MEMBER_GET = "REMOTE_BROWSER_MEMBER_GET",
BROWSER_MEMBER_SET = "REMOTE_BROWSER_MEMBER_SET",
BROWSER_DEREFERENCE = "REMOTE_BROWSER_DEREFERENCE",
BROWSER_CONTEXT_RELEASE = "REMOTE_BROWSER_CONTEXT_RELEASE",
BROWSER_WRONG_CONTEXT_ERROR = "REMOTE_BROWSER_WRONG_CONTEXT_ERROR",
RENDERER_CALLBACK = "REMOTE_RENDERER_CALLBACK",
RENDERER_RELEASE_CALLBACK = "REMOTE_RENDERER_RELEASE_CALLBACK"
}
+2
View File
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
+2
View File
@@ -0,0 +1,2 @@
export declare const commonModuleNames: string[];
export declare const browserModuleNames: string[];
+50
View File
@@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.browserModuleNames = exports.commonModuleNames = void 0;
const get_electron_binding_1 = require("./get-electron-binding");
exports.commonModuleNames = [
'clipboard',
'nativeImage',
'shell',
];
exports.browserModuleNames = [
'app',
'autoUpdater',
'BaseWindow',
'BrowserView',
'BrowserWindow',
'contentTracing',
'crashReporter',
'dialog',
'globalShortcut',
'ipcMain',
'inAppPurchase',
'Menu',
'MenuItem',
'nativeTheme',
'net',
'netLog',
'MessageChannelMain',
'Notification',
'powerMonitor',
'powerSaveBlocker',
'protocol',
'screen',
'session',
'ShareMenu',
'systemPreferences',
'TopLevelWindow',
'TouchBar',
'Tray',
'View',
'webContents',
'WebContentsView',
'webFrameMain',
].concat(exports.commonModuleNames);
const features = get_electron_binding_1.getElectronBinding('features');
if (!features || features.isDesktopCapturerEnabled()) {
exports.browserModuleNames.push('desktopCapturer');
}
if (!features || features.isViewApiEnabled()) {
exports.browserModuleNames.push('ImageView');
}
+4
View File
@@ -0,0 +1,4 @@
export declare function isPromise(val: any): any;
export declare function isSerializableObject(value: any): boolean;
export declare function serialize(value: any): any;
export declare function deserialize(value: any): any;
+112
View File
@@ -0,0 +1,112 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.deserialize = exports.serialize = exports.isSerializableObject = exports.isPromise = void 0;
const electron_1 = require("electron");
function isPromise(val) {
return (val &&
val.then &&
val.then instanceof Function &&
val.constructor &&
val.constructor.reject &&
val.constructor.reject instanceof Function &&
val.constructor.resolve &&
val.constructor.resolve instanceof Function);
}
exports.isPromise = isPromise;
const serializableTypes = [
Boolean,
Number,
String,
Date,
Error,
RegExp,
ArrayBuffer
];
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#Supported_types
function isSerializableObject(value) {
return value === null || ArrayBuffer.isView(value) || serializableTypes.some(type => value instanceof type);
}
exports.isSerializableObject = isSerializableObject;
const objectMap = function (source, mapper) {
const sourceEntries = Object.entries(source);
const targetEntries = sourceEntries.map(([key, val]) => [key, mapper(val)]);
return Object.fromEntries(targetEntries);
};
function serializeNativeImage(image) {
const representations = [];
const scaleFactors = image.getScaleFactors();
// Use Buffer when there's only one representation for better perf.
// This avoids compressing to/from PNG where it's not necessary to
// ensure uniqueness of dataURLs (since there's only one).
if (scaleFactors.length === 1) {
const scaleFactor = scaleFactors[0];
const size = image.getSize(scaleFactor);
const buffer = image.toBitmap({ scaleFactor });
representations.push({ scaleFactor, size, buffer });
}
else {
// Construct from dataURLs to ensure that they are not lost in creation.
for (const scaleFactor of scaleFactors) {
const size = image.getSize(scaleFactor);
const dataURL = image.toDataURL({ scaleFactor });
representations.push({ scaleFactor, size, dataURL });
}
}
return { __ELECTRON_SERIALIZED_NativeImage__: true, representations };
}
function deserializeNativeImage(value) {
const image = electron_1.nativeImage.createEmpty();
// Use Buffer when there's only one representation for better perf.
// This avoids compressing to/from PNG where it's not necessary to
// ensure uniqueness of dataURLs (since there's only one).
if (value.representations.length === 1) {
const { buffer, size, scaleFactor } = value.representations[0];
const { width, height } = size;
image.addRepresentation({ buffer, scaleFactor, width, height });
}
else {
// Construct from dataURLs to ensure that they are not lost in creation.
for (const rep of value.representations) {
const { dataURL, size, scaleFactor } = rep;
const { width, height } = size;
image.addRepresentation({ dataURL, scaleFactor, width, height });
}
}
return image;
}
function serialize(value) {
if (value && value.constructor && value.constructor.name === 'NativeImage') {
return serializeNativeImage(value);
}
if (Array.isArray(value)) {
return value.map(serialize);
}
else if (isSerializableObject(value)) {
return value;
}
else if (value instanceof Object) {
return objectMap(value, serialize);
}
else {
return value;
}
}
exports.serialize = serialize;
function deserialize(value) {
if (value && value.__ELECTRON_SERIALIZED_NativeImage__) {
return deserializeNativeImage(value);
}
else if (Array.isArray(value)) {
return value.map(deserialize);
}
else if (isSerializableObject(value)) {
return value;
}
else if (value instanceof Object) {
return objectMap(value, deserialize);
}
else {
return value;
}
}
exports.deserialize = deserialize;
+1
View File
@@ -0,0 +1 @@
export { initialize } from './server';
+5
View File
@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initialize = void 0;
var server_1 = require("./server");
Object.defineProperty(exports, "initialize", { enumerable: true, get: function () { return server_1.initialize; } });
+16
View File
@@ -0,0 +1,16 @@
import { WebContents } from 'electron';
declare class ObjectsRegistry {
private nextId;
private storage;
private owners;
private electronIds;
add(webContents: WebContents, contextId: string, obj: any): number;
get(id: number): any;
remove(webContents: WebContents, contextId: string, id: number): void;
clear(webContents: WebContents, contextId: string): void;
private saveToStorage;
private dereference;
private registerDeleteListener;
}
declare const _default: ObjectsRegistry;
export default _default;
+117
View File
@@ -0,0 +1,117 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const getOwnerKey = (webContents, contextId) => {
return `${webContents.id}-${contextId}`;
};
class ObjectsRegistry {
constructor() {
this.nextId = 0;
// Stores all objects by ref-counting.
// (id) => {object, count}
this.storage = {};
// Stores the IDs + refCounts of objects referenced by WebContents.
// (ownerKey) => { id: refCount }
this.owners = {};
this.electronIds = new WeakMap();
}
// Register a new object and return its assigned ID. If the object is already
// registered then the already assigned ID would be returned.
add(webContents, contextId, obj) {
// Get or assign an ID to the object.
const id = this.saveToStorage(obj);
// Add object to the set of referenced objects.
const ownerKey = getOwnerKey(webContents, contextId);
let owner = this.owners[ownerKey];
if (!owner) {
owner = this.owners[ownerKey] = new Map();
this.registerDeleteListener(webContents, contextId);
}
if (!owner.has(id)) {
owner.set(id, 0);
// Increase reference count if not referenced before.
this.storage[id].count++;
}
owner.set(id, owner.get(id) + 1);
return id;
}
// Get an object according to its ID.
get(id) {
const pointer = this.storage[id];
if (pointer != null)
return pointer.object;
}
// Dereference an object according to its ID.
// Note that an object may be double-freed (cleared when page is reloaded, and
// then garbage collected in old page).
remove(webContents, contextId, id) {
const ownerKey = getOwnerKey(webContents, contextId);
const owner = this.owners[ownerKey];
if (owner && owner.has(id)) {
const newRefCount = owner.get(id) - 1;
// Only completely remove if the number of references GCed in the
// renderer is the same as the number of references we sent them
if (newRefCount <= 0) {
// Remove the reference in owner.
owner.delete(id);
// Dereference from the storage.
this.dereference(id);
}
else {
owner.set(id, newRefCount);
}
}
}
// Clear all references to objects refrenced by the WebContents.
clear(webContents, contextId) {
const ownerKey = getOwnerKey(webContents, contextId);
const owner = this.owners[ownerKey];
if (!owner)
return;
for (const id of owner.keys())
this.dereference(id);
delete this.owners[ownerKey];
}
// Saves the object into storage and assigns an ID for it.
saveToStorage(object) {
let id = this.electronIds.get(object);
if (!id) {
id = ++this.nextId;
this.storage[id] = {
count: 0,
object: object
};
this.electronIds.set(object, id);
}
return id;
}
// Dereference the object from store.
dereference(id) {
const pointer = this.storage[id];
if (pointer == null) {
return;
}
pointer.count -= 1;
if (pointer.count === 0) {
this.electronIds.delete(pointer.object);
delete this.storage[id];
}
}
// Clear the storage when renderer process is destroyed.
registerDeleteListener(webContents, contextId) {
// contextId => ${processHostId}-${contextCount}
const processHostId = contextId.split('-')[0];
const listener = (_, deletedProcessHostId) => {
if (deletedProcessHostId &&
deletedProcessHostId.toString() === processHostId) {
webContents.removeListener('render-view-deleted', listener);
this.clear(webContents, contextId);
}
};
// Note that the "render-view-deleted" event may not be emitted on time when
// the renderer process get destroyed because of navigation, we rely on the
// renderer process to send "ELECTRON_BROWSER_CONTEXT_RELEASE" message to
// guard this situation.
webContents.on('render-view-deleted', listener);
}
}
exports.default = new ObjectsRegistry();
+3
View File
@@ -0,0 +1,3 @@
import { WebContents } from 'electron';
export declare const isRemoteModuleEnabled: (contents: WebContents) => any;
export declare function initialize(): void;
+486
View File
@@ -0,0 +1,486 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.initialize = exports.isRemoteModuleEnabled = void 0;
const events_1 = require("events");
const objects_registry_1 = __importDefault(require("./objects-registry"));
const type_utils_1 = require("../common/type-utils");
const electron_1 = require("electron");
const get_electron_binding_1 = require("../common/get-electron-binding");
const v8Util = get_electron_binding_1.getElectronBinding('v8_util');
// The internal properties of Function.
const FUNCTION_PROPERTIES = [
'length', 'name', 'arguments', 'caller', 'prototype'
];
// The remote functions in renderer processes.
const rendererFunctionCache = new Map();
// eslint-disable-next-line no-undef
const finalizationRegistry = new FinalizationRegistry((fi) => {
const mapKey = fi.id[0] + '~' + fi.id[1];
const ref = rendererFunctionCache.get(mapKey);
if (ref !== undefined && ref.deref() === undefined) {
rendererFunctionCache.delete(mapKey);
if (!fi.webContents.isDestroyed()) {
try {
fi.webContents.sendToFrame(fi.frameId, "REMOTE_RENDERER_RELEASE_CALLBACK" /* RENDERER_RELEASE_CALLBACK */, fi.id[0], fi.id[1]);
}
catch (error) {
console.warn(`sendToFrame() failed: ${error}`);
}
}
}
});
function getCachedRendererFunction(id) {
const mapKey = id[0] + '~' + id[1];
const ref = rendererFunctionCache.get(mapKey);
if (ref !== undefined) {
const deref = ref.deref();
if (deref !== undefined)
return deref;
}
}
function setCachedRendererFunction(id, wc, frameId, value) {
// eslint-disable-next-line no-undef
const wr = new WeakRef(value);
const mapKey = id[0] + '~' + id[1];
rendererFunctionCache.set(mapKey, wr);
finalizationRegistry.register(value, {
id,
webContents: wc,
frameId
});
return value;
}
const locationInfo = new WeakMap();
// Return the description of object's members:
const getObjectMembers = function (object) {
let names = Object.getOwnPropertyNames(object);
// For Function, we should not override following properties even though they
// are "own" properties.
if (typeof object === 'function') {
names = names.filter((name) => {
return !FUNCTION_PROPERTIES.includes(name);
});
}
// Map properties to descriptors.
return names.map((name) => {
const descriptor = Object.getOwnPropertyDescriptor(object, name);
let type;
let writable = false;
if (descriptor.get === undefined && typeof object[name] === 'function') {
type = 'method';
}
else {
if (descriptor.set || descriptor.writable)
writable = true;
type = 'get';
}
return { name, enumerable: descriptor.enumerable, writable, type };
});
};
// Return the description of object's prototype.
const getObjectPrototype = function (object) {
const proto = Object.getPrototypeOf(object);
if (proto === null || proto === Object.prototype)
return null;
return {
members: getObjectMembers(proto),
proto: getObjectPrototype(proto)
};
};
// Convert a real value into meta data.
const valueToMeta = function (sender, contextId, value, optimizeSimpleObject = false) {
// Determine the type of value.
let type;
switch (typeof value) {
case 'object':
// Recognize certain types of objects.
if (value instanceof Buffer) {
type = 'buffer';
}
else if (value && value.constructor && value.constructor.name === 'NativeImage') {
type = 'nativeimage';
}
else if (Array.isArray(value)) {
type = 'array';
}
else if (value instanceof Error) {
type = 'error';
}
else if (type_utils_1.isSerializableObject(value)) {
type = 'value';
}
else if (type_utils_1.isPromise(value)) {
type = 'promise';
}
else if (Object.prototype.hasOwnProperty.call(value, 'callee') && value.length != null) {
// Treat the arguments object as array.
type = 'array';
}
else if (optimizeSimpleObject && v8Util.getHiddenValue(value, 'simple')) {
// Treat simple objects as value.
type = 'value';
}
else {
type = 'object';
}
break;
case 'function':
type = 'function';
break;
default:
type = 'value';
break;
}
// Fill the meta object according to value's type.
if (type === 'array') {
return {
type,
members: value.map((el) => valueToMeta(sender, contextId, el, optimizeSimpleObject))
};
}
else if (type === 'nativeimage') {
return { type, value: type_utils_1.serialize(value) };
}
else if (type === 'object' || type === 'function') {
return {
type,
name: value.constructor ? value.constructor.name : '',
// Reference the original value if it's an object, because when it's
// passed to renderer we would assume the renderer keeps a reference of
// it.
id: objects_registry_1.default.add(sender, contextId, value),
members: getObjectMembers(value),
proto: getObjectPrototype(value)
};
}
else if (type === 'buffer') {
return { type, value };
}
else if (type === 'promise') {
// Add default handler to prevent unhandled rejections in main process
// Instead they should appear in the renderer process
value.then(function () { }, function () { });
return {
type,
then: valueToMeta(sender, contextId, function (onFulfilled, onRejected) {
value.then(onFulfilled, onRejected);
})
};
}
else if (type === 'error') {
return {
type,
value,
members: Object.keys(value).map(name => ({
name,
value: valueToMeta(sender, contextId, value[name])
}))
};
}
else {
return {
type: 'value',
value
};
}
};
const throwRPCError = function (message) {
const error = new Error(message);
error.code = 'EBADRPC';
error.errno = -72;
throw error;
};
const removeRemoteListenersAndLogWarning = (sender, callIntoRenderer) => {
const location = locationInfo.get(callIntoRenderer);
let message = 'Attempting to call a function in a renderer window that has been closed or released.' +
`\nFunction provided here: ${location}`;
if (sender instanceof events_1.EventEmitter) {
const remoteEvents = sender.eventNames().filter((eventName) => {
return sender.listeners(eventName).includes(callIntoRenderer);
});
if (remoteEvents.length > 0) {
message += `\nRemote event names: ${remoteEvents.join(', ')}`;
remoteEvents.forEach((eventName) => {
sender.removeListener(eventName, callIntoRenderer);
});
}
}
console.warn(message);
};
const fakeConstructor = (constructor, name) => new Proxy(Object, {
get(target, prop, receiver) {
if (prop === 'name') {
return name;
}
else {
return Reflect.get(target, prop, receiver);
}
}
});
// Convert array of meta data from renderer into array of real values.
const unwrapArgs = function (sender, frameId, contextId, args) {
const metaToValue = function (meta) {
switch (meta.type) {
case 'nativeimage':
return type_utils_1.deserialize(meta.value);
case 'value':
return meta.value;
case 'remote-object':
return objects_registry_1.default.get(meta.id);
case 'array':
return unwrapArgs(sender, frameId, contextId, meta.value);
case 'buffer':
return Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength);
case 'promise':
return Promise.resolve({
then: metaToValue(meta.then)
});
case 'object': {
const ret = meta.name !== 'Object' ? Object.create({
constructor: fakeConstructor(Object, meta.name)
}) : {};
for (const { name, value } of meta.members) {
ret[name] = metaToValue(value);
}
return ret;
}
case 'function-with-return-value': {
const returnValue = metaToValue(meta.value);
return function () {
return returnValue;
};
}
case 'function': {
// Merge contextId and meta.id, since meta.id can be the same in
// different webContents.
const objectId = [contextId, meta.id];
// Cache the callbacks in renderer.
const cachedFunction = getCachedRendererFunction(objectId);
if (cachedFunction !== undefined) {
return cachedFunction;
}
const callIntoRenderer = function (...args) {
let succeed = false;
if (!sender.isDestroyed()) {
try {
succeed = sender.sendToFrame(frameId, "REMOTE_RENDERER_CALLBACK" /* RENDERER_CALLBACK */, contextId, meta.id, valueToMeta(sender, contextId, args)) !== false;
}
catch (error) {
console.warn(`sendToFrame() failed: ${error}`);
}
}
if (!succeed) {
removeRemoteListenersAndLogWarning(this, callIntoRenderer);
}
};
locationInfo.set(callIntoRenderer, meta.location);
Object.defineProperty(callIntoRenderer, 'length', { value: meta.length });
setCachedRendererFunction(objectId, sender, frameId, callIntoRenderer);
return callIntoRenderer;
}
default:
throw new TypeError(`Unknown type: ${meta.type}`);
}
};
return args.map(metaToValue);
};
const isRemoteModuleEnabledImpl = function (contents) {
const webPreferences = contents.getLastWebPreferences() || {};
return webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : false;
};
const isRemoteModuleEnabledCache = new WeakMap();
const isRemoteModuleEnabled = function (contents) {
if (!isRemoteModuleEnabledCache.has(contents)) {
isRemoteModuleEnabledCache.set(contents, isRemoteModuleEnabledImpl(contents));
}
return isRemoteModuleEnabledCache.get(contents);
};
exports.isRemoteModuleEnabled = isRemoteModuleEnabled;
const handleRemoteCommand = function (channel, handler) {
electron_1.ipcMain.on(channel, (event, contextId, ...args) => {
let returnValue;
if (!exports.isRemoteModuleEnabled(event.sender)) {
event.returnValue = {
type: 'exception',
value: valueToMeta(event.sender, contextId, new Error('@electron/remote is disabled for this WebContents. Set {enableRemoteModule: true} in WebPreferences to enable it.'))
};
return;
}
try {
returnValue = handler(event, contextId, ...args);
}
catch (error) {
returnValue = {
type: 'exception',
value: valueToMeta(event.sender, contextId, error),
};
}
if (returnValue !== undefined) {
event.returnValue = returnValue;
}
});
};
const emitCustomEvent = function (contents, eventName, ...args) {
const event = { sender: contents, returnValue: undefined, defaultPrevented: false };
electron_1.app.emit(eventName, event, contents, ...args);
contents.emit(eventName, event, ...args);
return event;
};
const logStack = function (contents, code, stack) {
if (stack) {
console.warn(`WebContents (${contents.id}): ${code}`, stack);
}
};
let initialized = false;
function initialize() {
if (initialized)
throw new Error('electron-remote has already been initialized');
initialized = true;
handleRemoteCommand("REMOTE_BROWSER_WRONG_CONTEXT_ERROR" /* BROWSER_WRONG_CONTEXT_ERROR */, function (event, contextId, passedContextId, id) {
const objectId = [passedContextId, id];
const cachedFunction = getCachedRendererFunction(objectId);
if (cachedFunction === undefined) {
// Do nothing if the error has already been reported before.
return;
}
removeRemoteListenersAndLogWarning(event.sender, cachedFunction);
});
handleRemoteCommand("REMOTE_BROWSER_REQUIRE" /* BROWSER_REQUIRE */, function (event, contextId, moduleName, stack) {
logStack(event.sender, `remote.require('${moduleName}')`, stack);
const customEvent = emitCustomEvent(event.sender, 'remote-require', moduleName);
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.require('${moduleName}')`);
}
else {
customEvent.returnValue = process.mainModule.require(moduleName);
}
}
return valueToMeta(event.sender, contextId, customEvent.returnValue);
});
handleRemoteCommand("REMOTE_BROWSER_GET_BUILTIN" /* BROWSER_GET_BUILTIN */, function (event, contextId, moduleName, stack) {
logStack(event.sender, `remote.getBuiltin('${moduleName}')`, stack);
const customEvent = emitCustomEvent(event.sender, 'remote-get-builtin', moduleName);
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.getBuiltin('${moduleName}')`);
}
else {
customEvent.returnValue = require('electron')[moduleName];
}
}
return valueToMeta(event.sender, contextId, customEvent.returnValue);
});
handleRemoteCommand("REMOTE_BROWSER_GET_GLOBAL" /* BROWSER_GET_GLOBAL */, function (event, contextId, globalName, stack) {
logStack(event.sender, `remote.getGlobal('${globalName}')`, stack);
const customEvent = emitCustomEvent(event.sender, 'remote-get-global', globalName);
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.getGlobal('${globalName}')`);
}
else {
customEvent.returnValue = global[globalName];
}
}
return valueToMeta(event.sender, contextId, customEvent.returnValue);
});
handleRemoteCommand("REMOTE_BROWSER_GET_CURRENT_WINDOW" /* BROWSER_GET_CURRENT_WINDOW */, function (event, contextId, stack) {
logStack(event.sender, 'remote.getCurrentWindow()', stack);
const customEvent = emitCustomEvent(event.sender, 'remote-get-current-window');
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error('Blocked remote.getCurrentWindow()');
}
else {
customEvent.returnValue = event.sender.getOwnerBrowserWindow();
}
}
return valueToMeta(event.sender, contextId, customEvent.returnValue);
});
handleRemoteCommand("REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS" /* BROWSER_GET_CURRENT_WEB_CONTENTS */, function (event, contextId, stack) {
logStack(event.sender, 'remote.getCurrentWebContents()', stack);
const customEvent = emitCustomEvent(event.sender, 'remote-get-current-web-contents');
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error('Blocked remote.getCurrentWebContents()');
}
else {
customEvent.returnValue = event.sender;
}
}
return valueToMeta(event.sender, contextId, customEvent.returnValue);
});
handleRemoteCommand("REMOTE_BROWSER_CONSTRUCTOR" /* BROWSER_CONSTRUCTOR */, function (event, contextId, id, args) {
args = unwrapArgs(event.sender, event.frameId, contextId, args);
const constructor = objects_registry_1.default.get(id);
if (constructor == null) {
throwRPCError(`Cannot call constructor on missing remote object ${id}`);
}
return valueToMeta(event.sender, contextId, new constructor(...args));
});
handleRemoteCommand("REMOTE_BROWSER_FUNCTION_CALL" /* BROWSER_FUNCTION_CALL */, function (event, contextId, id, args) {
args = unwrapArgs(event.sender, event.frameId, contextId, args);
const func = objects_registry_1.default.get(id);
if (func == null) {
throwRPCError(`Cannot call function on missing remote object ${id}`);
}
try {
return valueToMeta(event.sender, contextId, func(...args), true);
}
catch (error) {
const err = new Error(`Could not call remote function '${func.name || 'anonymous'}'. Check that the function signature is correct. Underlying error: ${error.message}\nUnderlying stack: ${error.stack}\n`);
err.cause = error;
throw err;
}
});
handleRemoteCommand("REMOTE_BROWSER_MEMBER_CONSTRUCTOR" /* BROWSER_MEMBER_CONSTRUCTOR */, function (event, contextId, id, method, args) {
args = unwrapArgs(event.sender, event.frameId, contextId, args);
const object = objects_registry_1.default.get(id);
if (object == null) {
throwRPCError(`Cannot call constructor '${method}' on missing remote object ${id}`);
}
return valueToMeta(event.sender, contextId, new object[method](...args));
});
handleRemoteCommand("REMOTE_BROWSER_MEMBER_CALL" /* BROWSER_MEMBER_CALL */, function (event, contextId, id, method, args) {
args = unwrapArgs(event.sender, event.frameId, contextId, args);
const object = objects_registry_1.default.get(id);
if (object == null) {
throwRPCError(`Cannot call method '${method}' on missing remote object ${id}`);
}
try {
return valueToMeta(event.sender, contextId, object[method](...args), true);
}
catch (error) {
const err = new Error(`Could not call remote method '${method}'. Check that the method signature is correct. Underlying error: ${error.message}\nUnderlying stack: ${error.stack}\n`);
err.cause = error;
throw err;
}
});
handleRemoteCommand("REMOTE_BROWSER_MEMBER_SET" /* BROWSER_MEMBER_SET */, function (event, contextId, id, name, args) {
args = unwrapArgs(event.sender, event.frameId, contextId, args);
const obj = objects_registry_1.default.get(id);
if (obj == null) {
throwRPCError(`Cannot set property '${name}' on missing remote object ${id}`);
}
obj[name] = args[0];
return null;
});
handleRemoteCommand("REMOTE_BROWSER_MEMBER_GET" /* BROWSER_MEMBER_GET */, function (event, contextId, id, name) {
const obj = objects_registry_1.default.get(id);
if (obj == null) {
throwRPCError(`Cannot get property '${name}' on missing remote object ${id}`);
}
return valueToMeta(event.sender, contextId, obj[name]);
});
handleRemoteCommand("REMOTE_BROWSER_DEREFERENCE" /* BROWSER_DEREFERENCE */, function (event, contextId, id) {
objects_registry_1.default.remove(event.sender, contextId, id);
});
handleRemoteCommand("REMOTE_BROWSER_CONTEXT_RELEASE" /* BROWSER_CONTEXT_RELEASE */, (event, contextId) => {
objects_registry_1.default.clear(event.sender, contextId);
return null;
});
}
exports.initialize = initialize;
@@ -0,0 +1,11 @@
export declare class CallbacksRegistry {
private nextId;
private callbacks;
private callbackIds;
private locationInfo;
add(callback: Function): number;
get(id: number): Function;
getLocation(callback: Function): string | undefined;
apply(id: number, ...args: any[]): any;
remove(id: number): void;
}
+64
View File
@@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CallbacksRegistry = void 0;
class CallbacksRegistry {
constructor() {
this.nextId = 0;
this.callbacks = {};
this.callbackIds = new WeakMap();
this.locationInfo = new WeakMap();
}
add(callback) {
// The callback is already added.
let id = this.callbackIds.get(callback);
if (id != null)
return id;
id = this.nextId += 1;
this.callbacks[id] = callback;
this.callbackIds.set(callback, id);
// Capture the location of the function and put it in the ID string,
// so that release errors can be tracked down easily.
const regexp = /at (.*)/gi;
const stackString = (new Error()).stack;
if (!stackString)
return id;
let filenameAndLine;
let match;
while ((match = regexp.exec(stackString)) !== null) {
const location = match[1];
if (location.includes('(native)'))
continue;
if (location.includes('(<anonymous>)'))
continue;
if (location.includes('callbacks-registry.js'))
continue;
if (location.includes('remote.js'))
continue;
if (location.includes('@electron/remote/dist'))
continue;
const ref = /([^/^)]*)\)?$/gi.exec(location);
if (ref)
filenameAndLine = ref[1];
break;
}
this.locationInfo.set(callback, filenameAndLine);
return id;
}
get(id) {
return this.callbacks[id] || function () { };
}
getLocation(callback) {
return this.locationInfo.get(callback);
}
apply(id, ...args) {
return this.get(id).apply(global, ...args);
}
remove(id) {
const callback = this.callbacks[id];
if (callback) {
this.callbackIds.delete(callback);
delete this.callbacks[id];
}
}
}
exports.CallbacksRegistry = CallbacksRegistry;
+1
View File
@@ -0,0 +1 @@
export * from './remote';
+15
View File
@@ -0,0 +1,15 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
if (process.type === 'browser')
throw new Error(`"@electron/remote" cannot be required in the browser process. Instead require("@electron/remote/main").`);
__exportStar(require("./remote"), exports);
+6
View File
@@ -0,0 +1,6 @@
import { BrowserWindow, WebContents } from 'electron';
export declare function getBuiltin(module: string): any;
export declare function getCurrentWindow(): BrowserWindow;
export declare function getCurrentWebContents(): WebContents;
export declare function getGlobal<T = any>(name: string): T;
export declare function createFunctionWithReturnValue<T>(returnValue: T): () => T;
+402
View File
@@ -0,0 +1,402 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFunctionWithReturnValue = exports.getGlobal = exports.getCurrentWebContents = exports.getCurrentWindow = exports.getBuiltin = void 0;
const callbacks_registry_1 = require("./callbacks-registry");
const type_utils_1 = require("../common/type-utils");
const electron_1 = require("electron");
const module_names_1 = require("../common/module-names");
const get_electron_binding_1 = require("../common/get-electron-binding");
const callbacksRegistry = new callbacks_registry_1.CallbacksRegistry();
const remoteObjectCache = new Map();
const finalizationRegistry = new FinalizationRegistry((id) => {
const ref = remoteObjectCache.get(id);
if (ref !== undefined && ref.deref() === undefined) {
remoteObjectCache.delete(id);
electron_1.ipcRenderer.send("REMOTE_BROWSER_DEREFERENCE" /* BROWSER_DEREFERENCE */, contextId, id, 0);
}
});
const electronIds = new WeakMap();
const isReturnValue = new WeakSet();
function getCachedRemoteObject(id) {
const ref = remoteObjectCache.get(id);
if (ref !== undefined) {
const deref = ref.deref();
if (deref !== undefined)
return deref;
}
}
function setCachedRemoteObject(id, value) {
const wr = new WeakRef(value);
remoteObjectCache.set(id, wr);
finalizationRegistry.register(value, id);
return value;
}
function getContextId() {
const v8Util = get_electron_binding_1.getElectronBinding('v8_util');
if (v8Util) {
return v8Util.getHiddenValue(global, 'contextId');
}
else {
throw new Error('Electron >=v13.0.0-beta.6 required to support sandboxed renderers');
}
}
// An unique ID that can represent current context.
const contextId = process.contextId || getContextId();
// Notify the main process when current context is going to be released.
// Note that when the renderer process is destroyed, the message may not be
// sent, we also listen to the "render-view-deleted" event in the main process
// to guard that situation.
process.on('exit', () => {
const command = "REMOTE_BROWSER_CONTEXT_RELEASE" /* BROWSER_CONTEXT_RELEASE */;
electron_1.ipcRenderer.send(command, contextId);
});
const IS_REMOTE_PROXY = Symbol('is-remote-proxy');
// Convert the arguments object into an array of meta data.
function wrapArgs(args, visited = new Set()) {
const valueToMeta = (value) => {
// Check for circular reference.
if (visited.has(value)) {
return {
type: 'value',
value: null
};
}
if (value && value.constructor && value.constructor.name === 'NativeImage') {
return { type: 'nativeimage', value: type_utils_1.serialize(value) };
}
else if (Array.isArray(value)) {
visited.add(value);
const meta = {
type: 'array',
value: wrapArgs(value, visited)
};
visited.delete(value);
return meta;
}
else if (value instanceof Buffer) {
return {
type: 'buffer',
value
};
}
else if (type_utils_1.isSerializableObject(value)) {
return {
type: 'value',
value
};
}
else if (typeof value === 'object') {
if (type_utils_1.isPromise(value)) {
return {
type: 'promise',
then: valueToMeta(function (onFulfilled, onRejected) {
value.then(onFulfilled, onRejected);
})
};
}
else if (electronIds.has(value)) {
return {
type: 'remote-object',
id: electronIds.get(value)
};
}
const meta = {
type: 'object',
name: value.constructor ? value.constructor.name : '',
members: []
};
visited.add(value);
for (const prop in value) { // eslint-disable-line guard-for-in
meta.members.push({
name: prop,
value: valueToMeta(value[prop])
});
}
visited.delete(value);
return meta;
}
else if (typeof value === 'function' && isReturnValue.has(value)) {
return {
type: 'function-with-return-value',
value: valueToMeta(value())
};
}
else if (typeof value === 'function') {
return {
type: 'function',
id: callbacksRegistry.add(value),
location: callbacksRegistry.getLocation(value),
length: value.length
};
}
else {
return {
type: 'value',
value
};
}
};
return args.map(valueToMeta);
}
// Populate object's members from descriptors.
// The |ref| will be kept referenced by |members|.
// This matches |getObjectMemebers| in rpc-server.
function setObjectMembers(ref, object, metaId, members) {
if (!Array.isArray(members))
return;
for (const member of members) {
if (Object.prototype.hasOwnProperty.call(object, member.name))
continue;
const descriptor = { enumerable: member.enumerable };
if (member.type === 'method') {
const remoteMemberFunction = function (...args) {
let command;
if (this && this.constructor === remoteMemberFunction) {
command = "REMOTE_BROWSER_MEMBER_CONSTRUCTOR" /* BROWSER_MEMBER_CONSTRUCTOR */;
}
else {
command = "REMOTE_BROWSER_MEMBER_CALL" /* BROWSER_MEMBER_CALL */;
}
const ret = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name, wrapArgs(args));
return metaToValue(ret);
};
let descriptorFunction = proxyFunctionProperties(remoteMemberFunction, metaId, member.name);
descriptor.get = () => {
descriptorFunction.ref = ref; // The member should reference its object.
return descriptorFunction;
};
// Enable monkey-patch the method
descriptor.set = (value) => {
descriptorFunction = value;
return value;
};
descriptor.configurable = true;
}
else if (member.type === 'get') {
descriptor.get = () => {
const command = "REMOTE_BROWSER_MEMBER_GET" /* BROWSER_MEMBER_GET */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name);
return metaToValue(meta);
};
if (member.writable) {
descriptor.set = (value) => {
const args = wrapArgs([value]);
const command = "REMOTE_BROWSER_MEMBER_SET" /* BROWSER_MEMBER_SET */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, member.name, args);
if (meta != null)
metaToValue(meta);
return value;
};
}
}
Object.defineProperty(object, member.name, descriptor);
}
}
// Populate object's prototype from descriptor.
// This matches |getObjectPrototype| in rpc-server.
function setObjectPrototype(ref, object, metaId, descriptor) {
if (descriptor === null)
return;
const proto = {};
setObjectMembers(ref, proto, metaId, descriptor.members);
setObjectPrototype(ref, proto, metaId, descriptor.proto);
Object.setPrototypeOf(object, proto);
}
// Wrap function in Proxy for accessing remote properties
function proxyFunctionProperties(remoteMemberFunction, metaId, name) {
let loaded = false;
// Lazily load function properties
const loadRemoteProperties = () => {
if (loaded)
return;
loaded = true;
const command = "REMOTE_BROWSER_MEMBER_GET" /* BROWSER_MEMBER_GET */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, metaId, name);
setObjectMembers(remoteMemberFunction, remoteMemberFunction, meta.id, meta.members);
};
return new Proxy(remoteMemberFunction, {
set: (target, property, value) => {
if (property !== 'ref')
loadRemoteProperties();
target[property] = value;
return true;
},
get: (target, property) => {
if (property === IS_REMOTE_PROXY)
return true;
if (!Object.prototype.hasOwnProperty.call(target, property))
loadRemoteProperties();
const value = target[property];
if (property === 'toString' && typeof value === 'function') {
return value.bind(target);
}
return value;
},
ownKeys: (target) => {
loadRemoteProperties();
return Object.getOwnPropertyNames(target);
},
getOwnPropertyDescriptor: (target, property) => {
const descriptor = Object.getOwnPropertyDescriptor(target, property);
if (descriptor)
return descriptor;
loadRemoteProperties();
return Object.getOwnPropertyDescriptor(target, property);
}
});
}
// Convert meta data from browser into real value.
function metaToValue(meta) {
if (meta.type === 'value') {
return meta.value;
}
else if (meta.type === 'array') {
return meta.members.map((member) => metaToValue(member));
}
else if (meta.type === 'nativeimage') {
return type_utils_1.deserialize(meta.value);
}
else if (meta.type === 'buffer') {
return Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength);
}
else if (meta.type === 'promise') {
return Promise.resolve({ then: metaToValue(meta.then) });
}
else if (meta.type === 'error') {
return metaToError(meta);
}
else if (meta.type === 'exception') {
if (meta.value.type === 'error') {
throw metaToError(meta.value);
}
else {
throw new Error(`Unexpected value type in exception: ${meta.value.type}`);
}
}
else {
let ret;
if ('id' in meta) {
const cached = getCachedRemoteObject(meta.id);
if (cached !== undefined) {
return cached;
}
}
// A shadow class to represent the remote function object.
if (meta.type === 'function') {
const remoteFunction = function (...args) {
let command;
if (this && this.constructor === remoteFunction) {
command = "REMOTE_BROWSER_CONSTRUCTOR" /* BROWSER_CONSTRUCTOR */;
}
else {
command = "REMOTE_BROWSER_FUNCTION_CALL" /* BROWSER_FUNCTION_CALL */;
}
const obj = electron_1.ipcRenderer.sendSync(command, contextId, meta.id, wrapArgs(args));
return metaToValue(obj);
};
ret = remoteFunction;
}
else {
ret = {};
}
setObjectMembers(ret, ret, meta.id, meta.members);
setObjectPrototype(ret, ret, meta.id, meta.proto);
if (ret.constructor && ret.constructor[IS_REMOTE_PROXY]) {
Object.defineProperty(ret.constructor, 'name', { value: meta.name });
}
// Track delegate obj's lifetime & tell browser to clean up when object is GCed.
electronIds.set(ret, meta.id);
setCachedRemoteObject(meta.id, ret);
return ret;
}
}
function metaToError(meta) {
const obj = meta.value;
for (const { name, value } of meta.members) {
obj[name] = metaToValue(value);
}
return obj;
}
function handleMessage(channel, handler) {
electron_1.ipcRenderer.on(channel, (event, passedContextId, id, ...args) => {
if (event.senderId !== 0) {
console.error(`Message ${channel} sent by unexpected WebContents (${event.senderId})`);
return;
}
if (passedContextId === contextId) {
handler(id, ...args);
}
else {
// Message sent to an un-exist context, notify the error to main process.
electron_1.ipcRenderer.send("REMOTE_BROWSER_WRONG_CONTEXT_ERROR" /* BROWSER_WRONG_CONTEXT_ERROR */, contextId, passedContextId, id);
}
});
}
const enableStacks = process.argv.includes('--enable-api-filtering-logging');
function getCurrentStack() {
const target = { stack: undefined };
if (enableStacks) {
Error.captureStackTrace(target, getCurrentStack);
}
return target.stack;
}
// Browser calls a callback in renderer.
handleMessage("REMOTE_RENDERER_CALLBACK" /* RENDERER_CALLBACK */, (id, args) => {
callbacksRegistry.apply(id, metaToValue(args));
});
// A callback in browser is released.
handleMessage("REMOTE_RENDERER_RELEASE_CALLBACK" /* RENDERER_RELEASE_CALLBACK */, (id) => {
callbacksRegistry.remove(id);
});
exports.require = (module) => {
const command = "REMOTE_BROWSER_REQUIRE" /* BROWSER_REQUIRE */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, module, getCurrentStack());
return metaToValue(meta);
};
// Alias to remote.require('electron').xxx.
function getBuiltin(module) {
const command = "REMOTE_BROWSER_GET_BUILTIN" /* BROWSER_GET_BUILTIN */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, module, getCurrentStack());
return metaToValue(meta);
}
exports.getBuiltin = getBuiltin;
function getCurrentWindow() {
const command = "REMOTE_BROWSER_GET_CURRENT_WINDOW" /* BROWSER_GET_CURRENT_WINDOW */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, getCurrentStack());
return metaToValue(meta);
}
exports.getCurrentWindow = getCurrentWindow;
// Get current WebContents object.
function getCurrentWebContents() {
const command = "REMOTE_BROWSER_GET_CURRENT_WEB_CONTENTS" /* BROWSER_GET_CURRENT_WEB_CONTENTS */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, getCurrentStack());
return metaToValue(meta);
}
exports.getCurrentWebContents = getCurrentWebContents;
// Get a global object in browser.
function getGlobal(name) {
const command = "REMOTE_BROWSER_GET_GLOBAL" /* BROWSER_GET_GLOBAL */;
const meta = electron_1.ipcRenderer.sendSync(command, contextId, name, getCurrentStack());
return metaToValue(meta);
}
exports.getGlobal = getGlobal;
// Get the process object in browser.
Object.defineProperty(exports, 'process', {
enumerable: true,
get: () => exports.getGlobal('process')
});
// Create a function that will return the specified value when called in browser.
function createFunctionWithReturnValue(returnValue) {
const func = () => returnValue;
isReturnValue.add(func);
return func;
}
exports.createFunctionWithReturnValue = createFunctionWithReturnValue;
const addBuiltinProperty = (name) => {
Object.defineProperty(exports, name, {
enumerable: true,
get: () => exports.getBuiltin(name)
});
};
module_names_1.browserModuleNames
.forEach(addBuiltinProperty);