2020-03-20 20:28:31 +00:00
'use strict' ;
2019-09-18 16:52:06 +00:00
2020-03-20 20:28:31 +00:00
import * as electron from 'electron' ;
import { EventEmitter } from 'events' ;
import objectsRegistry from './objects-registry' ;
import { ipcMainInternal } from '../ipc-main-internal' ;
2020-05-28 16:43:15 +00:00
import { isPromise , isSerializableObject , deserialize , serialize } from '@electron/internal/common/type-utils' ;
2020-05-18 16:29:24 +00:00
import { Size } from 'electron/main' ;
2019-09-18 16:52:06 +00:00
2020-03-20 20:28:31 +00:00
const v8Util = process . electronBinding ( 'v8_util' ) ;
const eventBinding = process . electronBinding ( 'event' ) ;
const features = process . electronBinding ( 'features' ) ;
2020-05-28 16:43:15 +00:00
const { NativeImage } = process . electronBinding ( 'native_image' ) ;
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
}
2020-03-20 20:28:31 +00:00
const hasProp = { } . hasOwnProperty ;
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
// The remote functions in renderer processes.
// id => Function
2020-03-20 20:28:31 +00:00
const rendererFunctions = v8Util . createDoubleIDWeakMap < ( . . . args : any [ ] ) = > void > ( ) ;
2019-09-18 16:52:06 +00:00
2019-09-30 22:00:22 +00:00
type ObjectMember = {
name : string ,
value? : any ,
enumerable? : boolean ,
writable? : boolean ,
type ? : 'method' | 'get'
}
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
2019-09-30 22:00:22 +00:00
type ObjProtoDescriptor = {
members : ObjectMember [ ] ,
proto : ObjProtoDescriptor
} | null
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
2019-09-30 22:00:22 +00:00
type MetaType = {
type : 'number' ,
value : number
} | {
type : 'boolean' ,
value : boolean
} | {
type : 'string' ,
value : string
} | {
type : 'bigint' ,
value : bigint
} | {
type : 'symbol' ,
value : symbol
} | {
type : 'undefined' ,
value : undefined
} | {
type : 'object' | 'function' ,
name : string ,
members : ObjectMember [ ] ,
proto : ObjProtoDescriptor ,
id : number ,
} | {
type : 'value' ,
value : any ,
} | {
type : 'buffer' ,
2019-10-10 13:59:08 +00:00
value : Uint8Array ,
2019-09-30 22:00:22 +00:00
} | {
type : 'array' ,
members : MetaType [ ]
} | {
type : 'error' ,
2019-10-10 13:59:08 +00:00
value : Error ,
2019-09-30 22:00:22 +00:00
members : ObjectMember [ ]
} | {
type : 'promise' ,
then : MetaType
2020-05-28 16:43:15 +00:00
} | {
type : 'nativeimage'
value : electron.NativeImage
2019-09-30 22:00:22 +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-03-20 20:28:31 +00:00
let type : MetaType [ 'type' ] = typeof value ;
2019-09-30 22:00:22 +00:00
if ( type === 'object' ) {
2019-09-18 16:52:06 +00:00
// Recognize certain types of objects.
2019-10-10 13:59:08 +00:00
if ( value instanceof Buffer ) {
2020-03-20 20:28:31 +00:00
type = 'buffer' ;
2020-05-28 16:43:15 +00:00
} else if ( value instanceof NativeImage ) {
type = 'nativeimage' ;
2019-09-18 16:52:06 +00:00
} else if ( Array . isArray ( value ) ) {
2020-03-20 20:28:31 +00:00
type = 'array' ;
2019-09-18 16:52:06 +00:00
} else if ( value instanceof Error ) {
2020-03-20 20:28:31 +00:00
type = 'error' ;
2019-10-10 13:59:08 +00:00
} else if ( isSerializableObject ( value ) ) {
2020-03-20 20:28:31 +00:00
type = 'value' ;
2019-09-18 16:52:06 +00:00
} else if ( isPromise ( value ) ) {
2020-03-20 20:28:31 +00:00
type = 'promise' ;
2019-09-18 16:52:06 +00:00
} else if ( hasProp . call ( value , 'callee' ) && value . length != null ) {
// Treat the arguments object as array.
2020-03-20 20:28:31 +00:00
type = 'array' ;
2019-09-18 16:52:06 +00:00
} else if ( optimizeSimpleObject && v8Util . getHiddenValue ( value , 'simple' ) ) {
// Treat simple objects as value.
2020-03-20 20:28:31 +00:00
type = 'value' ;
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-09-30 22:00:22 +00:00
type MetaTypeFromRenderer = {
type : 'value' ,
value : any
} | {
type : 'remote-object' ,
id : number
} | {
type : 'array' ,
value : MetaTypeFromRenderer [ ]
} | {
type : 'buffer' ,
2019-10-10 13:59:08 +00:00
value : Uint8Array
2019-09-30 22:00:22 +00:00
} | {
type : 'promise' ,
then : MetaTypeFromRenderer
} | {
type : 'object' ,
name : string ,
2020-05-22 15:56:57 +00:00
members : {
name : string ,
value : MetaTypeFromRenderer
} [ ]
2019-09-30 22:00:22 +00:00
} | {
type : 'function-with-return-value' ,
value : MetaTypeFromRenderer
} | {
type : 'function' ,
id : number ,
location : string ,
length : number
2020-05-18 16:29:24 +00:00
} | {
type : 'nativeimage' ,
2020-05-22 15:56:57 +00:00
value : {
size : Size ,
buffer : Buffer ,
scaleFactor : number ,
dataURL : string
} [ ]
2019-09-30 22:00:22 +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.
if ( rendererFunctions . has ( objectId ) ) {
2020-03-20 20:28:31 +00:00
return rendererFunctions . get ( objectId ) ;
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-03-20 20:28:31 +00:00
succeed = ( sender as any ) . _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-03-20 20:28:31 +00:00
v8Util . setRemoteCallbackFreer ( callIntoRenderer , frameId , contextId , meta . id , sender ) ;
rendererFunctions . set ( objectId , callIntoRenderer ) ;
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-03-20 20:28:31 +00:00
const webPreferences = ( contents as any ) . getLastWebPreferences ( ) || { } ;
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
2019-09-30 22:00:22 +00:00
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 ] ;
2019-09-18 16:52:06 +00:00
if ( ! rendererFunctions . has ( objectId ) ) {
// 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-03-20 20:28:31 +00:00
removeRemoteListenersAndLogWarning ( event . sender , rendererFunctions . get ( objectId ) ! ) ;
} ) ;
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-03-20 20:28:31 +00:00
customEvent . returnValue = process . 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
handleRemoteCommand ( 'ELECTRON_BROWSER_DEREFERENCE' , function ( event , contextId , id , rendererSideRefCount ) {
2020-03-20 20:28:31 +00:00
objectsRegistry . remove ( event . sender , contextId , id , rendererSideRefCount ) ;
} ) ;
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 ) ;
} ) ;
2019-09-18 16:52:06 +00:00
module . exports = {
isRemoteModuleEnabled
2020-03-20 20:28:31 +00:00
} ;