Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions example/tests/sandbox_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,15 @@
);
});

await test("TM半沙盒:把祖先类别继承直接写在半沙盒上 (Issue #1462 PR #1463)", async () => {
const trueWindow = unsafeWindow;
const sandboxWindow = window;
assertSame(false, Object.hasOwn(trueWindow, "addEventListener"), "unsafeWindow 继承 Object.hasOwn");
assertSame(true, Reflect.has(trueWindow, "addEventListener"), "unsafeWindow 继承 Reflect.has");
assertSame(true, Object.hasOwn(sandboxWindow, "addEventListener"), "window 属性 Object.hasOwn");
assertSame(true, Reflect.has(sandboxWindow, "addEventListener"), "window 属性 Reflect.has");
});

section("GM API 注入与命名空间");

await test("GM_info、GM.info 与 unsafeWindow 正确暴露", () => {
Expand Down
5 changes: 5 additions & 0 deletions src/app/service/content/create_context.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,9 @@ describe.concurrent("createProxyContext", () => {
sandbox.onload = null;
expect(removeEventListener).toHaveBeenCalledWith("load", eventObject);
});

it.concurrent("TM半沙盒:把祖先类别继承直接写在半沙盒上 ( #1462 #1463 )", () => {
const sandbox = createProxyContext(createTestContext([]));
expect(Object.hasOwn(sandbox, "addEventListener")).toBe(true);
});
});
16 changes: 16 additions & 0 deletions src/app/service/content/create_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ const overridedDescs: Record<string, PropertyDescriptor> = Object.create(null);
// 记录原生 onxxxxx 的 PropertyDescriptor
const eventDescs: Record<string, PropertyDescriptor> = Object.create(null);

// 在 USE_PSEUDO_WINDOW 情况下,由于没有 类的prototype, 父类的成员要手动传下去
const protoBaseDescs: Record<string, PropertyDescriptor> = Object.create(null);

// 包含物件本身及所有父类(不包含Object)的PropertyDescriptor
// 主要是找出哪些 function值, setter/getter 需要替换 global window
getAllPropertyDescriptors(global, ([key, desc]) => {
Expand All @@ -194,6 +197,18 @@ getAllPropertyDescriptors(global, ([key, desc]) => {
value: boundValue,
};
descsCache.add(key); // 必须:子类属性覆盖父类属性
} else if (!(key in initOwnDescs) && !Object.hasOwn(global, key)) {
if (!protoBaseDescs[key]) {
if (typeof value === "function") {
const boundValue = value.bind(global);
protoBaseDescs[key] = {
...desc,
value: boundValue,
};
} else {
protoBaseDescs[key] = { ...desc };
}
}
}
} else {
if (desc.configurable && desc.get && desc.set && desc.enumerable && key.startsWith("on")) {
Expand Down Expand Up @@ -248,6 +263,7 @@ Object.defineProperty(PseudoWindowPrototype, "__proto__", {

const sharedInitCopy = USE_PSEUDO_WINDOW
? Object.create(null, {
...protoBaseDescs, // 较快的 @unwrap 注入时有机会改变 EventTarget.prototype
...Object.getOwnPropertyDescriptors(PseudoWindowPrototype),
...initOwnDescs,
...overridedDescs,
Expand Down
Loading