diff --git a/mode/connect.js b/mode/connect.js index 8977d7b24..22118d21a 100644 --- a/mode/connect.js +++ b/mode/connect.js @@ -2,6 +2,9 @@ game.import("mode", function (lib, game, ui, get, ai, _status) { return { name: "connect", + init() { + game.requireSandbox(); + }, start: function () { var directstartmode = lib.config.directstartmode; ui.create.menu(true); diff --git a/noname/library/index.js b/noname/library/index.js index 47c1b220e..ec3ca63fe 100644 --- a/noname/library/index.js +++ b/noname/library/index.js @@ -24,6 +24,7 @@ import * as Element from "./element/index.js"; import { updateURLs } from "./update-urls.js"; import { defaultHooks } from "./hooks/index.js"; import { freezeButExtensible } from "../util/index.js"; +import security from "../util/security.js"; export class Library { configprefix = "noname_0.9_"; @@ -6333,8 +6334,8 @@ export class Library { code = container.textarea.value; } try { - var character = null; - eval(code); + debugger; // NEED TO VIEW DATA + var { character } = security.exec2(code); if (!Array.isArray(character)) { throw "err"; } @@ -6421,8 +6422,8 @@ export class Library { code = container.textarea.value; } try { - var character = null; - eval(code); + debugger; // NEED TO VIEW DATA + var { character } = security.exec2(code); if (!Array.isArray(character)) { throw "err"; } @@ -6850,8 +6851,8 @@ export class Library { code = container.textarea.value; } try { - var character = null; - eval(code); + debugger; // NEED TO VIEW DATA + var { character } = security.exec2(code); if (!get.is.object(character)) { throw "err"; } @@ -7752,7 +7753,8 @@ export class Library { if (Array.isArray(context)) { try { const code = context.length == 1 ? context[0].string : context.reduceRight((pre, cur) => (pre.string || pre) + "." + cur.string); - obj = eval(code); + debugger; // NEED TO VIEW DATA + obj = security.eval(`return ${code};`); if (![null, undefined].includes(obj)) { const keys = Object.getOwnPropertyNames(obj) .concat(Object.getOwnPropertyNames(Object.getPrototypeOf(obj))) @@ -9560,8 +9562,14 @@ export class Library { if (!Array.isArray(message) || typeof lib.message.client[message[0]] !== "function") { throw "err"; } - for (var i = 1; i < message.length; i++) { - message[i] = get.parsedResult(message[i]); + if (!game.sandbox) game.sandbox = security.createSandbox(); + security.enterSandbox(game.sandbox); + try { + for (var i = 1; i < message.length; i++) { + message[i] = get.parsedResult(message[i]); + } + } finally { + security.exitSandbox(); } } catch (e) { console.log(e); @@ -9597,6 +9605,7 @@ export class Library { } game.online = false; game.ws = null; + game.sandbox = null; }, }, /** @@ -12251,8 +12260,9 @@ export class Library { log: function () { var items = []; try { + debugger; // NEED TO VIEW DATA for (var i = 0; i < arguments.length; i++) { - eval("items.push(" + arguments[i] + ")"); + items.push(security.eval(`return ${arguments[i]}`)); } } catch (e) { this.send("log", ["err"]); diff --git a/noname/library/init/index.js b/noname/library/init/index.js index 704ba8831..99774b251 100644 --- a/noname/library/init/index.js +++ b/noname/library/init/index.js @@ -11,6 +11,9 @@ import { GameEvent } from "../element/gameEvent.js"; import { GameEventPromise } from "../element/gameEventPromise.js"; import { rootURL } from "../../../noname.js"; +import security from "../../util/security.js"; +import { Domain, Marshal, Sandbox } from "../../util/sandbox.js"; + export class LibInit { /** * 部分函数的Promise版本 @@ -140,8 +143,16 @@ export class LibInit { if (!Array.isArray(message) || typeof lib.message.server[message[0]] !== "function") { throw "err"; } - for (var i = 1; i < message.length; i++) { - message[i] = get.parsedResult(message[i]); + if (!client.sandbox) client.sandbox = security.createSandbox(); + // @ts-ignore + security.enterSandbox(client.sandbox); + try { + for (var i = 1; i < message.length; i++) { + message[i] = get.parsedResult(message[i]); + } + } finally { + // @ts-ignore + security.exitSandbox(client.sandbox); } } catch (e) { console.log(e); @@ -283,7 +294,8 @@ export class LibInit { if (data.includes("sojson") || data.includes("jsjiami") || data.includes("var _0x")) alert(`检测到您安装了使用免费版sojson进行加密的扩展。请谨慎使用这些扩展,避免游戏数据遭到破坏。\n扩展文件:${pathToRead}`); } try { - window.eval(data); + debugger; // NEED TO VIEW DATA + security.eval(data); if (typeof onLoad == "function") onLoad(); } catch (error) { if (typeof onError == "function") onError(error); @@ -584,6 +596,33 @@ export class LibInit { * @returns */ parsex(item, scope) { + let ModFunction = Function; + let ModGeneratorFunction = GeneratorFunction; + // let ModAsyncFunction = AsyncFunction; + // let ModAsyncGeneratorFunction = AsyncGeneratorFunction; + + // 虽然现在 parsex 被控制到了沙盒, + // 但是因为默认沙盒还是可以额外操作东西, + // 故而对不同的运行域做了区分 + if (security.SANDBOX_ENABLED) { + const domain = Marshal.getMarshalledDomain(item) || Domain.caller; + + // 非顶级域调用情况下我们替换掉Function类型 + if (domain && domain !== Domain.topDomain) { + const sandbox = Sandbox.from(domain); + + if (!sandbox) + throw "意外的运行域: 运行域没有绑定沙盒"; + + [ + ModFunction, + ModGeneratorFunction, + // ModAsyncFunction, + // ModAsyncGeneratorFunction, + ] = security.getIsolateds(sandbox); + } + } + //by 诗笺、Tipx-L /** * @param {Function} func @@ -608,7 +647,7 @@ export class LibInit { debuggerCopy = debuggerCopy.slice(0, debuggerSkip + debuggerResult.index) + insertDebugger + debuggerCopy.slice(debuggerSkip + debuggerResult.index + debuggerResult[0].length, -1); //测试是否有错误 try { - new GeneratorFunction(debuggerCopy); + new ModGeneratorFunction(debuggerCopy); str = debuggerCopy + "}"; debuggerSkip += debuggerResult.index + insertDebugger.length; hasDebugger = true; @@ -635,7 +674,7 @@ export class LibInit { copy = copy.slice(0, skip + result.index) + insertStr + copy.slice(skip + result.index + result[0].length); //测试是否有错误 try { - new (hasDebugger ? GeneratorFunction : Function)(copy); + new (hasDebugger ? ModGeneratorFunction : ModFunction)(copy); str = copy; skip += result.index + insertStr.length; } catch (error) { @@ -647,11 +686,12 @@ export class LibInit { str = `if(event.step==${k}){event.finish();return;}` + str; } if (!scope) { - return new (hasDebugger ? GeneratorFunction : Function)("event", "step", "source", "player", "target", "targets", "card", "cards", "skill", "forced", "num", "trigger", "result", "_status", "lib", "game", "ui", "get", "ai", str); + return new (hasDebugger ? ModGeneratorFunction : ModFunction)("event", "step", "source", "player", "target", "targets", "card", "cards", "skill", "forced", "num", "trigger", "result", "_status", "lib", "game", "ui", "get", "ai", str); } else { - return scope(`function${hasDebugger ? "*" : ""} anonymous(event,step,source,player,target,targets, + new (hasDebugger ? ModGeneratorFunction : ModFunction)(str); // 防止注入喵 + return scope(`(function${hasDebugger ? "*" : ""}(event,step,source,player,target,targets, card,cards,skill,forced,num,trigger,result, - _status,lib,game,ui,get,ai){${str}}; anonymous;`); + _status,lib,game,ui,get,ai){${str}})`); } } switch (typeof item) { @@ -687,7 +727,8 @@ export class LibInit { }; } else { if (Symbol.iterator in item) return lib.init.parsex(Array.from(item)); - if (item.toString !== Object.prototype.toString) return lib.init.parsex(item.toString()); + // 根据狂神喵的建议,禁用parsex接受字符串喵 + // if (item.toString !== Object.prototype.toString) return lib.init.parsex(item.toString()); if ("render" in item) { // TODO: Object Render Parse throw new Error("NYI: Object Render Parse"); @@ -744,22 +785,24 @@ export class LibInit { content._gen = true; return content; } else if (item._parsed) return item; - // falls through - default: return Legacy(item); + default: + throw new TypeError("为确保安全禁止用parsex解析字符串"); } } eval(func) { if (typeof func == "function") { - return eval("(" + func.toString() + ")"); + debugger; // NEED TO VIEW DATA + return security.eval(`return (${func.toString()});`); } else if (typeof func == "object") { for (var i in func) { if (Object.prototype.hasOwnProperty.call(func, i)) { if (typeof func[i] == "function") { let checkObject = {}; checkObject[i] = func[i]; - return eval(`(function(){return ${get.stringify(checkObject)};})()`)[i]; + debugger; // NEED TO VIEW DATA + return security.eval(`return ${get.stringify(checkObject)};`)[i]; } else { func[i] = lib.init.eval(func[i]); } diff --git a/noname/ui/create/menu/pages/exetensionMenu.js b/noname/ui/create/menu/pages/exetensionMenu.js index d23b7b0a5..fd8ac2797 100644 --- a/noname/ui/create/menu/pages/exetensionMenu.js +++ b/noname/ui/create/menu/pages/exetensionMenu.js @@ -333,20 +333,17 @@ export const extensionMenu = function (connectMenu) { inputExtName.disabled = true; setTimeout(function () { var ext = {}; - var config = null, - help = null; - debugger; // NEED TO VIEW DATA for (var i in dash4.content) { try { if (i == "content" || i == "precontent") { - ({ config, help, return: ext[i] } = security.exec2(`return (${dash4.content[i]});`)); + ext[i] = security.exec2(`return (${dash4.content[i]});`).return; if (typeof ext[i] != "function") { throw "err"; } else { ext[i] = ext[i].toString(); } } else { - ({ config, help, return: ext[i] } = security.exec2(`${dash4.content[i]}; return (${i});`)); + ext[i] = security.exec2(dash4.content[i])[i]; if (ext[i] == null || typeof ext[i] != "object") { throw "err"; } else {