修复bug;提高沙盒稳定性;优化沙盒性能
This commit is contained in:
parent
7a8a98424c
commit
03380d1d93
|
@ -1515,7 +1515,7 @@ export class Get {
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param {string} str
|
* @param {string} str
|
||||||
* @returns
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
pureFunctionStr(str) {
|
pureFunctionStr(str) {
|
||||||
str = str.trim();
|
str = str.trim();
|
||||||
|
@ -1551,7 +1551,13 @@ export class Get {
|
||||||
if (func._filter_args) {
|
if (func._filter_args) {
|
||||||
return "_noname_func:" + JSON.stringify(get.stringifiedResult(func._filter_args, 3));
|
return "_noname_func:" + JSON.stringify(get.stringifiedResult(func._filter_args, 3));
|
||||||
}
|
}
|
||||||
const str = func.toString();
|
const { Marshal, Sandbox } = security.importSandbox();
|
||||||
|
const domain = Marshal.getMarshalledDomain(func);
|
||||||
|
if (domain) {
|
||||||
|
const sandbox = Sandbox.from(domain);
|
||||||
|
if (sandbox && "client" in sandbox) throw new Error("不应该二次扩散远程代码");
|
||||||
|
}
|
||||||
|
const str = Marshal.decompileFunction(func);
|
||||||
// js内置的函数
|
// js内置的函数
|
||||||
if (/\{\s*\[native code\]\s*\}/.test(str)) return "_noname_func:function () {}";
|
if (/\{\s*\[native code\]\s*\}/.test(str)) return "_noname_func:function () {}";
|
||||||
return "_noname_func:" + get.pureFunctionStr(str);
|
return "_noname_func:" + get.pureFunctionStr(str);
|
||||||
|
@ -4960,10 +4966,10 @@ function freezeSlot(obj, key) {
|
||||||
Reflect.defineProperty(obj, key, descriptor);
|
Reflect.defineProperty(obj, key, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
freezeSlot(Get, "isFunctionBody");
|
freezeSlot(Get.prototype, "isFunctionBody");
|
||||||
freezeSlot(Get, "pureFunctionStr");
|
freezeSlot(Get.prototype, "pureFunctionStr");
|
||||||
freezeSlot(Get, "funcInfoOL");
|
freezeSlot(Get.prototype, "funcInfoOL");
|
||||||
freezeSlot(Get, "infoFuncOL");
|
freezeSlot(Get.prototype, "infoFuncOL");
|
||||||
|
|
||||||
export let get = new Get();
|
export let get = new Get();
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,8 +8,9 @@ import security from "../../util/security.js";
|
||||||
export class Client {
|
export class Client {
|
||||||
/**
|
/**
|
||||||
* @param {import('../index.js').NodeWS | InstanceType<typeof import('ws').WebSocket> | Client} ws
|
* @param {import('../index.js').NodeWS | InstanceType<typeof import('ws').WebSocket> | Client} ws
|
||||||
|
* @param {boolean} temp
|
||||||
*/
|
*/
|
||||||
constructor(ws, temp) {
|
constructor(ws, temp = false) {
|
||||||
if (ws instanceof Client) throw new Error("Client cannot copy.");
|
if (ws instanceof Client) throw new Error("Client cannot copy.");
|
||||||
this.ws = ws;
|
this.ws = ws;
|
||||||
/**
|
/**
|
||||||
|
@ -19,8 +20,21 @@ export class Client {
|
||||||
this.id = ws.wsid || get.id();
|
this.id = ws.wsid || get.id();
|
||||||
this.closed = false;
|
this.closed = false;
|
||||||
|
|
||||||
if (!temp)
|
if (!temp) {
|
||||||
this.sandbox = security.createSandbox();
|
this.sandbox = security.createSandbox();
|
||||||
|
if (this.sandbox) {
|
||||||
|
Reflect.defineProperty(this, "sandbox", {
|
||||||
|
value: this.sandbox,
|
||||||
|
writable: false,
|
||||||
|
configurable: false,
|
||||||
|
});
|
||||||
|
Reflect.defineProperty(this.sandbox, "client", {
|
||||||
|
value: this,
|
||||||
|
writable: false,
|
||||||
|
configurable: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
send() {
|
send() {
|
||||||
if (this.closed) return this;
|
if (this.closed) return this;
|
||||||
|
|
|
@ -164,8 +164,9 @@ export class Library {
|
||||||
* } }
|
* } }
|
||||||
*/
|
*/
|
||||||
node;
|
node;
|
||||||
|
// 谁写的值类型是string,这也太离谱了喵
|
||||||
/**
|
/**
|
||||||
* @type { { [key: string]: string } }
|
* @type { { [key: string]: Player } }
|
||||||
*/
|
*/
|
||||||
playerOL;
|
playerOL;
|
||||||
/**
|
/**
|
||||||
|
@ -9561,14 +9562,13 @@ export class Library {
|
||||||
if (!Array.isArray(message) || typeof lib.message.client[message[0]] !== "function") {
|
if (!Array.isArray(message) || typeof lib.message.client[message[0]] !== "function") {
|
||||||
throw "err";
|
throw "err";
|
||||||
}
|
}
|
||||||
if (!game.sandbox) game.sandbox = security.createSandbox();
|
if (game.sandbox) security.enterSandbox(game.sandbox);
|
||||||
security.enterSandbox(game.sandbox);
|
|
||||||
try {
|
try {
|
||||||
for (var i = 1; i < message.length; i++) {
|
for (var i = 1; i < message.length; i++) {
|
||||||
message[i] = get.parsedResult(message[i]);
|
message[i] = get.parsedResult(message[i]);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
security.exitSandbox();
|
if (game.sandbox) security.exitSandbox();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
@ -12011,7 +12011,9 @@ export class Library {
|
||||||
cardPile = {};
|
cardPile = {};
|
||||||
message = {
|
message = {
|
||||||
server: {
|
server: {
|
||||||
/** @this { any } */
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
init(version, config, banned_info) {
|
init(version, config, banned_info) {
|
||||||
if (lib.node.banned.includes(banned_info)) {
|
if (lib.node.banned.includes(banned_info)) {
|
||||||
this.send("denied", "banned");
|
this.send("denied", "banned");
|
||||||
|
@ -12030,9 +12032,14 @@ export class Library {
|
||||||
lib.node.clients.remove(this);
|
lib.node.clients.remove(this);
|
||||||
this.closed = true;
|
this.closed = true;
|
||||||
} else if (!_status.waitingForPlayer) {
|
} else if (!_status.waitingForPlayer) {
|
||||||
if (game.phaseNumber && lib.configOL.observe) {
|
if (!config.nickname) {
|
||||||
|
this.send("denied", "banned");
|
||||||
|
lib.node.clients.remove(this);
|
||||||
|
this.closed = true;
|
||||||
|
} else if (game.phaseNumber && lib.configOL.observe) {
|
||||||
lib.node.observing.push(this);
|
lib.node.observing.push(this);
|
||||||
this.send("reinit", lib.configOL, get.arenaState(), game.getState ? game.getState() : {}, game.ip, game.players[0].playerid, null, _status.cardtag);
|
this.send("reinit", lib.configOL, get.arenaState(), game.getState ? game.getState() : {}, game.ip, game.players[0].playerid, null, _status.cardtag);
|
||||||
|
game.broadcastAll(name => game.log("玩家 ", `#y${name}`, " 进入房间旁观"), config.nickname);
|
||||||
if (!ui.removeObserve) {
|
if (!ui.removeObserve) {
|
||||||
ui.removeObserve = ui.create.system(
|
ui.removeObserve = ui.create.system(
|
||||||
"移除旁观",
|
"移除旁观",
|
||||||
|
@ -12077,37 +12084,53 @@ export class Library {
|
||||||
this.send("init", this.id, lib.configOL, game.ip, window.isNonameServer, game.roomId);
|
this.send("init", this.id, lib.configOL, game.ip, window.isNonameServer, game.roomId);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** @this { any } */
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
inited() {
|
inited() {
|
||||||
this.inited = true;
|
this.inited = true;
|
||||||
if (_status.waitingForPlayer) {
|
if (_status.waitingForPlayer) {
|
||||||
game.updateWaiting();
|
game.updateWaiting();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** @this { any } */
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
reinited() {
|
reinited() {
|
||||||
this.inited = true;
|
this.inited = true;
|
||||||
},
|
},
|
||||||
result: function (result) {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
result(result) {
|
||||||
if (lib.node.observing.includes(this)) return;
|
if (lib.node.observing.includes(this)) return;
|
||||||
var player = lib.playerOL[this.id];
|
var player = lib.playerOL[this.id];
|
||||||
if (player) {
|
if (player) {
|
||||||
player.unwait(result);
|
player.unwait(result);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tempResult: function (result) {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
tempResult(result) {
|
||||||
if (lib.node.observing.includes(this)) return;
|
if (lib.node.observing.includes(this)) return;
|
||||||
var player = lib.playerOL[this.id];
|
var player = lib.playerOL[this.id];
|
||||||
if (player) {
|
if (player) {
|
||||||
player.tempUnwait(result);
|
player.tempUnwait(result);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
startGame: function () {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
startGame() {
|
||||||
if (this.id == game.onlinezhu) {
|
if (this.id == game.onlinezhu) {
|
||||||
game.resume();
|
game.resume();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeRoomConfig: function (config) {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
changeRoomConfig(config) {
|
||||||
if (this.id == game.onlinezhu) {
|
if (this.id == game.onlinezhu) {
|
||||||
game.broadcastAll(function (config) {
|
game.broadcastAll(function (config) {
|
||||||
for (var i in config) {
|
for (var i in config) {
|
||||||
|
@ -12134,7 +12157,10 @@ export class Library {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeNumConfig: function (num, index, bool) {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
changeNumConfig(num, index, bool) {
|
||||||
if (this.id == game.onlinezhu) {
|
if (this.id == game.onlinezhu) {
|
||||||
lib.configOL.number = num;
|
lib.configOL.number = num;
|
||||||
game.send("server", "config", lib.configOL);
|
game.send("server", "config", lib.configOL);
|
||||||
|
@ -12148,14 +12174,20 @@ export class Library {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
throwEmotion: function (target, emotion, rotate) {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
throwEmotion(target, emotion, rotate) {
|
||||||
if (lib.node.observing.includes(this)) return;
|
if (lib.node.observing.includes(this)) return;
|
||||||
var player = lib.playerOL[this.id];
|
var player = lib.playerOL[this.id];
|
||||||
if (player) {
|
if (player) {
|
||||||
player.throwEmotion(target, emotion, rotate);
|
player.throwEmotion(target, emotion, rotate);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emotion: function (id, pack, emotion) {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
emotion(id, pack, emotion) {
|
||||||
if (lib.node.observing.includes(this)) return;
|
if (lib.node.observing.includes(this)) return;
|
||||||
var that = this;
|
var that = this;
|
||||||
if (
|
if (
|
||||||
|
@ -12185,7 +12217,10 @@ export class Library {
|
||||||
}
|
}
|
||||||
if (player) player.emotion(pack, emotion);
|
if (player) player.emotion(pack, emotion);
|
||||||
},
|
},
|
||||||
chat: function (id, str) {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
chat(id, str) {
|
||||||
if (lib.node.observing.includes(this)) return;
|
if (lib.node.observing.includes(this)) return;
|
||||||
var that = this;
|
var that = this;
|
||||||
if (
|
if (
|
||||||
|
@ -12215,8 +12250,18 @@ export class Library {
|
||||||
}
|
}
|
||||||
if (player) player.chat(str);
|
if (player) player.chat(str);
|
||||||
},
|
},
|
||||||
giveup: function (player) {
|
/**
|
||||||
|
* ```plain
|
||||||
|
* 当客机向主机发送投降请求时的回调
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
* @param {Player} player
|
||||||
|
*/
|
||||||
|
giveup(player) {
|
||||||
if (lib.node.observing.includes(this) || !player || !player._giveUp) return;
|
if (lib.node.observing.includes(this) || !player || !player._giveUp) return;
|
||||||
|
var self = lib.playerOL[this.id];
|
||||||
|
if (self !== player) return; // 禁止让别人投降
|
||||||
_status.event.next.length = 0;
|
_status.event.next.length = 0;
|
||||||
game
|
game
|
||||||
.createEvent("giveup", false)
|
.createEvent("giveup", false)
|
||||||
|
@ -12227,7 +12272,10 @@ export class Library {
|
||||||
player.die("nosource").includeOut = true;
|
player.die("nosource").includeOut = true;
|
||||||
}).player = player;
|
}).player = player;
|
||||||
},
|
},
|
||||||
auto: function () {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
auto() {
|
||||||
if (lib.node.observing.includes(this)) return;
|
if (lib.node.observing.includes(this)) return;
|
||||||
var player = lib.playerOL[this.id];
|
var player = lib.playerOL[this.id];
|
||||||
if (player) {
|
if (player) {
|
||||||
|
@ -12238,7 +12286,10 @@ export class Library {
|
||||||
}, player);
|
}, player);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
unauto: function () {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
unauto() {
|
||||||
if (lib.node.observing.includes(this)) return;
|
if (lib.node.observing.includes(this)) return;
|
||||||
var player = lib.playerOL[this.id];
|
var player = lib.playerOL[this.id];
|
||||||
if (player) {
|
if (player) {
|
||||||
|
@ -12249,18 +12300,21 @@ export class Library {
|
||||||
}, player);
|
}, player);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
exec: function (func) {
|
exec(func) {
|
||||||
// if(typeof func=='function'){
|
// if(typeof func=='function'){
|
||||||
// var args=Array.from(arguments);
|
// var args=Array.from(arguments);
|
||||||
// args.shift();
|
// args.shift();
|
||||||
// func.apply(this,args);
|
// func.apply(this,args);
|
||||||
// }
|
// }
|
||||||
},
|
},
|
||||||
log: function () {
|
/**
|
||||||
|
* @this {import("./element/client.js").Client}
|
||||||
|
*/
|
||||||
|
log() {
|
||||||
var items = [];
|
var items = [];
|
||||||
try {
|
try {
|
||||||
for (var i = 0; i < arguments.length; i++) {
|
for (var i = 0; i < arguments.length; i++) {
|
||||||
items.push(security.eval(`return ${arguments[i]}`));
|
items.push(this.sandbox.exec(`return ${arguments[i]}`));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.send("log", ["err"]);
|
this.send("log", ["err"]);
|
||||||
|
|
|
@ -142,23 +142,21 @@ export class LibInit {
|
||||||
if (!Array.isArray(message) || typeof lib.message.server[message[0]] !== "function") {
|
if (!Array.isArray(message) || typeof lib.message.server[message[0]] !== "function") {
|
||||||
throw "err";
|
throw "err";
|
||||||
}
|
}
|
||||||
if (!client.sandbox) client.sandbox = security.createSandbox();
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
security.enterSandbox(client.sandbox);
|
if (client.sandbox) security.enterSandbox(client.sandbox);
|
||||||
try {
|
try {
|
||||||
for (var i = 1; i < message.length; i++) {
|
for (var i = 1; i < message.length; i++) {
|
||||||
message[i] = get.parsedResult(message[i]);
|
message[i] = get.parsedResult(message[i]);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
security.exitSandbox(client.sandbox);
|
if (client.sandbox) security.exitSandbox();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
console.log("invalid message: " + messagestr);
|
console.log("invalid message: " + messagestr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lib.message.server[message.shift()].apply(client, message);
|
|
||||||
});
|
});
|
||||||
ws.on("close", function () {
|
ws.on("close", function () {
|
||||||
client.close();
|
client.close();
|
||||||
|
@ -609,10 +607,10 @@ export class LibInit {
|
||||||
* @param {Function} func
|
* @param {Function} func
|
||||||
*/
|
*/
|
||||||
function Legacy(func) {
|
function Legacy(func) {
|
||||||
|
const { Marshal } = security.importSandbox();
|
||||||
//Remove all comments
|
//Remove all comments
|
||||||
//移除所有注释
|
//移除所有注释
|
||||||
let str = func
|
let str = Marshal.decompileFunction(func)
|
||||||
.toString()
|
|
||||||
.replace(/((?:(?:^[ \t]*)?(?:\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/(?:[ \t]*\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/)))?|\/\/(?:[^\\]|\\(?:\r?\n)?)*?(?:\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/))|(?=\r?\n))))+)|("(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|(?:\r?\n|[\s\S])[^/"'\\\s]*)/gm, "$2")
|
.replace(/((?:(?:^[ \t]*)?(?:\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/(?:[ \t]*\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/)))?|\/\/(?:[^\\]|\\(?:\r?\n)?)*?(?:\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/))|(?=\r?\n))))+)|("(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|(?:\r?\n|[\s\S])[^/"'\\\s]*)/gm, "$2")
|
||||||
.trim();
|
.trim();
|
||||||
//获取第一个 { 后的所有字符
|
//获取第一个 { 后的所有字符
|
||||||
|
|
|
@ -20,7 +20,6 @@ const SandboxSignal_GetMarshalledProxy = Symbol("GetMarshalledProxy");
|
||||||
const SandboxSignal_SetMarshalledProxy = Symbol("SetMarshalledProxy");
|
const SandboxSignal_SetMarshalledProxy = Symbol("SetMarshalledProxy");
|
||||||
const SandboxSignal_GetWindow = Symbol("GetWindow");
|
const SandboxSignal_GetWindow = Symbol("GetWindow");
|
||||||
const SandboxSignal_GetPromise = Symbol("GetPromise");
|
const SandboxSignal_GetPromise = Symbol("GetPromise");
|
||||||
const SandboxSignal_IsArray = Symbol("IsArray");
|
|
||||||
const SandboxSignal_EnterDomain = Symbol("EnterDomain");
|
const SandboxSignal_EnterDomain = Symbol("EnterDomain");
|
||||||
const SandboxSignal_ExitDomain = Symbol("ExitDomain");
|
const SandboxSignal_ExitDomain = Symbol("ExitDomain");
|
||||||
const SandboxSignal_ListDomain = Symbol("ListDomain");
|
const SandboxSignal_ListDomain = Symbol("ListDomain");
|
||||||
|
@ -31,6 +30,7 @@ const SandboxSignal_TrapDomain = Symbol("TrapDomain");
|
||||||
const SandboxSignal_DiapatchMonitor = Symbol("DiapatchMonitor");
|
const SandboxSignal_DiapatchMonitor = Symbol("DiapatchMonitor");
|
||||||
const SandboxSignal_ListMonitor = Symbol("ListMonitor");
|
const SandboxSignal_ListMonitor = Symbol("ListMonitor");
|
||||||
const SandboxSignal_ExposeInfo = Symbol("ExposeInfo");
|
const SandboxSignal_ExposeInfo = Symbol("ExposeInfo");
|
||||||
|
const SandboxSignal_TryFunctionRefs = Symbol("TryFunctionRefs");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ```plain
|
* ```plain
|
||||||
|
@ -52,17 +52,17 @@ function isPrimitive(obj) {
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class AccessAction {
|
class AccessAction {
|
||||||
// static CALL = 0; // apply
|
// static CALL = 0; // apply
|
||||||
// static NEW = 1; // construct
|
// static NEW = 1; // construct
|
||||||
// static READ = 2; // get
|
// static READ = 2; // get
|
||||||
// static WRITE = 3; // set
|
// static WRITE = 3; // set
|
||||||
// static DESCRIBE = 4; // getOwnPropertyDescriptor
|
// static DESCRIBE = 4; // getOwnPropertyDescriptor
|
||||||
// static DEFINE = 5; // defineProperty
|
// static DEFINE = 5; // defineProperty
|
||||||
// static TRACE = 6; // getPrototypeOf
|
// static TRACE = 6; // getPrototypeOf
|
||||||
// static META = 7; // setPrototypeOf
|
// static META = 7; // setPrototypeOf
|
||||||
// static SEAL = 8; // preventExtensions
|
// static SEAL = 8; // preventExtensions
|
||||||
// static EXISTS = 9; // has
|
// static EXISTS = 9; // has
|
||||||
// static LIST = 10; // ownKeys
|
// static LIST = 10; // ownKeys
|
||||||
// static DELETE = 11; // delete
|
// static DELETE = 11; // delete
|
||||||
|
|
||||||
/** ```Reflect.apply``` */
|
/** ```Reflect.apply``` */
|
||||||
|
@ -443,6 +443,36 @@ const MARSHALLED_LIST = Object.freeze([
|
||||||
"/cancelIdleCallback",
|
"/cancelIdleCallback",
|
||||||
"/queueMicrotask",
|
"/queueMicrotask",
|
||||||
"/MutationObserver",
|
"/MutationObserver",
|
||||||
|
// 根据狂神喵提供的问题
|
||||||
|
// 我们对console进行迁移
|
||||||
|
"/console/debug",
|
||||||
|
"/console/error",
|
||||||
|
"/console/info",
|
||||||
|
"/console/log",
|
||||||
|
"/console/warn",
|
||||||
|
"/console/dir",
|
||||||
|
"/console/dirxml",
|
||||||
|
"/console/table",
|
||||||
|
"/console/trace",
|
||||||
|
"/console/group",
|
||||||
|
"/console/groupCollapsed",
|
||||||
|
"/console/groupEnd",
|
||||||
|
"/console/clear",
|
||||||
|
"/console/count",
|
||||||
|
"/console/countReset",
|
||||||
|
"/console/assert",
|
||||||
|
"/console/profile",
|
||||||
|
"/console/profileEnd",
|
||||||
|
"/console/time",
|
||||||
|
"/console/timeLog",
|
||||||
|
"/console/timeEnd",
|
||||||
|
"/console/timeStamp",
|
||||||
|
"/console/context",
|
||||||
|
"/console/createTask",
|
||||||
|
"/console/memory",
|
||||||
|
// 另外补充这两个可能的函数哦
|
||||||
|
"/alert",
|
||||||
|
"/confirm",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -532,6 +562,8 @@ class Globals {
|
||||||
if (!Globals.#globals.has(domain)) {
|
if (!Globals.#globals.has(domain)) {
|
||||||
const window = domain[SandboxExposer](SandboxSignal_GetWindow);
|
const window = domain[SandboxExposer](SandboxSignal_GetWindow);
|
||||||
const globals = [new WeakMap(), {}];
|
const globals = [new WeakMap(), {}];
|
||||||
|
// @ts-ignore
|
||||||
|
Globals.#globals.set(domain, globals);
|
||||||
|
|
||||||
// 检查是否是顶级域
|
// 检查是否是顶级域
|
||||||
if (Globals.#topGlobals) {
|
if (Globals.#topGlobals) {
|
||||||
|
@ -572,9 +604,6 @@ class Globals {
|
||||||
globals[0].set(obj, key);
|
globals[0].set(obj, key);
|
||||||
globals[1][key] = obj;
|
globals[1][key] = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
Globals.#globals.set(domain, globals);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1057,6 +1086,8 @@ class DomainMonitors {
|
||||||
/** @type {WeakMap<Domain, DomainMonitors>} */
|
/** @type {WeakMap<Domain, DomainMonitors>} */
|
||||||
static #domainMonitors = new WeakMap();
|
static #domainMonitors = new WeakMap();
|
||||||
|
|
||||||
|
/** @type {WeakMap<Object, Set<Monitor>>} */
|
||||||
|
#targetMonitorsMap = new WeakMap();
|
||||||
/** @type {WeakMap<Domain, Object<number, Set<Monitor>>>} */
|
/** @type {WeakMap<Domain, Object<number, Set<Monitor>>>} */
|
||||||
#monitorsMap = new WeakMap();
|
#monitorsMap = new WeakMap();
|
||||||
|
|
||||||
|
@ -1075,9 +1106,25 @@ class DomainMonitors {
|
||||||
actions,
|
actions,
|
||||||
allowDomains,
|
allowDomains,
|
||||||
disallowDomains,
|
disallowDomains,
|
||||||
|
targets,
|
||||||
] = Monitor[SandboxExposer2]
|
] = Monitor[SandboxExposer2]
|
||||||
(SandboxSignal_ExposeInfo, monitor);
|
(SandboxSignal_ExposeInfo, monitor);
|
||||||
|
|
||||||
|
// 如果指定了目标,使用目标 Monitor 集合
|
||||||
|
// 以此对于特定对象的 Monitor 进行性能优化
|
||||||
|
if (targets) {
|
||||||
|
for (const target of targets) {
|
||||||
|
let monitors = thiz.#targetMonitorsMap.get(target);
|
||||||
|
|
||||||
|
if (!monitors)
|
||||||
|
thiz.#targetMonitorsMap.set(target, monitors = new Set());
|
||||||
|
|
||||||
|
monitors.add(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function addToActionMap(actionMap) {
|
function addToActionMap(actionMap) {
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
let monitorMap = actionMap[action];
|
let monitorMap = actionMap[action];
|
||||||
|
@ -1133,9 +1180,24 @@ class DomainMonitors {
|
||||||
actions,
|
actions,
|
||||||
allowDomains,
|
allowDomains,
|
||||||
disallowDomains,
|
disallowDomains,
|
||||||
|
targets,
|
||||||
] = Monitor[SandboxExposer2]
|
] = Monitor[SandboxExposer2]
|
||||||
(SandboxSignal_ExposeInfo, monitor);
|
(SandboxSignal_ExposeInfo, monitor);
|
||||||
|
|
||||||
|
// 对于指定了目标的 Monitor 特殊处理
|
||||||
|
if (targets) {
|
||||||
|
for (const target of targets) {
|
||||||
|
const monitors = thiz.#targetMonitorsMap.get(target);
|
||||||
|
|
||||||
|
if (!monitors)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
monitors.delete(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function removeFromActionMap(actionMap) {
|
function removeFromActionMap(actionMap) {
|
||||||
for (const action of actions) {
|
for (const action of actions) {
|
||||||
const monitorMap = actionMap[action];
|
const monitorMap = actionMap[action];
|
||||||
|
@ -1183,20 +1245,32 @@ class DomainMonitors {
|
||||||
* @param {Domain} sourceDomain
|
* @param {Domain} sourceDomain
|
||||||
* @param {Domain} targetDomain
|
* @param {Domain} targetDomain
|
||||||
* @param {number} action
|
* @param {number} action
|
||||||
* @returns {Set<Monitor>?}
|
* @param {Object} target
|
||||||
|
* @returns {Array<Monitor>?}
|
||||||
*/
|
*/
|
||||||
static #getMonitorsBy = function (sourceDomain, targetDomain, action) {
|
static #getMonitorsBy = function (sourceDomain, targetDomain, action, target) {
|
||||||
const instance = DomainMonitors.#domainMonitors.get(sourceDomain);
|
const instance = DomainMonitors.#domainMonitors.get(sourceDomain);
|
||||||
|
|
||||||
if (!instance)
|
if (!instance)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
const targetMap = instance.#targetMonitorsMap.get(target);
|
||||||
const actionMap = instance.#monitorsMap.get(targetDomain);
|
const actionMap = instance.#monitorsMap.get(targetDomain);
|
||||||
|
const actionMonitors = actionMap && actionMap[action];
|
||||||
|
|
||||||
if (!actionMap || !(action in actionMap))
|
let array = null;
|
||||||
return null;
|
|
||||||
|
|
||||||
return actionMap[action];
|
if (targetMap)
|
||||||
|
array = [...targetMap]; // 优先执行指定目标的 Monitor
|
||||||
|
|
||||||
|
if (actionMonitors) {
|
||||||
|
if (!array)
|
||||||
|
array = [...actionMonitors];
|
||||||
|
else
|
||||||
|
array.push(...actionMonitors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1222,9 +1296,14 @@ class DomainMonitors {
|
||||||
actions,
|
actions,
|
||||||
allowDomains,
|
allowDomains,
|
||||||
disallowDomains,
|
disallowDomains,
|
||||||
|
targets,
|
||||||
] = Monitor[SandboxExposer2]
|
] = Monitor[SandboxExposer2]
|
||||||
(SandboxSignal_ExposeInfo, monitor);
|
(SandboxSignal_ExposeInfo, monitor);
|
||||||
|
|
||||||
|
// 指定了目标的 Monitor 不参与新运行域处理
|
||||||
|
if (targets)
|
||||||
|
continue;
|
||||||
|
|
||||||
// 判断新增的 Domain 是否是 Monitor 监听的目标
|
// 判断新增的 Domain 是否是 Monitor 监听的目标
|
||||||
if (allowDomains
|
if (allowDomains
|
||||||
&& !allowDomains.has(domain))
|
&& !allowDomains.has(domain))
|
||||||
|
@ -1355,14 +1434,16 @@ class DomainMonitors {
|
||||||
Object.freeze(nameds);
|
Object.freeze(nameds);
|
||||||
|
|
||||||
// 获取可能的 Monitor 集合
|
// 获取可能的 Monitor 集合
|
||||||
const monitorMap = DomainMonitors.#getMonitorsBy(sourceDomain, targetDomain, action);
|
const monitorMap = DomainMonitors.#getMonitorsBy(
|
||||||
|
sourceDomain, targetDomain, action, args[0]);
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
preventDefault: false,
|
preventDefault: false,
|
||||||
stopPropagation: false,
|
stopPropagation: false,
|
||||||
returnValue: undefined,
|
returnValue: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!monitorMap || monitorMap.size == 0)
|
if (!monitorMap || !monitorMap.length)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
const access = {
|
const access = {
|
||||||
|
@ -1386,6 +1467,9 @@ class DomainMonitors {
|
||||||
setReturnValue(value) {
|
setReturnValue(value) {
|
||||||
result.returnValue = value;
|
result.returnValue = value;
|
||||||
},
|
},
|
||||||
|
throwDenied(message = null) {
|
||||||
|
throw new RangeError(message || "封送对象的源运行域禁止了此项操作");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 遍历并尝试分发监听事件
|
// 遍历并尝试分发监听事件
|
||||||
|
@ -1450,7 +1534,7 @@ class DomainMonitors {
|
||||||
* monitor.require("property", "value"); // 指定监听 value 属性
|
* monitor.require("property", "value"); // 指定监听 value 属性
|
||||||
* monitor.filter((access, nameds) => nameds.value >= 0); // 过滤掉大于等于 0 的修改
|
* monitor.filter((access, nameds) => nameds.value >= 0); // 过滤掉大于等于 0 的修改
|
||||||
* monitor.then((access, nameds, control) => {
|
* monitor.then((access, nameds, control) => {
|
||||||
* control.overrideParameter("value", 0); // 将要修改的新值改回 0
|
* control.overrideParameter("value", 0); // 将要修改的新值改回 0
|
||||||
* });
|
* });
|
||||||
* monitor.start(); // 启动Monitor
|
* monitor.start(); // 启动Monitor
|
||||||
* ```
|
* ```
|
||||||
|
@ -1595,37 +1679,41 @@ class Monitor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @typedef {"target" | "thisArg" | "arguments" | "newTarget" | "property" | "descriptor" | "receiver" | "prototype" | "value"} PropertyKey
|
* @typedef {"target" | "thisArg" | "arguments"
|
||||||
|
* | "newTarget" | "property" | "descriptor"
|
||||||
|
* | "receiver" | "prototype" | "value"
|
||||||
|
* } PropertyKey
|
||||||
*
|
*
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* domain: Domain,
|
* domain: Domain,
|
||||||
* action: number,
|
* action: number,
|
||||||
* }} Access
|
* }} Access
|
||||||
*
|
*
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* target: Object,
|
* target: Object,
|
||||||
* thisArg?: Object,
|
* thisArg?: Object,
|
||||||
* arguments?: Array<any>,
|
* arguments?: Array<any>,
|
||||||
* newTarget?: Function,
|
* newTarget?: Function,
|
||||||
* property?: string | symbol,
|
* property?: string | symbol,
|
||||||
* descriptor?: {
|
* descriptor?: {
|
||||||
* value?: any,
|
* value?: any,
|
||||||
* writable?: boolean,
|
* writable?: boolean,
|
||||||
* get?: () => any,
|
* get?: () => any,
|
||||||
* set?: (value: any) => void,
|
* set?: (value: any) => void,
|
||||||
* enumerable?: boolean,
|
* enumerable?: boolean,
|
||||||
* configurable?: boolean,
|
* configurable?: boolean,
|
||||||
* },
|
* },
|
||||||
* receiver?: Object,
|
* receiver?: Object,
|
||||||
* prototype?: Object,
|
* prototype?: Object,
|
||||||
* value?: any,
|
* value?: any,
|
||||||
* }} Nameds
|
* }} Nameds
|
||||||
*
|
*
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* preventDefault: () => void,
|
* preventDefault: () => void,
|
||||||
* stopPropagation: () => void,
|
* stopPropagation: () => void,
|
||||||
* overrideParameter: (name: PropertyKey, value: any) => void,
|
* overrideParameter: (name: PropertyKey, value: any) => void,
|
||||||
* setReturnValue: (value: any) => void,
|
* setReturnValue: (value: any) => void,
|
||||||
|
* throwDenied: (message?: string) => never,
|
||||||
* }} Control
|
* }} Control
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -1774,7 +1862,8 @@ class Monitor {
|
||||||
return [
|
return [
|
||||||
thiz.#actions,
|
thiz.#actions,
|
||||||
thiz.#allowDomains,
|
thiz.#allowDomains,
|
||||||
thiz.#disallowDomains
|
thiz.#disallowDomains,
|
||||||
|
thiz.#checkInfo["target"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1895,8 +1984,8 @@ class Marshal {
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @typedef {[
|
* @typedef {[
|
||||||
* Domain,
|
* Domain,
|
||||||
* Object,
|
* Object,
|
||||||
* ]} Reverted
|
* ]} Reverted
|
||||||
*
|
*
|
||||||
* @param {any} proxy
|
* @param {any} proxy
|
||||||
|
@ -2000,6 +2089,29 @@ class Marshal {
|
||||||
return domain;
|
return domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ```plain
|
||||||
|
* 对于封送或未封送的函数执行转字符串操作
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {Function} func
|
||||||
|
*/
|
||||||
|
static decompileFunction(func) {
|
||||||
|
if (typeof func !== "function")
|
||||||
|
throw new TypeError("无效的函数对象");
|
||||||
|
|
||||||
|
if (Marshal.#marshalledProxies.has(func))
|
||||||
|
[, func] = Marshal.#revertProxy(func);
|
||||||
|
|
||||||
|
const refs = Sandbox[SandboxExposer2]
|
||||||
|
(SandboxSignal_TryFunctionRefs, func);
|
||||||
|
|
||||||
|
if (refs)
|
||||||
|
return refs;
|
||||||
|
|
||||||
|
return Function.prototype.toString.call(func);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ```plain
|
* ```plain
|
||||||
* 陷入某个运行域并执行代码
|
* 陷入某个运行域并执行代码
|
||||||
|
@ -2073,6 +2185,41 @@ class Marshal {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* ```plain
|
||||||
|
* 根据目标对象的特征复制一个基本对象
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {Object} src
|
||||||
|
* @returns {any}
|
||||||
|
*/
|
||||||
|
static #clonePureObject = function (src) {
|
||||||
|
let cloned;
|
||||||
|
|
||||||
|
if (typeof src === "function") {
|
||||||
|
const descriptor = Reflect.getOwnPropertyDescriptor(src, "prototype");
|
||||||
|
if (descriptor
|
||||||
|
&& descriptor.value
|
||||||
|
&& !descriptor.enumerable
|
||||||
|
&& !descriptor.configurable
|
||||||
|
&& descriptor.value.constructor === src)
|
||||||
|
cloned = function () { };
|
||||||
|
else
|
||||||
|
cloned = () => { };
|
||||||
|
} else if (Array.isArray(src))
|
||||||
|
cloned = [];
|
||||||
|
else
|
||||||
|
cloned = {};
|
||||||
|
|
||||||
|
Reflect.setPrototypeOf(cloned, null);
|
||||||
|
cloned["target"] = src;
|
||||||
|
return cloned;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ```plain
|
||||||
|
* 封送核心函数
|
||||||
|
* ```
|
||||||
|
*
|
||||||
* @param {Object} obj
|
* @param {Object} obj
|
||||||
* @param {Domain} targetDomain
|
* @param {Domain} targetDomain
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
|
@ -2135,9 +2282,15 @@ class Marshal {
|
||||||
if (cached)
|
if (cached)
|
||||||
return cached;
|
return cached;
|
||||||
|
|
||||||
|
// 创建一个空白对象,防止JavaScript的一些奇怪错误
|
||||||
|
const pure = Marshal.#clonePureObject(target);
|
||||||
|
// 设置属性方便调试
|
||||||
|
pure.sourceDomain = sourceDomain;
|
||||||
|
pure.targetDomain = targetDomain;
|
||||||
|
|
||||||
// 创建封送代理
|
// 创建封送代理
|
||||||
const proxy = new Proxy(target, {
|
const proxy = new Proxy(pure, {
|
||||||
apply(target, thisArg, argArray) {
|
apply(_, thisArg, argArray) {
|
||||||
const defaultApply = () => {
|
const defaultApply = () => {
|
||||||
const marshalledThis = Marshal.#marshal(thisArg, sourceDomain);
|
const marshalledThis = Marshal.#marshal(thisArg, sourceDomain);
|
||||||
const marshalledArgs = Marshal.#marshalArray(argArray, sourceDomain);
|
const marshalledArgs = Marshal.#marshalArray(argArray, sourceDomain);
|
||||||
|
@ -2169,7 +2322,7 @@ class Marshal {
|
||||||
|
|
||||||
return defaultApply();
|
return defaultApply();
|
||||||
},
|
},
|
||||||
construct(target, argArray, newTarget) {
|
construct(_, argArray, newTarget) {
|
||||||
const marshalledArgs = Marshal.#marshalArray(argArray, sourceDomain);
|
const marshalledArgs = Marshal.#marshalArray(argArray, sourceDomain);
|
||||||
const marshalledNewTarget = Marshal.#marshal(newTarget, sourceDomain);
|
const marshalledNewTarget = Marshal.#marshal(newTarget, sourceDomain);
|
||||||
|
|
||||||
|
@ -2192,7 +2345,7 @@ class Marshal {
|
||||||
return Marshal.#marshal(result, targetDomain);
|
return Marshal.#marshal(result, targetDomain);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
defineProperty(target, property, attributes) {
|
defineProperty(_, property, attributes) {
|
||||||
const isSourceDomain = sourceDomain === Domain.current;
|
const isSourceDomain = sourceDomain === Domain.current;
|
||||||
|
|
||||||
if (!isSourceDomain) {
|
if (!isSourceDomain) {
|
||||||
|
@ -2247,7 +2400,7 @@ class Marshal {
|
||||||
? domainTrapAction()
|
? domainTrapAction()
|
||||||
: Marshal.#trapDomain(sourceDomain, domainTrapAction);
|
: Marshal.#trapDomain(sourceDomain, domainTrapAction);
|
||||||
},
|
},
|
||||||
deleteProperty(target, p) {
|
deleteProperty(_, p) {
|
||||||
return Marshal.#trapDomain(sourceDomain, () => {
|
return Marshal.#trapDomain(sourceDomain, () => {
|
||||||
const rule = ruleRef.rule;
|
const rule = ruleRef.rule;
|
||||||
|
|
||||||
|
@ -2265,7 +2418,7 @@ class Marshal {
|
||||||
return Reflect.deleteProperty(...args);
|
return Reflect.deleteProperty(...args);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
get(target, p, receiver) {
|
get(_, p, receiver) {
|
||||||
// 因为 get 的东西最多,所以对此追加注释
|
// 因为 get 的东西最多,所以对此追加注释
|
||||||
// 其他的拦截器都是与 get 类似
|
// 其他的拦截器都是与 get 类似
|
||||||
|
|
||||||
|
@ -2304,7 +2457,7 @@ class Marshal {
|
||||||
return Marshal.#marshal(result, targetDomain);
|
return Marshal.#marshal(result, targetDomain);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getOwnPropertyDescriptor(target, p) {
|
getOwnPropertyDescriptor(_, p) {
|
||||||
const isSourceDomain = Domain.current === sourceDomain;
|
const isSourceDomain = Domain.current === sourceDomain;
|
||||||
|
|
||||||
const domainTrapAction = () => {
|
const domainTrapAction = () => {
|
||||||
|
@ -2332,7 +2485,7 @@ class Marshal {
|
||||||
return Marshal.#marshalObject(descriptor, targetDomain);
|
return Marshal.#marshalObject(descriptor, targetDomain);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getPrototypeOf(target) {
|
getPrototypeOf(_) {
|
||||||
return Marshal.#trapDomain(sourceDomain, () => {
|
return Marshal.#trapDomain(sourceDomain, () => {
|
||||||
const rule = ruleRef.rule;
|
const rule = ruleRef.rule;
|
||||||
|
|
||||||
|
@ -2356,7 +2509,7 @@ class Marshal {
|
||||||
return marshalledResult;
|
return marshalledResult;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
has(target, p) {
|
has(_, p) {
|
||||||
const isSourceDomain = Domain.current === sourceDomain;
|
const isSourceDomain = Domain.current === sourceDomain;
|
||||||
const domainTrapAction = () => {
|
const domainTrapAction = () => {
|
||||||
const rule = ruleRef.rule;
|
const rule = ruleRef.rule;
|
||||||
|
@ -2380,10 +2533,10 @@ class Marshal {
|
||||||
|
|
||||||
return Marshal.#trapDomain(sourceDomain, domainTrapAction);
|
return Marshal.#trapDomain(sourceDomain, domainTrapAction);
|
||||||
},
|
},
|
||||||
isExtensible(target) {
|
isExtensible(_) {
|
||||||
return Reflect.isExtensible(target);
|
return Reflect.isExtensible(target);
|
||||||
},
|
},
|
||||||
ownKeys(target) {
|
ownKeys(_) {
|
||||||
return Marshal.#trapDomain(sourceDomain, () => {
|
return Marshal.#trapDomain(sourceDomain, () => {
|
||||||
const rule = ruleRef.rule;
|
const rule = ruleRef.rule;
|
||||||
|
|
||||||
|
@ -2410,7 +2563,7 @@ class Marshal {
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
preventExtensions(target) {
|
preventExtensions(_) {
|
||||||
return Marshal.#trapDomain(sourceDomain, () => {
|
return Marshal.#trapDomain(sourceDomain, () => {
|
||||||
const rule = ruleRef.rule;
|
const rule = ruleRef.rule;
|
||||||
|
|
||||||
|
@ -2428,7 +2581,7 @@ class Marshal {
|
||||||
return Reflect.preventExtensions(...args);
|
return Reflect.preventExtensions(...args);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
set(target, p, newValue, receiver) {
|
set(_, p, newValue, receiver) {
|
||||||
const marshalledNewValue = Marshal.#marshal(newValue, sourceDomain);
|
const marshalledNewValue = Marshal.#marshal(newValue, sourceDomain);
|
||||||
const marshalledReceiver = Marshal.#marshal(receiver, sourceDomain);
|
const marshalledReceiver = Marshal.#marshal(receiver, sourceDomain);
|
||||||
|
|
||||||
|
@ -2450,7 +2603,7 @@ class Marshal {
|
||||||
return Reflect.set(...args);
|
return Reflect.set(...args);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setPrototypeOf(target, v) {
|
setPrototypeOf(_, v) {
|
||||||
const marshalledV = Marshal.#marshal(v, sourceDomain);
|
const marshalledV = Marshal.#marshal(v, sourceDomain);
|
||||||
|
|
||||||
if (Marshal.#marshalledProxies.has(marshalledV))
|
if (Marshal.#marshalledProxies.has(marshalledV))
|
||||||
|
@ -2610,30 +2763,30 @@ class Domain {
|
||||||
|
|
||||||
// 实装这个要代理Object喵
|
// 实装这个要代理Object喵
|
||||||
// static #hasInstanceMarshalled = function (obj) {
|
// static #hasInstanceMarshalled = function (obj) {
|
||||||
// if (Marshal.isMarshalled(obj))
|
// if (Marshal.isMarshalled(obj))
|
||||||
// [, obj] = Marshal[SandboxExposer2]
|
// [, obj] = Marshal[SandboxExposer2]
|
||||||
// (SandboxSignal_UnpackProxy, obj);
|
// (SandboxSignal_UnpackProxy, obj);
|
||||||
|
|
||||||
// return Domain.#hasInstance.call(this, obj);
|
// return Domain.#hasInstance.call(this, obj);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 效率影响不确定,暂不实装
|
// 效率影响不确定,暂不实装
|
||||||
// static #marshalledThen = function (onfulfilled, onrejected) {
|
// static #marshalledThen = function (onfulfilled, onrejected) {
|
||||||
// if (Marshal.isMarshalled(this)) {
|
// if (Marshal.isMarshalled(this)) {
|
||||||
// const [domain, promise] = Marshal[SandboxExposer2]
|
// const [domain, promise] = Marshal[SandboxExposer2]
|
||||||
// (SandboxSignal_UnpackProxy, this);
|
// (SandboxSignal_UnpackProxy, this);
|
||||||
|
|
||||||
// const marshaller = value => {
|
// const marshaller = value => {
|
||||||
// return this(trapMarshal(domain, Domain.current, value));
|
// return this(trapMarshal(domain, Domain.current, value));
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// return trapMarshal(domain, Domain.current, promise.then(
|
// return trapMarshal(domain, Domain.current, promise.then(
|
||||||
// marshaller.bind(onfulfilled),
|
// marshaller.bind(onfulfilled),
|
||||||
// marshaller.bind(onrejected)
|
// marshaller.bind(onrejected)
|
||||||
// ));
|
// ));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// return [[DefaultThen]].call(this, onfulfilled, onrejected);
|
// return [[DefaultThen]].call(this, onfulfilled, onrejected);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2881,9 +3034,6 @@ class Domain {
|
||||||
return Domain.#exitDomain();
|
return Domain.#exitDomain();
|
||||||
case SandboxSignal_ListDomain:
|
case SandboxSignal_ListDomain:
|
||||||
return Domain.#listDomain();
|
return Domain.#listDomain();
|
||||||
case SandboxSignal_IsArray:
|
|
||||||
// @ts-ignore
|
|
||||||
return Domain.#isArray(...args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2925,6 +3075,8 @@ class Sandbox {
|
||||||
static #domainMap = new WeakMap();
|
static #domainMap = new WeakMap();
|
||||||
/** @type {Array} */
|
/** @type {Array} */
|
||||||
static #executingScope = [];
|
static #executingScope = [];
|
||||||
|
/** @type {WeakMap<Function, string>} */
|
||||||
|
static #functionRefCodes = new WeakMap();
|
||||||
|
|
||||||
/** @type {Object} */
|
/** @type {Object} */
|
||||||
#scope;
|
#scope;
|
||||||
|
@ -3015,10 +3167,10 @@ class Sandbox {
|
||||||
|
|
||||||
const code = argArray.slice(-1)[0];
|
const code = argArray.slice(-1)[0];
|
||||||
const params = argArray.slice(0, -1);
|
const params = argArray.slice(0, -1);
|
||||||
new target(code); // 防止注入
|
|
||||||
|
|
||||||
const compiled = Sandbox.#compileCore(thiz, code, null, params, true);
|
const compiled = Sandbox.#compileCore(thiz, code, null, params, true);
|
||||||
compiled[Symbol.toStringTag] = `function (${params.join(", ")}) {\n${code}\n}`;
|
Sandbox.#functionRefCodes.set(compiled,
|
||||||
|
`function (${params.join(", ")}) {\n${code}\n}`);
|
||||||
return compiled;
|
return compiled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3486,6 +3638,18 @@ class Sandbox {
|
||||||
|
|
||||||
return builtName;
|
return builtName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Symbol} signal
|
||||||
|
* @param {...any} args
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
static [SandboxExposer2](signal, ...args) {
|
||||||
|
switch (signal) {
|
||||||
|
case SandboxSignal_TryFunctionRefs:
|
||||||
|
return Sandbox.#functionRefCodes.get(args[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sealClass(clazz) {
|
function sealClass(clazz) {
|
||||||
|
|
|
@ -98,6 +98,8 @@ let ModAsyncGeneratorFunction;
|
||||||
function enterSandbox(box) {
|
function enterSandbox(box) {
|
||||||
if (!SANDBOX_ENABLED)
|
if (!SANDBOX_ENABLED)
|
||||||
return;
|
return;
|
||||||
|
if (!(box instanceof Sandbox))
|
||||||
|
throw new TypeError("无效的沙盒对象");
|
||||||
|
|
||||||
if (!Domain.isBelievable(Domain.topDomain))
|
if (!Domain.isBelievable(Domain.topDomain))
|
||||||
throw "无法在沙盒里面访问";
|
throw "无法在沙盒里面访问";
|
||||||
|
@ -117,7 +119,7 @@ function exitSandbox() {
|
||||||
if (!Domain.isBelievable(Domain.topDomain))
|
if (!Domain.isBelievable(Domain.topDomain))
|
||||||
throw "无法在沙盒里面访问";
|
throw "无法在沙盒里面访问";
|
||||||
if (!sandboxStack.length)
|
if (!sandboxStack.length)
|
||||||
return;
|
throw new ReferenceError("无法弹出更多的沙盒");
|
||||||
|
|
||||||
sandboxStack.pop();
|
sandboxStack.pop();
|
||||||
}
|
}
|
||||||
|
@ -422,6 +424,7 @@ async function initSecurity({
|
||||||
...ioFuncs.map(n => game[n]).filter(Boolean),
|
...ioFuncs.map(n => game[n]).filter(Boolean),
|
||||||
...Object.values(game.promises),
|
...Object.values(game.promises),
|
||||||
defaultEval,
|
defaultEval,
|
||||||
|
localStorage.setItem,
|
||||||
window.require,
|
window.require,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
window.define,
|
window.define,
|
||||||
|
@ -472,6 +475,8 @@ async function initSecurity({
|
||||||
writeRule.setGranted(AccessAction.DEFINE, false); // 禁止重定义属性
|
writeRule.setGranted(AccessAction.DEFINE, false); // 禁止重定义属性
|
||||||
// 禁止修改 game.promises 的函数
|
// 禁止修改 game.promises 的函数
|
||||||
Marshal.setRule(game.promises, writeRule);
|
Marshal.setRule(game.promises, writeRule);
|
||||||
|
// 禁止修改 localStorage
|
||||||
|
Marshal.setRule(localStorage, writeRule);
|
||||||
|
|
||||||
// 对于 game 当中访问特定函数我们通过 Monitor 进行拦截
|
// 对于 game 当中访问特定函数我们通过 Monitor 进行拦截
|
||||||
new Monitor()
|
new Monitor()
|
||||||
|
@ -481,29 +486,28 @@ async function initSecurity({
|
||||||
// 如果目标是 game 的 ioFuncs 包含的所有函数
|
// 如果目标是 game 的 ioFuncs 包含的所有函数
|
||||||
.require("target", game)
|
.require("target", game)
|
||||||
.require("property", ...ioFuncs)
|
.require("property", ...ioFuncs)
|
||||||
.require("property", "ws")
|
.require("property", "ws", "sandbox")
|
||||||
// 抛出异常
|
// 抛出异常
|
||||||
.then((access, nameds, control) => {
|
.then((access, nameds, control) => {
|
||||||
throw `禁止沙盒修改 \`game.${nameds.prototype}\` 属性`;
|
throw `有不信任的代码修改 \`game.${String(nameds.property)}\` 属性`;
|
||||||
})
|
})
|
||||||
// 让 Monitor 开始工作
|
// 让 Monitor 开始工作
|
||||||
.start(); // 差点忘记启动了喵
|
.start(); // 差点忘记启动了喵
|
||||||
|
|
||||||
// 现在 parsex 已经禁止传递字符串,这段 Monitor 不需要了
|
|
||||||
// 监听原型、toStringTag的更改
|
// 监听原型、toStringTag的更改
|
||||||
// const toStringTag = Symbol.toStringTag;
|
const toStringTag = Symbol.toStringTag;
|
||||||
// new Monitor()
|
new Monitor()
|
||||||
// .action(AccessAction.WRITE)
|
.action(AccessAction.WRITE)
|
||||||
// .action(AccessAction.DEFINE)
|
.action(AccessAction.DEFINE)
|
||||||
// .action(AccessAction.META)
|
.action(AccessAction.META)
|
||||||
// .require("property", toStringTag)
|
.require("property", toStringTag)
|
||||||
// .then((access, nameds, control) => {
|
.then((access, nameds, control) => {
|
||||||
// // 阻止原型、toStringTag的更改
|
// 阻止原型、toStringTag的更改
|
||||||
// control.preventDefault();
|
control.preventDefault();
|
||||||
// control.stopPropagation();
|
control.stopPropagation();
|
||||||
// control.setReturnValue(false);
|
control.setReturnValue(false);
|
||||||
// })
|
})
|
||||||
// .start();
|
.start();
|
||||||
|
|
||||||
if (SANDBOX_AUTOTEST) {
|
if (SANDBOX_AUTOTEST) {
|
||||||
// 一个测试循环喵
|
// 一个测试循环喵
|
||||||
|
@ -646,12 +650,12 @@ function getIsolatedsFrom(item) {
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @returns {{
|
* @returns {{
|
||||||
* AccessAction: typeof import("./sandbox.js").AccessAction,
|
* AccessAction: typeof import("./sandbox.js").AccessAction,
|
||||||
* Domain: typeof import("./sandbox.js").Domain,
|
* Domain: typeof import("./sandbox.js").Domain,
|
||||||
* Marshal: typeof import("./sandbox.js").Marshal,
|
* Marshal: typeof import("./sandbox.js").Marshal,
|
||||||
* Monitor: typeof import("./sandbox.js").Monitor,
|
* Monitor: typeof import("./sandbox.js").Monitor,
|
||||||
* Rule: typeof import("./sandbox.js").Rule,
|
* Rule: typeof import("./sandbox.js").Rule,
|
||||||
* Sandbox: typeof import("./sandbox.js").Sandbox,
|
* Sandbox: typeof import("./sandbox.js").Sandbox,
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
function importSandbox() {
|
function importSandbox() {
|
||||||
|
@ -885,11 +889,11 @@ function setupPolyfills(sandbox) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试暴露喵
|
// 测试暴露喵
|
||||||
// Reflect.defineProperty(window, "sandbox", {
|
Reflect.defineProperty(window, "sandbox", {
|
||||||
// get: () => defaultSandbox,
|
get: () => defaultSandbox,
|
||||||
// set: () => { },
|
set: () => { },
|
||||||
// configurable: true,
|
configurable: true,
|
||||||
// });
|
});
|
||||||
|
|
||||||
const exports = {
|
const exports = {
|
||||||
enterSandbox,
|
enterSandbox,
|
||||||
|
|
Loading…
Reference in New Issue