11import {
22 assignFilteredGlobalDescriptorsFromPropertyDescriptorMap ,
3+ CallableEvaluate ,
34 createBlueConnector ,
45 createRedConnector ,
56 getFilteredGlobalOwnKeys ,
67 linkIntrinsics ,
78 DistortionCallback ,
89 Instrumentation ,
910 PropertyKeys ,
11+ SUPPORTS_SHADOW_REALM ,
1012 VirtualEnvironment ,
1113} from '@locker/near-membrane-base' ;
1214
@@ -30,10 +32,15 @@ const IFRAME_SANDBOX_ATTRIBUTE_VALUE = 'allow-same-origin allow-scripts';
3032const ObjectCtor = Object ;
3133const TypeErrorCtor = TypeError ;
3234const { prototype : DocumentProto } = Document ;
35+ const { bind : FunctionProtoBind } = Function . prototype ;
3336const { prototype : NodeProto } = Node ;
3437const { remove : ElementProtoRemove , setAttribute : ElementProtoSetAttribute } = Element . prototype ;
3538const { appendChild : NodeProtoAppendChild } = NodeProto ;
36- const { assign : ObjectAssign } = ObjectCtor ;
39+ const {
40+ assign : ObjectAssign ,
41+ create : ObjectCreate ,
42+ getOwnPropertyDescriptors : ObjectGetOwnPropertyDescriptors ,
43+ } = ObjectCtor ;
3744// eslint-disable-next-line @typescript-eslint/naming-convention
3845const { __lookupGetter__ : ObjectProto__lookupGetter__ } = ObjectCtor . prototype as any ;
3946const { apply : ReflectApply } = Reflect ;
@@ -56,9 +63,14 @@ const HTMLIFrameElementProtoContentWindowGetter = ReflectApply(
5663const NodeProtoLastChildGetter = ReflectApply ( ObjectProto__lookupGetter__ , NodeProto , [
5764 'lastChild' ,
5865] ) ! ;
66+ // @ts -ignore: Prevent cannot find name 'ShadowRealm' error.
67+ const ShadowRealmCtor = SUPPORTS_SHADOW_REALM ? ShadowRealm : undefined ;
68+ const ShadowRealmProtoEvaluate : CallableEvaluate | undefined = ShadowRealmCtor ?. prototype ?. evaluate ;
69+ const defaultGlobalOwnKeysRegistry = { __proto__ : null } ;
5970const docRef = document ;
6071
6172let defaultGlobalOwnKeys : PropertyKeys | null = null ;
73+ let defaultGlobalPropertyDescriptorMap : PropertyDescriptorMap | null = null ;
6274
6375function createDetachableIframe ( ) : HTMLIFrameElement {
6476 const iframe = ReflectApply ( DocumentProtoCreateElement , docRef , [
@@ -163,4 +175,103 @@ function createIframeVirtualEnvironment(
163175 return env ;
164176}
165177
166- export default createIframeVirtualEnvironment ;
178+ function createShadowRealmVirtualEnvironment (
179+ globalObject : WindowProxy & typeof globalThis ,
180+ globalObjectShape : object | null ,
181+ providedOptions ?: BrowserEnvironmentOptions
182+ ) : VirtualEnvironment {
183+ if ( typeof globalObject !== 'object' || globalObject === null ) {
184+ throw new TypeErrorCtor ( 'Missing global object virtualization target.' ) ;
185+ }
186+ const {
187+ distortionCallback,
188+ endowments,
189+ instrumentation,
190+ // eslint-disable-next-line prefer-object-spread
191+ } = ObjectAssign ( { __proto__ : null } , providedOptions ) ;
192+
193+ // If a globalObjectShape has been explicitly specified, reset the
194+ // defaultGlobalPropertyDescriptorMap to null. This will ensure that
195+ // the provided globalObjectShape is used to re-create the cached
196+ // defaultGlobalPropertyDescriptorMap.
197+ if ( globalObjectShape !== null ) {
198+ defaultGlobalPropertyDescriptorMap = null ;
199+ }
200+ if ( defaultGlobalPropertyDescriptorMap === null ) {
201+ let sourceShapeOrOneTimeWindow = globalObjectShape ! ;
202+ let sourceIsIframe = false ;
203+ if ( globalObjectShape === null ) {
204+ const oneTimeIframe = createDetachableIframe ( ) ;
205+ sourceShapeOrOneTimeWindow = ReflectApply (
206+ HTMLIFrameElementProtoContentWindowGetter ,
207+ oneTimeIframe ,
208+ [ ]
209+ ) ! ;
210+ sourceIsIframe = true ;
211+ }
212+ defaultGlobalOwnKeys = getFilteredGlobalOwnKeys ( sourceShapeOrOneTimeWindow ) ;
213+ if ( sourceIsIframe ) {
214+ ReflectApply ( ElementProtoRemove , sourceShapeOrOneTimeWindow , [ ] ) ;
215+ }
216+ defaultGlobalPropertyDescriptorMap = {
217+ __proto__ : null ,
218+ } as unknown as PropertyDescriptorMap ;
219+ assignFilteredGlobalDescriptorsFromPropertyDescriptorMap (
220+ defaultGlobalPropertyDescriptorMap ,
221+ ObjectGetOwnPropertyDescriptors ( globalObject )
222+ ) ;
223+ for ( let i = 0 , { length } = defaultGlobalOwnKeys ; i < length ; i += 1 ) {
224+ defaultGlobalOwnKeysRegistry [ defaultGlobalOwnKeys [ i ] ] = true ;
225+ }
226+ for ( const key in defaultGlobalPropertyDescriptorMap ) {
227+ if ( ! ( key in defaultGlobalOwnKeysRegistry ) ) {
228+ delete defaultGlobalPropertyDescriptorMap [ key ] ;
229+ }
230+ }
231+ }
232+ const blueRefs = getCachedGlobalObjectReferences ( globalObject ) ;
233+ // Create a new environment.
234+ const env = new VirtualEnvironment ( {
235+ blueConnector : createBlueConnector ( globalObject ) ,
236+ distortionCallback,
237+ instrumentation,
238+ redConnector : createRedConnector (
239+ ReflectApply ( FunctionProtoBind , ShadowRealmProtoEvaluate , [ new ShadowRealmCtor ( ) ] )
240+ ) ,
241+ } ) ;
242+ linkIntrinsics ( env , globalObject ) ;
243+ // window
244+ env . link ( 'globalThis' ) ;
245+ // Set globalThis.__proto__ in the sandbox to a proxy of
246+ // globalObject.__proto__ and with this, the entire
247+ // structure around window proto chain should be covered.
248+ env . remapProto ( globalObject , blueRefs . WindowProto ) ;
249+ let unsafeBlueDescMap : PropertyDescriptorMap = defaultGlobalPropertyDescriptorMap ;
250+ if ( globalObject !== window ) {
251+ unsafeBlueDescMap = { __proto__ : null } as unknown as PropertyDescriptorMap ;
252+ assignFilteredGlobalDescriptorsFromPropertyDescriptorMap (
253+ unsafeBlueDescMap ,
254+ ObjectGetOwnPropertyDescriptors ( globalObject )
255+ ) ;
256+ for ( const key in unsafeBlueDescMap ) {
257+ if ( ! ( key in defaultGlobalOwnKeysRegistry ) ) {
258+ delete unsafeBlueDescMap [ key ] ;
259+ }
260+ }
261+ }
262+ env . remapProperties ( blueRefs . window , unsafeBlueDescMap ) ;
263+ if ( endowments ) {
264+ const filteredEndowments : PropertyDescriptorMap = { } ;
265+ assignFilteredGlobalDescriptorsFromPropertyDescriptorMap ( filteredEndowments , endowments ) ;
266+ removeWindowDescriptors ( filteredEndowments ) ;
267+ env . remapProperties ( blueRefs . window , filteredEndowments ) ;
268+ }
269+ // We remap `blueRefs.WindowPropertiesProto` to an empty object because it
270+ // is "magical" in that it provides access to elements by id.
271+ env . remapProto ( blueRefs . WindowProto , ObjectCreate ( blueRefs . EventTargetProto ) ) ;
272+ return env ;
273+ }
274+
275+ export default SUPPORTS_SHADOW_REALM
276+ ? createShadowRealmVirtualEnvironment
277+ : createIframeVirtualEnvironment ;
0 commit comments