From 69aebf9d07d8fa5aff1f027e3ce5e4633ede54b6 Mon Sep 17 00:00:00 2001 From: IceCola <739201322@qq.com> Date: Wed, 29 May 2024 12:58:24 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=B3=A8=E9=87=8A=EF=BC=9B?= =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug=EF=BC=9B=E4=B8=BA=E6=97=81=E8=A7=82?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E6=B7=BB=E5=8A=A0=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- noname/get/index.js | 4 +-- noname/library/index.js | 4 ++- noname/library/init/index.js | 1 + noname/util/sandbox.js | 16 +++++++++--- noname/util/security.js | 49 +++++++++++++++++++++++++----------- 5 files changed, 53 insertions(+), 21 deletions(-) diff --git a/noname/get/index.js b/noname/get/index.js index c7ce0f832..cd8092f72 100644 --- a/noname/get/index.js +++ b/noname/get/index.js @@ -1566,9 +1566,9 @@ export class Get { } infoFuncOL(info) { let func; - console.log("[infoFuncOL] info:", info); + if ("sandbox" in window) console.log("[infoFuncOL] info:", info); const str = get.pureFunctionStr(info.slice(13)); // 清洗函数并阻止注入 - console.log("[infoFuncOL] pured:", str); + if ("sandbox" in window) console.log("[infoFuncOL] pured:", str); try { // js内置的函数 if (/\{\s*\[native code\]\s*\}/.test(str)) return function () { }; diff --git a/noname/library/index.js b/noname/library/index.js index 3b27266de..592d3d2e5 100644 --- a/noname/library/index.js +++ b/noname/library/index.js @@ -12039,7 +12039,9 @@ export class Library { } else if (game.phaseNumber && lib.configOL.observe) { 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); - game.broadcastAll(name => game.log("玩家 ", `#y${name}`, " 进入房间旁观"), config.nickname); + // 没有系统提示的接口喵? + game.log("玩家 ", `#y${config.nickname}`, " 进入房间观战"); + game.me.chat(`玩家 ${config.nickname} 进入房间观战`); if (!ui.removeObserve) { ui.removeObserve = ui.create.system( "移除旁观", diff --git a/noname/library/init/index.js b/noname/library/init/index.js index b5cfee990..af524c121 100644 --- a/noname/library/init/index.js +++ b/noname/library/init/index.js @@ -157,6 +157,7 @@ export class LibInit { console.log("invalid message: " + messagestr); return; } + lib.message.server[message.shift()].apply(client, message); }); ws.on("close", function () { client.close(); diff --git a/noname/util/sandbox.js b/noname/util/sandbox.js index 6962a78e3..e89a88d91 100644 --- a/noname/util/sandbox.js +++ b/noname/util/sandbox.js @@ -1,3 +1,11 @@ +// 给扩展开发者的的提示: +// 如果你在调试时启用了类似 `在出现异常时中断` 的选项, +// 如果你不想频繁进入此文件,那么你可以在调试窗口中 `右键-将此文件添加到忽略列表/black box script` 来屏蔽此文件 +// 另外由于封送的原因,如果当前模式启用了沙盒,会导致编译后的本地或远程代码创建的对象使用代理包装 +// 你在调试器中需要通过 `[[Target]].target` 查看原始对象,在此导致的不便对开发者表示歉意 + +// 最后为安全考虑,请遵守规范,尽量不要使用 `eval` 函数而是使用 `security.exec2` 来替代 + import { SANDBOX_EXPORT } from "./initRealms.js"; // 很重要的事情! @@ -410,9 +418,6 @@ const GLOBAL_PATHES = Object.freeze([ "/parseFloat", "/isNaN", "/isFinite", - "/alert", - "/confirm", - "/console", // 危险对象不传递 // "/Function", @@ -1595,6 +1600,7 @@ class Monitor { allow(...domains) { Monitor.#assertOperator(this); + // 参数检查 if (this.isStarted) throw new Error("Monitor 在启动期间不能修改"); if (!domains.length) @@ -1632,6 +1638,7 @@ class Monitor { disallow(...domains) { Monitor.#assertOperator(this); + // 参数检查 if (this.isStarted) throw new Error("Monitor 在启动期间不能修改"); if (!domains.length) @@ -1665,6 +1672,7 @@ class Monitor { action(...action) { Monitor.#assertOperator(this); + // 参数检查 if (this.isStarted) throw new Error("Monitor 在启动期间不能修改"); if (action.length == 0 @@ -3412,7 +3420,7 @@ class Sandbox { * @param {string} code 代码字符串 * @param {Object?} context 额外的执行上下文 * @param {Array?} paramList 参数名列表,以此来创建可以传递参数的函数 - * @param {boolean?} inheritScope 是否继承当前正在执行的scope而不是当前沙盒的scope + * @param {boolean?} inheritScope 是否继承当前正在执行的scope而不是当前沙盒的scope(为封装Function类型而提供的参数) * @param {"exists"|"extend"|"all"} writeContext 当执行的代码尝试为未声明的变量赋值时,应该 根据context与window的变量写入(默认行为)|默认行为并且新的变量写入context|全部写入context * @returns */ diff --git a/noname/util/security.js b/noname/util/security.js index f7c17c6fd..c2e713c38 100644 --- a/noname/util/security.js +++ b/noname/util/security.js @@ -1,10 +1,15 @@ +// 声明:沙盒维护的是服务器秩序,让服务器秩序不会因为非房主的玩家以及旁观者的影响,并在此基础上维护玩家设备不受危险代码攻击 +// 但沙盒不会也没有办法维护恶意服务器/房主对于游戏规则的破坏,请玩家尽量选择官方或其他安全的服务器,同时选择一个受信任的玩家作为房主 + // 是否强制所有模式下使用沙盒 -const SANDBOX_FORCED = true; +const SANDBOX_FORCED = false; // 是否启用自动测试 const SANDBOX_AUTOTEST = false; // 是否禁用自动测试延迟 // 这将放弃渲染,在游戏结束前无响应 const SANDBOX_AUTOTEST_NODELAY = false; +// 沙盒开发模式 +const SANDBOX_DEV = false; const WSURL_FOR_IP = /ws:\/\/(\d+.\d+.\d+.\d+):\d+\//; const TRUSTED_IPS = Object.freeze([ @@ -311,8 +316,20 @@ function _exec(x, scope = {}) { * 携带简单上下文的eval函数,并返回scope * eval代码的返回值将覆盖 `scope.return` 这个属性 * 另外任意因对未定义变量赋值导致全局变量赋值的行为将被转移到scope里面 + * (替代eval的对策函数,具体看下面的例子) * * 自动根据沙盒的启用状态使用不同的实现 + * + * 下面是 `security.exec2` 的使用示例: + * ``` + * @example + * ```javascript + * // 执行一段代码并获取赋值的多个变量 + * let { return: skill, filter, content } = security.exec2(` + * filter = (e, p) => e.source && e.source == p; + * content = async (e, t, p) => t.cancel(); + * return { filter, content }; + * `, { content: () => {}, lib, game, ui, get, ai, _status, }); // 提供默认的content,提供六个变量 * ``` * * @param {any} x @@ -511,13 +528,6 @@ async function initSecurity({ if (SANDBOX_AUTOTEST) { // 一个测试循环喵 - if (SANDBOX_AUTOTEST_NODELAY) { - game.resume = () => { }; - game.pause = () => { }; - } - game.delay = game.delayx = () => { }; - game.asyncDelay = game.asyncDelayx = async () => { }; - Reflect.defineProperty(lib.element.GameEvent.prototype, "animate", { get: () => undefined, set() { }, @@ -544,7 +554,16 @@ async function initSecurity({ }, SANDBOX_AUTOTEST_NODELAY ? 5000 : 1000); }; - lib.arenaReady.push(() => ui.click.auto()); + lib.arenaReady.push(() => setTimeout(() => { + if (SANDBOX_AUTOTEST_NODELAY) { + game.resume = () => { }; + game.pause = () => { }; + } + game.delay = game.delayx = () => { }; + game.asyncDelay = game.asyncDelayx = async () => { }; + + ui.auto.click(); + }, 1000)); } initialized = true; @@ -889,11 +908,13 @@ function setupPolyfills(sandbox) { } // 测试暴露喵 -Reflect.defineProperty(window, "sandbox", { - get: () => defaultSandbox, - set: () => { }, - configurable: true, -}); +if (SANDBOX_DEV) { + Reflect.defineProperty(window, "sandbox", { + get: () => defaultSandbox, + set: () => { }, + configurable: true, + }); +} const exports = { enterSandbox,