hijack dynamic document appending in evalling code (#1052)

This commit is contained in:
Kuitos 2020-11-05 17:03:05 +08:00 committed by GitHub
parent 798f3437b9
commit 3fa008be96
4 changed files with 49 additions and 22 deletions

View File

@ -4,7 +4,7 @@
*/
import { isBoundedFunction } from '../../utils';
import { documentAttachProxyMap } from '../common';
import { getCurrentRunningSandboxProxy } from '../common';
import ProxySandbox from '../proxySandbox';
beforeAll(() => {
@ -201,26 +201,42 @@ test('hasOwnProperty should always returns same reference', () => {
expect(proxy.testA.hasOwnProperty).toBe(proxy.testB.hasOwnProperty);
});
test('document accessing should modify the attachDocProxySymbol value every time', () => {
test('document and eval accessing should modify the attachDocProxySymbol value every time', () => {
const proxy1 = new ProxySandbox('doc-access-test1').proxy;
const proxy2 = new ProxySandbox('doc-access-test2').proxy;
const proxy3 = new ProxySandbox('eval-access-test1').proxy;
const proxy4 = new ProxySandbox('eval-access-test2').proxy;
const d1 = proxy1.document;
expect(documentAttachProxyMap.get(d1)).toBe(proxy1);
expect(getCurrentRunningSandboxProxy()).toBe(proxy1);
const d2 = proxy2.document;
expect(documentAttachProxyMap.get(d2)).toBe(proxy2);
expect(getCurrentRunningSandboxProxy()).toBe(proxy2);
expect(d1).toBe(d2);
expect(d1).toBe(document);
// @ts-ignore
const eval1 = proxy3.eval;
expect(getCurrentRunningSandboxProxy()).toBe(proxy3);
// @ts-ignore
const eval2 = proxy4.eval;
expect(getCurrentRunningSandboxProxy()).toBe(proxy4);
expect(eval1).toBe(eval2);
// eslint-disable-next-line no-eval
expect(eval1).toBe(eval);
});
test('document attachDocProxySymbol mark should be remove before next tasl', (done) => {
test('document attachDocProxySymbol mark should be remove before next task', (done) => {
const { proxy } = new ProxySandbox('doc-symbol');
// just access
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const d1 = proxy.document;
expect(documentAttachProxyMap.get(d1)).toBe(proxy);
expect(getCurrentRunningSandboxProxy()).toBe(proxy);
setTimeout(() => {
expect(documentAttachProxyMap.get(d1)).toBeUndefined();
expect(getCurrentRunningSandboxProxy()).toBeNull();
done();
});
});

View File

@ -5,7 +5,14 @@
import { isBoundedFunction, isCallable, isConstructable } from '../utils';
export const documentAttachProxyMap = new WeakMap<HTMLDocument, WindowProxy>();
let currentRunningSandboxProxy: WindowProxy | null;
export function getCurrentRunningSandboxProxy() {
return currentRunningSandboxProxy;
}
export function setCurrentRunningSandboxProxy(proxy: WindowProxy | null) {
currentRunningSandboxProxy = proxy;
}
const functionBoundedValueMap = new WeakMap<Function, Function>();
export function getTargetValue(target: any, value: any): any {

View File

@ -4,7 +4,7 @@
*/
import { Freer } from '../../../interfaces';
import { documentAttachProxyMap } from '../../common';
import { getCurrentRunningSandboxProxy } from '../../common';
import {
ContainerConfig,
isHijackingTag,
@ -27,11 +27,9 @@ function patchDocumentCreateElement() {
): HTMLElement {
const element = rawDocumentCreateElement.call(this, tagName, options);
if (isHijackingTag(tagName)) {
// 这里使用document来获取比this更加健壮因为之前set的时候是传入的document
// 因为document不一定是原生的document这种情况出现在qiankun本身就在另一个沙箱下运行的情况而那个沙箱可能连document都重写了。
const attachProxy = documentAttachProxyMap.get(document);
if (attachProxy) {
const proxyContainerConfig = proxyAttachContainerConfigMap.get(attachProxy);
const currentRunningSandboxProxy = getCurrentRunningSandboxProxy();
if (currentRunningSandboxProxy) {
const proxyContainerConfig = proxyAttachContainerConfigMap.get(currentRunningSandboxProxy);
if (proxyContainerConfig) {
elementAttachContainerConfigMap.set(element, proxyContainerConfig);
}

View File

@ -5,7 +5,7 @@
*/
import { SandBox, SandBoxType } from '../interfaces';
import { nextTick } from '../utils';
import { documentAttachProxyMap, getTargetValue } from './common';
import { getTargetValue, setCurrentRunningSandboxProxy } from './common';
/**
* fastest(at most time) unique array method
@ -50,7 +50,6 @@ const unscopables = {
String: true,
Boolean: true,
Math: true,
eval: true,
Number: true,
Symbol: true,
parseFloat: true,
@ -223,13 +222,20 @@ export default class ProxySandbox implements SandBox {
}
// mark the symbol to document while accessing as document.createElement could know is invoked by which sandbox for dynamic append patcher
if (p === 'document') {
documentAttachProxyMap.set(document, proxy);
if (p === 'document' || p === 'eval') {
setCurrentRunningSandboxProxy(proxy);
// FIXME if you have any other good ideas
// remove the mark in next tick, thus we can identify whether it in micro app or not
// this approach is just a workaround, it could not cover all the complex scenarios, such as the micro app runs in the same task context with master in som case
// fixme if you have any other good ideas
nextTick(() => documentAttachProxyMap.delete(document));
return document;
// this approach is just a workaround, it could not cover all complex cases, such as the micro app runs in the same task context with master in some case
nextTick(() => setCurrentRunningSandboxProxy(null));
switch (p) {
case 'document':
return document;
case 'eval':
// eslint-disable-next-line no-eval
return eval;
// no default
}
}
// eslint-disable-next-line no-bitwise