2020-07-13 16:58:49 +00:00
import * as electron from 'electron/main' ;
2020-03-20 20:28:31 +00:00
import { EventEmitter } from 'events' ;
2020-07-13 16:58:49 +00:00
import objectsRegistry from '@electron/internal/browser/remote/objects-registry' ;
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal' ;
import { isPromise , isSerializableObject , deserialize , serialize } from '@electron/internal/common/type-utils' ;
import type { MetaTypeFromRenderer , ObjectMember , MetaType , ObjProtoDescriptor } from '@electron/internal/common/remote/types' ;
2019-09-18 16:52:06 +00:00
2020-06-23 03:32:45 +00:00
const v8Util = process . _linkedBinding ( 'electron_common_v8_util' ) ;
const eventBinding = process . _linkedBinding ( 'electron_browser_event' ) ;
const features = process . _linkedBinding ( 'electron_common_features' ) ;
2019-09-18 16:52:06 +00:00
if ( ! features . isRemoteModuleEnabled ( ) ) {
2020-03-20 20:28:31 +00:00
throw new Error ( 'remote module is disabled' ) ;
2019-09-18 16:52:06 +00:00
}
// The internal properties of Function.
const FUNCTION_PROPERTIES = [
'length' , 'name' , 'arguments' , 'caller' , 'prototype'
2020-03-20 20:28:31 +00:00
] ;
2019-09-18 16:52:06 +00:00
2020-06-16 21:34:08 +00:00
type RendererFunctionId = [ string , number ] // [contextId, funcId]
type FinalizerInfo = { id : RendererFunctionId , webContents : electron.WebContents , frameId : number } ;
type CallIntoRenderer = ( . . . args : any [ ] ) = > void
2019-09-18 16:52:06 +00:00
// The remote functions in renderer processes.
2020-06-16 21:34:08 +00:00
const rendererFunctionCache = new Map < string , WeakRef < CallIntoRenderer > > ( ) ;
// eslint-disable-next-line no-undef
2020-10-08 01:01:23 +00:00
const finalizationRegistry = new FinalizationRegistry ( ( fi : FinalizerInfo ) = > {
2020-06-16 21:34:08 +00:00
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 ( ) ) { fi . webContents . sendToFrame ( fi . frameId , 'ELECTRON_RENDERER_RELEASE_CALLBACK' , fi . id [ 0 ] , fi . id [ 1 ] ) ; }
}
} ) ;
function getCachedRendererFunction ( id : RendererFunctionId ) : CallIntoRenderer | undefined {
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 : RendererFunctionId , wc : electron.WebContents , frameId : number , value : CallIntoRenderer ) {
// eslint-disable-next-line no-undef
2020-10-08 01:01:23 +00:00
const wr = new WeakRef < CallIntoRenderer > ( value ) ;
2020-06-16 21:34:08 +00:00
const mapKey = id [ 0 ] + '~' + id [ 1 ] ;
rendererFunctionCache . set ( mapKey , wr ) ;
finalizationRegistry . register ( value , {
id ,
webContents : wc ,
frameId
} as FinalizerInfo ) ;
return value ;
}
2019-09-18 16:52:06 +00:00
// Return the description of object's members:
2019-09-30 22:00:22 +00:00
const getObjectMembers = function ( object : any ) : ObjectMember [ ] {
2020-03-20 20:28:31 +00:00
let names = Object . getOwnPropertyNames ( object ) ;
2019-09-18 16:52:06 +00:00
// For Function, we should not override following properties even though they
// are "own" properties.
if ( typeof object === 'function' ) {
names = names . filter ( ( name ) = > {
2020-03-20 20:28:31 +00:00
return ! FUNCTION_PROPERTIES . includes ( name ) ;
} ) ;
2019-09-18 16:52:06 +00:00
}
// Map properties to descriptors.
return names . map ( ( name ) = > {
2020-03-20 20:28:31 +00:00
const descriptor = Object . getOwnPropertyDescriptor ( object , name ) ! ;
let type : ObjectMember [ 'type' ] ;
let writable = false ;
2019-09-18 16:52:06 +00:00
if ( descriptor . get === undefined && typeof object [ name ] === 'function' ) {
2020-03-20 20:28:31 +00:00
type = 'method' ;
2019-09-18 16:52:06 +00:00
} else {
2020-03-20 20:28:31 +00:00
if ( descriptor . set || descriptor . writable ) writable = true ;
type = 'get' ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
return { name , enumerable : descriptor.enumerable , writable , type } ;
} ) ;
} ;
2019-09-18 16:52:06 +00:00
// Return the description of object's prototype.
2019-09-30 22:00:22 +00:00
const getObjectPrototype = function ( object : any ) : ObjProtoDescriptor {
2020-03-20 20:28:31 +00:00
const proto = Object . getPrototypeOf ( object ) ;
if ( proto === null || proto === Object . prototype ) return null ;
2019-09-18 16:52:06 +00:00
return {
members : getObjectMembers ( proto ) ,
proto : getObjectPrototype ( proto )
2020-03-20 20:28:31 +00:00
} ;
} ;
2019-09-18 16:52:06 +00:00
// Convert a real value into meta data.
2019-09-30 22:00:22 +00:00
const valueToMeta = function ( sender : electron.WebContents , contextId : string , value : any , optimizeSimpleObject = false ) : MetaType {
2019-09-18 16:52:06 +00:00
// Determine the type of value.
2020-06-11 18:36:03 +00:00
let type : MetaType [ 'type' ] ;
switch ( typeof value ) {
case 'object' :
// Recognize certain types of objects.
if ( value instanceof Buffer ) {
type = 'buffer' ;
2020-07-13 21:44:12 +00:00
} else if ( value && value . constructor && value . constructor . name === 'NativeImage' ) {
2020-06-11 18:36:03 +00:00
type = 'nativeimage' ;
} else if ( Array . isArray ( value ) ) {
type = 'array' ;
} else if ( value instanceof Error ) {
type = 'error' ;
} else if ( isSerializableObject ( value ) ) {
type = 'value' ;
} else if ( isPromise ( value ) ) {
type = 'promise' ;
2020-06-16 21:34:08 +00:00
} else if ( Object . prototype . hasOwnProperty . call ( value , 'callee' ) && value . length != null ) {
2020-06-11 18:36:03 +00:00
// 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 :
2020-03-20 20:28:31 +00:00
type = 'value' ;
2020-06-11 18:36:03 +00:00
break ;
2019-09-18 16:52:06 +00:00
}
// Fill the meta object according to value's type.
2019-09-30 22:00:22 +00:00
if ( type === 'array' ) {
return {
type ,
members : value.map ( ( el : any ) = > valueToMeta ( sender , contextId , el , optimizeSimpleObject ) )
2020-03-20 20:28:31 +00:00
} ;
2020-05-28 16:43:15 +00:00
} else if ( type === 'nativeimage' ) {
return { type , value : serialize ( value ) } ;
2019-09-30 22:00:22 +00:00
} 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 : objectsRegistry.add ( sender , contextId , value ) ,
members : getObjectMembers ( value ) ,
proto : getObjectPrototype ( value )
2020-03-20 20:28:31 +00:00
} ;
2019-09-30 22:00:22 +00:00
} else if ( type === 'buffer' ) {
2020-03-20 20:28:31 +00:00
return { type , value } ;
2019-09-30 22:00:22 +00:00
} else if ( type === 'promise' ) {
2019-09-18 16:52:06 +00:00
// Add default handler to prevent unhandled rejections in main process
// Instead they should appear in the renderer process
2020-03-20 20:28:31 +00:00
value . then ( function ( ) { } , function ( ) { } ) ;
2019-09-18 16:52:06 +00:00
2019-09-30 22:00:22 +00:00
return {
type ,
then : valueToMeta ( sender , contextId , function ( onFulfilled : Function , onRejected : Function ) {
2020-03-20 20:28:31 +00:00
value . then ( onFulfilled , onRejected ) ;
2019-09-30 22:00:22 +00:00
} )
2020-03-20 20:28:31 +00:00
} ;
2019-09-30 22:00:22 +00:00
} else if ( type === 'error' ) {
2019-10-10 13:59:08 +00:00
return {
type ,
value ,
members : Object.keys ( value ) . map ( name = > ( {
name ,
value : valueToMeta ( sender , contextId , value [ name ] )
} ) )
2020-03-20 20:28:31 +00:00
} ;
2019-09-18 16:52:06 +00:00
} else {
2019-09-30 22:00:22 +00:00
return {
type : 'value' ,
value
2020-03-20 20:28:31 +00:00
} ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
} ;
2019-09-18 16:52:06 +00:00
2019-09-30 22:00:22 +00:00
const throwRPCError = function ( message : string ) {
2020-03-20 20:28:31 +00:00
const error = new Error ( message ) as Error & { code : string , errno : number } ;
error . code = 'EBADRPC' ;
error . errno = - 72 ;
throw error ;
} ;
2019-09-18 16:52:06 +00:00
2019-09-30 22:00:22 +00:00
const removeRemoteListenersAndLogWarning = ( sender : any , callIntoRenderer : ( . . . args : any [ ] ) = > void ) = > {
2020-03-20 20:28:31 +00:00
const location = v8Util . getHiddenValue ( callIntoRenderer , 'location' ) ;
2020-03-20 15:12:18 +00:00
let message = 'Attempting to call a function in a renderer window that has been closed or released.' +
2020-03-20 20:28:31 +00:00
` \ nFunction provided here: ${ location } ` ;
2019-09-18 16:52:06 +00:00
if ( sender instanceof EventEmitter ) {
const remoteEvents = sender . eventNames ( ) . filter ( ( eventName ) = > {
2020-03-20 20:28:31 +00:00
return sender . listeners ( eventName ) . includes ( callIntoRenderer ) ;
} ) ;
2019-09-18 16:52:06 +00:00
if ( remoteEvents . length > 0 ) {
2020-03-20 20:28:31 +00:00
message += ` \ nRemote event names: ${ remoteEvents . join ( ', ' ) } ` ;
2019-09-18 16:52:06 +00:00
remoteEvents . forEach ( ( eventName ) = > {
2020-03-20 20:28:31 +00:00
sender . removeListener ( eventName as any , callIntoRenderer ) ;
} ) ;
2019-09-18 16:52:06 +00:00
}
}
2020-03-20 20:28:31 +00:00
console . warn ( message ) ;
} ;
2019-09-18 16:52:06 +00:00
2019-10-21 06:48:03 +00:00
const fakeConstructor = ( constructor : Function , name : string ) = >
new Proxy ( Object , {
get ( target , prop , receiver ) {
if ( prop === 'name' ) {
2020-03-20 20:28:31 +00:00
return name ;
2019-10-21 06:48:03 +00:00
} else {
2020-03-20 20:28:31 +00:00
return Reflect . get ( target , prop , receiver ) ;
2019-10-21 06:48:03 +00:00
}
}
2020-03-20 20:28:31 +00:00
} ) ;
2019-10-21 06:48:03 +00:00
2019-09-18 16:52:06 +00:00
// Convert array of meta data from renderer into array of real values.
2019-09-30 22:00:22 +00:00
const unwrapArgs = function ( sender : electron.WebContents , frameId : number , contextId : string , args : any [ ] ) {
const metaToValue = function ( meta : MetaTypeFromRenderer ) : any {
2019-09-18 16:52:06 +00:00
switch ( meta . type ) {
2020-05-22 15:56:57 +00:00
case 'nativeimage' :
return deserialize ( meta . value ) ;
2019-09-18 16:52:06 +00:00
case 'value' :
2020-03-20 20:28:31 +00:00
return meta . value ;
2019-09-18 16:52:06 +00:00
case 'remote-object' :
2020-03-20 20:28:31 +00:00
return objectsRegistry . get ( meta . id ) ;
2019-09-18 16:52:06 +00:00
case 'array' :
2020-03-20 20:28:31 +00:00
return unwrapArgs ( sender , frameId , contextId , meta . value ) ;
2019-09-18 16:52:06 +00:00
case 'buffer' :
2020-03-20 20:28:31 +00:00
return Buffer . from ( meta . value . buffer , meta . value . byteOffset , meta . value . byteLength ) ;
2019-09-18 16:52:06 +00:00
case 'promise' :
return Promise . resolve ( {
then : metaToValue ( meta . then )
2020-03-20 20:28:31 +00:00
} ) ;
2019-09-18 16:52:06 +00:00
case 'object' : {
2019-10-21 06:48:03 +00:00
const ret : any = meta . name !== 'Object' ? Object . create ( {
constructor : fakeConstructor ( Object , meta . name )
2020-03-20 20:28:31 +00:00
} ) : { } ;
2019-09-18 16:52:06 +00:00
for ( const { name , value } of meta . members ) {
2020-03-20 20:28:31 +00:00
ret [ name ] = metaToValue ( value ) ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
return ret ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 15:12:18 +00:00
case 'function-with-return-value' : {
2020-03-20 20:28:31 +00:00
const returnValue = metaToValue ( meta . value ) ;
2019-09-18 16:52:06 +00:00
return function ( ) {
2020-03-20 20:28:31 +00:00
return returnValue ;
} ;
2020-03-20 15:12:18 +00:00
}
2019-09-18 16:52:06 +00:00
case 'function' : {
// Merge contextId and meta.id, since meta.id can be the same in
// different webContents.
2020-03-20 20:28:31 +00:00
const objectId : [ string , number ] = [ contextId , meta . id ] ;
2019-09-18 16:52:06 +00:00
// Cache the callbacks in renderer.
2020-06-16 21:34:08 +00:00
const cachedFunction = getCachedRendererFunction ( objectId ) ;
if ( cachedFunction !== undefined ) { return cachedFunction ; }
2019-09-18 16:52:06 +00:00
2019-09-30 22:00:22 +00:00
const callIntoRenderer = function ( this : any , . . . args : any [ ] ) {
2020-03-20 20:28:31 +00:00
let succeed = false ;
2019-09-18 16:52:06 +00:00
if ( ! sender . isDestroyed ( ) ) {
2020-10-08 01:01:23 +00:00
succeed = sender . _sendToFrameInternal ( frameId , 'ELECTRON_RENDERER_CALLBACK' , contextId , meta . id , valueToMeta ( sender , contextId , args ) ) ;
2019-09-18 16:52:06 +00:00
}
if ( ! succeed ) {
2020-03-20 20:28:31 +00:00
removeRemoteListenersAndLogWarning ( this , callIntoRenderer ) ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
} ;
v8Util . setHiddenValue ( callIntoRenderer , 'location' , meta . location ) ;
Object . defineProperty ( callIntoRenderer , 'length' , { value : meta.length } ) ;
2019-09-18 16:52:06 +00:00
2020-06-16 21:34:08 +00:00
setCachedRendererFunction ( objectId , sender , frameId , callIntoRenderer ) ;
2020-03-20 20:28:31 +00:00
return callIntoRenderer ;
2019-09-18 16:52:06 +00:00
}
default :
2020-03-20 20:28:31 +00:00
throw new TypeError ( ` Unknown type: ${ ( meta as any ) . type } ` ) ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
} ;
return args . map ( metaToValue ) ;
} ;
2019-09-18 16:52:06 +00:00
2019-09-30 22:00:22 +00:00
const isRemoteModuleEnabledImpl = function ( contents : electron.WebContents ) {
2020-06-25 17:19:08 +00:00
const webPreferences = contents . getLastWebPreferences ( ) || { } ;
2020-03-20 20:28:31 +00:00
return webPreferences . enableRemoteModule != null ? ! ! webPreferences.enableRemoteModule : false ;
} ;
2019-09-18 16:52:06 +00:00
2020-03-20 20:28:31 +00:00
const isRemoteModuleEnabledCache = new WeakMap ( ) ;
2019-09-18 16:52:06 +00:00
2020-06-11 18:36:03 +00:00
export const isRemoteModuleEnabled = function ( contents : electron.WebContents ) {
2019-09-18 16:52:06 +00:00
if ( ! isRemoteModuleEnabledCache . has ( contents ) ) {
2020-03-20 20:28:31 +00:00
isRemoteModuleEnabledCache . set ( contents , isRemoteModuleEnabledImpl ( contents ) ) ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
return isRemoteModuleEnabledCache . get ( contents ) ;
} ;
2019-09-18 16:52:06 +00:00
2019-09-30 22:00:22 +00:00
const handleRemoteCommand = function ( channel : string , handler : ( event : ElectronInternal.IpcMainInternalEvent , contextId : string , . . . args : any [ ] ) = > void ) {
ipcMainInternal . on ( channel , ( event , contextId : string , . . . args : any [ ] ) = > {
2020-03-20 20:28:31 +00:00
let returnValue ;
2019-09-18 16:52:06 +00:00
if ( ! isRemoteModuleEnabled ( event . sender ) ) {
2020-03-20 20:28:31 +00:00
event . returnValue = null ;
return ;
2019-09-18 16:52:06 +00:00
}
try {
2020-03-20 20:28:31 +00:00
returnValue = handler ( event , contextId , . . . args ) ;
2019-09-18 16:52:06 +00:00
} catch ( error ) {
2019-10-10 13:59:08 +00:00
returnValue = {
type : 'exception' ,
value : valueToMeta ( event . sender , contextId , error )
2020-03-20 20:28:31 +00:00
} ;
2019-09-18 16:52:06 +00:00
}
if ( returnValue !== undefined ) {
2020-03-20 20:28:31 +00:00
event . returnValue = returnValue ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
} ) ;
} ;
2019-09-18 16:52:06 +00:00
2019-09-30 22:00:22 +00:00
const emitCustomEvent = function ( contents : electron.WebContents , eventName : string , . . . args : any [ ] ) {
2020-03-20 20:28:31 +00:00
const event = eventBinding . createWithSender ( contents ) ;
2019-09-18 16:52:06 +00:00
2020-03-20 20:28:31 +00:00
electron . app . emit ( eventName , event , contents , . . . args ) ;
contents . emit ( eventName , event , . . . args ) ;
2019-09-18 16:52:06 +00:00
2020-03-20 20:28:31 +00:00
return event ;
} ;
2019-09-18 16:52:06 +00:00
2019-10-04 17:49:09 +00:00
const logStack = function ( contents : electron.WebContents , code : string , stack : string | undefined ) {
if ( stack ) {
2020-03-20 20:28:31 +00:00
console . warn ( ` WebContents ( ${ contents . id } ): ${ code } ` , stack ) ;
2019-10-04 17:49:09 +00:00
}
2020-03-20 20:28:31 +00:00
} ;
2019-10-04 17:49:09 +00:00
2019-09-18 16:52:06 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_WRONG_CONTEXT_ERROR' , function ( event , contextId , passedContextId , id ) {
2020-03-20 20:28:31 +00:00
const objectId : [ string , number ] = [ passedContextId , id ] ;
2020-06-16 21:34:08 +00:00
const cachedFunction = getCachedRendererFunction ( objectId ) ;
if ( cachedFunction === undefined ) {
2019-09-18 16:52:06 +00:00
// Do nothing if the error has already been reported before.
2020-03-20 20:28:31 +00:00
return ;
2019-09-18 16:52:06 +00:00
}
2020-06-16 21:34:08 +00:00
removeRemoteListenersAndLogWarning ( event . sender , cachedFunction ) ;
2020-03-20 20:28:31 +00:00
} ) ;
2019-09-18 16:52:06 +00:00
2019-10-04 17:49:09 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_REQUIRE' , function ( event , contextId , moduleName , stack ) {
2020-03-20 20:28:31 +00:00
logStack ( event . sender , ` remote.require(' ${ moduleName } ') ` , stack ) ;
const customEvent = emitCustomEvent ( event . sender , 'remote-require' , moduleName ) ;
2019-09-18 16:52:06 +00:00
if ( customEvent . returnValue === undefined ) {
if ( customEvent . defaultPrevented ) {
2020-03-20 20:28:31 +00:00
throw new Error ( ` Blocked remote.require(' ${ moduleName } ') ` ) ;
2019-09-18 16:52:06 +00:00
} else {
2020-09-17 22:08:57 +00:00
customEvent . returnValue = ( process as any ) . mainModule . require ( moduleName ) ;
2019-09-18 16:52:06 +00:00
}
}
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , customEvent . returnValue ) ;
} ) ;
2019-09-18 16:52:06 +00:00
2019-10-04 17:49:09 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_GET_BUILTIN' , function ( event , contextId , moduleName , stack ) {
2020-03-20 20:28:31 +00:00
logStack ( event . sender , ` remote.getBuiltin(' ${ moduleName } ') ` , stack ) ;
const customEvent = emitCustomEvent ( event . sender , 'remote-get-builtin' , moduleName ) ;
2019-09-18 16:52:06 +00:00
if ( customEvent . returnValue === undefined ) {
if ( customEvent . defaultPrevented ) {
2020-03-20 20:28:31 +00:00
throw new Error ( ` Blocked remote.getBuiltin(' ${ moduleName } ') ` ) ;
2019-09-18 16:52:06 +00:00
} else {
2020-03-20 20:28:31 +00:00
customEvent . returnValue = ( electron as any ) [ moduleName ] ;
2019-09-18 16:52:06 +00:00
}
}
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , customEvent . returnValue ) ;
} ) ;
2019-09-18 16:52:06 +00:00
2019-10-04 17:49:09 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_GLOBAL' , function ( event , contextId , globalName , stack ) {
2020-03-20 20:28:31 +00:00
logStack ( event . sender , ` remote.getGlobal(' ${ globalName } ') ` , stack ) ;
const customEvent = emitCustomEvent ( event . sender , 'remote-get-global' , globalName ) ;
2019-09-18 16:52:06 +00:00
if ( customEvent . returnValue === undefined ) {
if ( customEvent . defaultPrevented ) {
2020-03-20 20:28:31 +00:00
throw new Error ( ` Blocked remote.getGlobal(' ${ globalName } ') ` ) ;
2019-09-18 16:52:06 +00:00
} else {
2020-03-20 20:28:31 +00:00
customEvent . returnValue = ( global as any ) [ globalName ] ;
2019-09-18 16:52:06 +00:00
}
}
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , customEvent . returnValue ) ;
} ) ;
2019-09-18 16:52:06 +00:00
2019-10-04 17:49:09 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_CURRENT_WINDOW' , function ( event , contextId , stack ) {
2020-03-20 20:28:31 +00:00
logStack ( event . sender , 'remote.getCurrentWindow()' , stack ) ;
const customEvent = emitCustomEvent ( event . sender , 'remote-get-current-window' ) ;
2019-09-18 16:52:06 +00:00
if ( customEvent . returnValue === undefined ) {
if ( customEvent . defaultPrevented ) {
2020-03-20 20:28:31 +00:00
throw new Error ( 'Blocked remote.getCurrentWindow()' ) ;
2019-09-18 16:52:06 +00:00
} else {
2020-03-20 20:28:31 +00:00
customEvent . returnValue = event . sender . getOwnerBrowserWindow ( ) ;
2019-09-18 16:52:06 +00:00
}
}
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , customEvent . returnValue ) ;
} ) ;
2019-09-18 16:52:06 +00:00
2019-10-04 17:49:09 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_CURRENT_WEB_CONTENTS' , function ( event , contextId , stack ) {
2020-03-20 20:28:31 +00:00
logStack ( event . sender , 'remote.getCurrentWebContents()' , stack ) ;
const customEvent = emitCustomEvent ( event . sender , 'remote-get-current-web-contents' ) ;
2019-09-18 16:52:06 +00:00
if ( customEvent . returnValue === undefined ) {
if ( customEvent . defaultPrevented ) {
2020-03-20 20:28:31 +00:00
throw new Error ( 'Blocked remote.getCurrentWebContents()' ) ;
2019-09-18 16:52:06 +00:00
} else {
2020-03-20 20:28:31 +00:00
customEvent . returnValue = event . sender ;
2019-09-18 16:52:06 +00:00
}
}
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , customEvent . returnValue ) ;
} ) ;
2019-09-18 16:52:06 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_CONSTRUCTOR' , function ( event , contextId , id , args ) {
2020-03-20 20:28:31 +00:00
args = unwrapArgs ( event . sender , event . frameId , contextId , args ) ;
const constructor = objectsRegistry . get ( id ) ;
2019-09-18 16:52:06 +00:00
if ( constructor == null ) {
2020-03-20 20:28:31 +00:00
throwRPCError ( ` Cannot call constructor on missing remote object ${ id } ` ) ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , new constructor ( . . . args ) ) ;
} ) ;
2019-09-18 16:52:06 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_FUNCTION_CALL' , function ( event , contextId , id , args ) {
2020-03-20 20:28:31 +00:00
args = unwrapArgs ( event . sender , event . frameId , contextId , args ) ;
const func = objectsRegistry . get ( id ) ;
2019-09-18 16:52:06 +00:00
if ( func == null ) {
2020-03-20 20:28:31 +00:00
throwRPCError ( ` Cannot call function on missing remote object ${ id } ` ) ;
2019-09-18 16:52:06 +00:00
}
try {
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , func ( . . . args ) , true ) ;
2019-09-18 16:52:06 +00:00
} catch ( error ) {
2019-09-30 22:00:22 +00:00
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 ` ) ;
2020-03-20 20:28:31 +00:00
( err as any ) . cause = error ;
throw err ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
} ) ;
2019-09-18 16:52:06 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_MEMBER_CONSTRUCTOR' , function ( event , contextId , id , method , args ) {
2020-03-20 20:28:31 +00:00
args = unwrapArgs ( event . sender , event . frameId , contextId , args ) ;
const object = objectsRegistry . get ( id ) ;
2019-09-18 16:52:06 +00:00
if ( object == null ) {
2020-03-20 20:28:31 +00:00
throwRPCError ( ` Cannot call constructor ' ${ method } ' on missing remote object ${ id } ` ) ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , new object [ method ] ( . . . args ) ) ;
} ) ;
2019-09-18 16:52:06 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_MEMBER_CALL' , function ( event , contextId , id , method , args ) {
2020-03-20 20:28:31 +00:00
args = unwrapArgs ( event . sender , event . frameId , contextId , args ) ;
const object = objectsRegistry . get ( id ) ;
2019-09-18 16:52:06 +00:00
if ( object == null ) {
2020-03-20 20:28:31 +00:00
throwRPCError ( ` Cannot call method ' ${ method } ' on missing remote object ${ id } ` ) ;
2019-09-18 16:52:06 +00:00
}
try {
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , object [ method ] ( . . . args ) , true ) ;
2019-09-18 16:52:06 +00:00
} catch ( error ) {
2019-09-30 22:00:22 +00:00
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 ` ) ;
2020-03-20 20:28:31 +00:00
( err as any ) . cause = error ;
throw err ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
} ) ;
2019-09-18 16:52:06 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_MEMBER_SET' , function ( event , contextId , id , name , args ) {
2020-03-20 20:28:31 +00:00
args = unwrapArgs ( event . sender , event . frameId , contextId , args ) ;
const obj = objectsRegistry . get ( id ) ;
2019-09-18 16:52:06 +00:00
if ( obj == null ) {
2020-03-20 20:28:31 +00:00
throwRPCError ( ` Cannot set property ' ${ name } ' on missing remote object ${ id } ` ) ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
obj [ name ] = args [ 0 ] ;
return null ;
} ) ;
2019-09-18 16:52:06 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_MEMBER_GET' , function ( event , contextId , id , name ) {
2020-03-20 20:28:31 +00:00
const obj = objectsRegistry . get ( id ) ;
2019-09-18 16:52:06 +00:00
if ( obj == null ) {
2020-03-20 20:28:31 +00:00
throwRPCError ( ` Cannot get property ' ${ name } ' on missing remote object ${ id } ` ) ;
2019-09-18 16:52:06 +00:00
}
2020-03-20 20:28:31 +00:00
return valueToMeta ( event . sender , contextId , obj [ name ] ) ;
} ) ;
2019-09-18 16:52:06 +00:00
2020-06-11 17:22:28 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_DEREFERENCE' , function ( event , contextId , id ) {
objectsRegistry . remove ( event . sender , contextId , id ) ;
2020-03-20 20:28:31 +00:00
} ) ;
2019-09-18 16:52:06 +00:00
handleRemoteCommand ( 'ELECTRON_BROWSER_CONTEXT_RELEASE' , ( event , contextId ) = > {
2020-03-20 20:28:31 +00:00
objectsRegistry . clear ( event . sender , contextId ) ;
} ) ;