@@ -2,24 +2,18 @@ import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-in
2
2
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils' ;
3
3
import { internalContextBridge } from '@electron/internal/renderer/api/context-bridge' ;
4
4
5
- const inMainWorld = internalContextBridge . isInMainWorld ( ) ;
6
5
const { contextIsolationEnabled } = internalContextBridge ;
7
6
8
- // Should we inject APIs into this world, if ctx isolation is enabled then only inject in the isolated world
9
- // else inject everywhere
10
- const shouldInjectGivenContextIsolationIsMaybeEnabled = contextIsolationEnabled ? ! inMainWorld : true ;
11
-
12
- // This file implements the following APIs Directly:
7
+ // This file implements the following APIs over the ctx bridge:
13
8
// - window.open()
14
9
// - window.opener.blur()
15
10
// - window.opener.close()
16
11
// - window.opener.eval()
17
12
// - window.opener.focus()
18
13
// - window.opener.location
19
14
// - window.opener.print()
15
+ // - window.opener.closed
20
16
// - window.opener.postMessage()
21
-
22
- // And the following APIs over the ctx bridge:
23
17
// - window.history.back()
24
18
// - window.history.forward()
25
19
// - window.history.go()
@@ -40,13 +34,13 @@ const toString = (value: any) => {
40
34
41
35
const windowProxies = new Map < number , BrowserWindowProxy > ( ) ;
42
36
43
- const getOrCreateProxy = ( guestId : number ) => {
37
+ const getOrCreateProxy = ( guestId : number ) : SafelyBoundBrowserWindowProxy => {
44
38
let proxy = windowProxies . get ( guestId ) ;
45
39
if ( proxy == null ) {
46
40
proxy = new BrowserWindowProxy ( guestId ) ;
47
41
windowProxies . set ( guestId , proxy ) ;
48
42
}
49
- return proxy ;
43
+ return proxy . getSafe ( ) ;
50
44
} ;
51
45
52
46
const removeProxy = ( guestId : number ) => {
@@ -74,6 +68,8 @@ class LocationProxy {
74
68
*/
75
69
private static ProxyProperty < T > ( target : LocationProxy , propertyKey : LocationProperties ) {
76
70
Object . defineProperty ( target , propertyKey , {
71
+ enumerable : true ,
72
+ configurable : true ,
77
73
get : function ( this : LocationProxy ) : T | string {
78
74
const guestURL = this . getGuestURL ( ) ;
79
75
const value = guestURL ? guestURL [ propertyKey ] : '' ;
@@ -92,6 +88,30 @@ class LocationProxy {
92
88
} ) ;
93
89
}
94
90
91
+ public getSafe = ( ) => {
92
+ const that = this ;
93
+ return {
94
+ get href ( ) { return that . href ; } ,
95
+ set href ( newValue ) { that . href = newValue ; } ,
96
+ get hash ( ) { return that . hash ; } ,
97
+ set hash ( newValue ) { that . hash = newValue ; } ,
98
+ get host ( ) { return that . host ; } ,
99
+ set host ( newValue ) { that . host = newValue ; } ,
100
+ get hostname ( ) { return that . hostname ; } ,
101
+ set hostname ( newValue ) { that . hostname = newValue ; } ,
102
+ get origin ( ) { return that . origin ; } ,
103
+ set origin ( newValue ) { that . origin = newValue ; } ,
104
+ get pathname ( ) { return that . pathname ; } ,
105
+ set pathname ( newValue ) { that . pathname = newValue ; } ,
106
+ get port ( ) { return that . port ; } ,
107
+ set port ( newValue ) { that . port = newValue ; } ,
108
+ get protocol ( ) { return that . protocol ; } ,
109
+ set protocol ( newValue ) { that . protocol = newValue ; } ,
110
+ get search ( ) { return that . search ; } ,
111
+ set search ( newValue ) { that . search = newValue ; }
112
+ } ;
113
+ }
114
+
95
115
constructor ( guestId : number ) {
96
116
// eslint will consider the constructor "useless"
97
117
// unless we assign them in the body. It's fine, that's what
@@ -124,6 +144,17 @@ class LocationProxy {
124
144
}
125
145
}
126
146
147
+ interface SafelyBoundBrowserWindowProxy {
148
+ location : WindowProxy [ 'location' ] ;
149
+ blur : WindowProxy [ 'blur' ] ;
150
+ close : WindowProxy [ 'close' ] ;
151
+ eval : typeof eval ; // eslint-disable-line no-eval
152
+ focus : WindowProxy [ 'focus' ] ;
153
+ print : WindowProxy [ 'print' ] ;
154
+ postMessage : WindowProxy [ 'postMessage' ] ;
155
+ closed : boolean ;
156
+ }
157
+
127
158
class BrowserWindowProxy {
128
159
public closed : boolean = false
129
160
@@ -134,7 +165,7 @@ class BrowserWindowProxy {
134
165
// so for now, we'll have to make do with an "any" in the mix.
135
166
// https://github.com/Microsoft/TypeScript/issues/2521
136
167
public get location ( ) : LocationProxy | any {
137
- return this . _location ;
168
+ return this . _location . getSafe ( ) ;
138
169
}
139
170
140
171
public set location ( url : string | any ) {
@@ -152,27 +183,48 @@ class BrowserWindowProxy {
152
183
} ) ;
153
184
}
154
185
155
- public close ( ) {
186
+ public getSafe = ( ) : SafelyBoundBrowserWindowProxy => {
187
+ const that = this ;
188
+ return {
189
+ postMessage : this . postMessage ,
190
+ blur : this . blur ,
191
+ close : this . close ,
192
+ focus : this . focus ,
193
+ print : this . print ,
194
+ eval : this . eval ,
195
+ get location ( ) {
196
+ return that . location ;
197
+ } ,
198
+ set location ( url : string | any ) {
199
+ that . location = url ;
200
+ } ,
201
+ get closed ( ) {
202
+ return that . closed ;
203
+ }
204
+ } ;
205
+ }
206
+
207
+ public close = ( ) => {
156
208
this . _invokeWindowMethod ( 'destroy' ) ;
157
209
}
158
210
159
- public focus ( ) {
211
+ public focus = ( ) => {
160
212
this . _invokeWindowMethod ( 'focus' ) ;
161
213
}
162
214
163
- public blur ( ) {
215
+ public blur = ( ) => {
164
216
this . _invokeWindowMethod ( 'blur' ) ;
165
217
}
166
218
167
- public print ( ) {
219
+ public print = ( ) => {
168
220
this . _invokeWebContentsMethod ( 'print' ) ;
169
221
}
170
222
171
- public postMessage ( message : any , targetOrigin : string ) {
223
+ public postMessage = ( message : any , targetOrigin : string ) => {
172
224
ipcRendererInternal . invoke ( 'ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE' , this . guestId , message , toString ( targetOrigin ) , window . location . origin ) ;
173
225
}
174
226
175
- public eval ( code : string ) {
227
+ public eval = ( code : string ) => {
176
228
this . _invokeWebContentsMethod ( 'executeJavaScript' , code ) ;
177
229
}
178
230
@@ -188,12 +240,12 @@ class BrowserWindowProxy {
188
240
export const windowSetup = (
189
241
guestInstanceId : number , openerId : number , isHiddenPage : boolean , usesNativeWindowOpen : boolean , rendererProcessReuseEnabled : boolean
190
242
) => {
191
- if ( ! process . sandboxed && guestInstanceId == null && shouldInjectGivenContextIsolationIsMaybeEnabled ) {
243
+ if ( ! process . sandboxed && guestInstanceId == null ) {
192
244
// Override default window.close.
193
245
window . close = function ( ) {
194
246
ipcRendererInternal . send ( 'ELECTRON_BROWSER_WINDOW_CLOSE' ) ;
195
247
} ;
196
- if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalMethodFromIsolatedWorld ( [ 'close' ] , window . close ) ;
248
+ if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalValueFromIsolatedWorld ( [ 'close' ] , window . close ) ;
197
249
}
198
250
199
251
if ( ! usesNativeWindowOpen ) {
@@ -210,23 +262,21 @@ export const windowSetup = (
210
262
return null ;
211
263
}
212
264
} ;
265
+ if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalValueWithDynamicPropsFromIsolatedWorld ( [ 'open' ] , window . open ) ;
213
266
}
214
267
215
268
if ( openerId != null ) {
216
- // TODO(MarshallOfSound): Make compatible with ctx isolation without hole-punch
217
269
window . opener = getOrCreateProxy ( openerId ) ;
270
+ if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalValueWithDynamicPropsFromIsolatedWorld ( [ 'opener' ] , window . opener ) ;
218
271
}
219
272
220
273
// But we do not support prompt().
221
- if ( shouldInjectGivenContextIsolationIsMaybeEnabled ) {
222
- window . prompt = function ( ) {
223
- throw new Error ( 'prompt() is and will not be supported.' ) ;
224
- } ;
225
- if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalMethodFromIsolatedWorld ( [ 'prompt' ] , window . prompt ) ;
226
- }
274
+ window . prompt = function ( ) {
275
+ throw new Error ( 'prompt() is and will not be supported.' ) ;
276
+ } ;
277
+ if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalValueFromIsolatedWorld ( [ 'prompt' ] , window . prompt ) ;
227
278
228
279
if ( ! usesNativeWindowOpen || openerId != null ) {
229
- // TODO(MarshallOfSound): Make compatible with ctx isolation without hole-punch
230
280
ipcRendererInternal . on ( 'ELECTRON_GUEST_WINDOW_POSTMESSAGE' , function (
231
281
_event , sourceId : number , message : any , sourceOrigin : string
232
282
) {
@@ -247,21 +297,21 @@ export const windowSetup = (
247
297
} ) ;
248
298
}
249
299
250
- if ( ! process . sandboxed && ! rendererProcessReuseEnabled && shouldInjectGivenContextIsolationIsMaybeEnabled ) {
300
+ if ( ! process . sandboxed && ! rendererProcessReuseEnabled ) {
251
301
window . history . back = function ( ) {
252
302
ipcRendererInternal . send ( 'ELECTRON_NAVIGATION_CONTROLLER_GO_BACK' ) ;
253
303
} ;
254
- if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalMethodFromIsolatedWorld ( [ 'history' , 'back' ] , window . history . back ) ;
304
+ if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalValueFromIsolatedWorld ( [ 'history' , 'back' ] , window . history . back ) ;
255
305
256
306
window . history . forward = function ( ) {
257
307
ipcRendererInternal . send ( 'ELECTRON_NAVIGATION_CONTROLLER_GO_FORWARD' ) ;
258
308
} ;
259
- if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalMethodFromIsolatedWorld ( [ 'history' , 'forward' ] , window . history . forward ) ;
309
+ if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalValueFromIsolatedWorld ( [ 'history' , 'forward' ] , window . history . forward ) ;
260
310
261
311
window . history . go = function ( offset : number ) {
262
312
ipcRendererInternal . send ( 'ELECTRON_NAVIGATION_CONTROLLER_GO_TO_OFFSET' , + offset ) ;
263
313
} ;
264
- if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalMethodFromIsolatedWorld ( [ 'history' , 'go' ] , window . history . go ) ;
314
+ if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalValueFromIsolatedWorld ( [ 'history' , 'go' ] , window . history . go ) ;
265
315
266
316
const getHistoryLength = ( ) => ipcRendererInternal . sendSync ( 'ELECTRON_NAVIGATION_CONTROLLER_LENGTH' ) + 104 ;
267
317
Object . defineProperty ( window . history , 'length' , {
@@ -271,7 +321,7 @@ export const windowSetup = (
271
321
if ( contextIsolationEnabled ) internalContextBridge . overrideGlobalPropertyFromIsolatedWorld ( [ 'history' , 'length' ] , getHistoryLength ) ;
272
322
}
273
323
274
- if ( guestInstanceId != null && shouldInjectGivenContextIsolationIsMaybeEnabled ) {
324
+ if ( guestInstanceId != null ) {
275
325
// Webview `document.visibilityState` tracks window visibility (and ignores
276
326
// the actual <webview> element visibility) for backwards compatibility.
277
327
// See discussion in #9178.
0 commit comments