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,