From d9bc349b2cdcb6b99b9c4e6ce8a9e43715763f02 Mon Sep 17 00:00:00 2001 From: ChomeNS <95471003+ChomeNS@users.noreply.github.com> Date: Fri, 15 Sep 2023 16:59:58 +0700 Subject: [PATCH] isolated-vm --- index.js | 104 +++++++++++++++++++++++++++++++++------------------ package.json | 1 + vm.js | 80 --------------------------------------- 3 files changed, 69 insertions(+), 116 deletions(-) delete mode 100644 vm.js diff --git a/index.js b/index.js index 9ca5869..d265bff 100644 --- a/index.js +++ b/index.js @@ -1,57 +1,89 @@ +const { Isolate } = require('isolated-vm') const { Server } = require('socket.io') -const { Worker } = require('worker_threads') -const path = require('path') +const util = require('util') +const { stylize } = require('./colors') +const randomstring = require('randomstring') +const ChatMessage = require('prismarine-chat')('1.20.1') +const mc = require('minecraft-protocol') +const moment = require('moment-timezone') +const crypto = require('crypto') +const nbt = require('prismarine-nbt') + +const BRIDGE_PREFIX = 'function:' const io = new Server(3069) io.on('connection', (socket) => { - let worker + let functions - let isFirst = true + let proxy - let jsonArray + const handler = { + get (target, prop) { + if (!target[prop]) throw new Error(`Function "${prop}" not available`) - function reset () { - worker = new Worker(path.join(__dirname, 'vm.js')) - - worker.on('message', (msg) => { - switch (msg.type) { - case 'socketEmit': - socket.emit(...msg.data) - - break - case 'socketOnce': - socket.once(...msg.data) - - break - } - }) - - // ohio - if (!isFirst) { - worker.postMessage({ type: 'setFunctions', jsonArray }) - } else isFirst = false + return (...args) => target[prop](...args) + } } - reset() + socket.on('setFunctions', (jsonArray) => { + const parsed = JSON.parse(jsonArray) - socket.on('setFunctions', (_jsonArray) => { - jsonArray = _jsonArray + functions = {} + + for (const eachFuntion of parsed) { + functions[eachFuntion] = (...args) => { + socket.emit(BRIDGE_PREFIX + eachFuntion, ...args) - worker.postMessage({ type: 'setFunctions', jsonArray }) + return new Promise((resolve) => { + socket.once(`functionOutput:${eachFuntion}`, (message, parseJSON) => { + if (parseJSON) resolve(JSON.parse(message)) + else resolve(message) + }) + }) + } + } + + proxy = new Proxy(functions, handler) + + resetVM() }) - socket.on('runCode', (transactionId, code) => { - worker.postMessage({ type: 'runCode', code }) + const isolate = new Isolate({ memoryLimit: 256 }) - worker.on('message', ({ type, error, output }) => { - if (type !== 'codeOutput') return + let context + async function resetVM () { + context = await isolate.createContext() - socket.emit('codeOutput', transactionId, error, output) - }) + // TODO: fix + + // const global = context.global + + // await global.set('this', global.derefInto()) + // await global.set('global', global.derefInto()) + + // await global.set('bridge', () => { return proxy }) + // await global.set('randomstring', () => randomstring) + // await global.set('ChatMessage', () => ChatMessage) + // await global.set('mc', () => mc) + // await global.set('moment', () => moment) + // await global.set('crypto', () => crypto) + // await global.set('nbt', () => nbt) + } + + resetVM() + + socket.on('runCode', async (transactionId, code) => { + try { + const output = await context.eval(code, { timeout: 3000 }) + + socket.emit('codeOutput', transactionId, false, util.inspect(output, { stylize })) + } catch (e) { + socket.emit('codeOutput', transactionId, true, e.toString()) + } }) - socket.on('reset', reset) + socket.on('reset', resetVM) }) process.on('uncaughtException', (e) => { diff --git a/package.json b/package.json index 4c44da0..6308c03 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "author": "", "license": "ISC", "dependencies": { + "isolated-vm": "^4.6.0", "minecraft-protocol": "^1.43.1", "moment": "^2.29.4", "moment-timezone": "^0.5.43", diff --git a/vm.js b/vm.js deleted file mode 100644 index 31fdaf5..0000000 --- a/vm.js +++ /dev/null @@ -1,80 +0,0 @@ -const { parentPort } = require('worker_threads') -const { VM } = require('vm2') -const randomstring = require('randomstring') -const ChatMessage = require('prismarine-chat')('1.20.1') -const mc = require('minecraft-protocol') -const moment = require('moment-timezone') -const crypto = require('crypto') -const nbt = require('prismarine-nbt') -const util = require('util') -const { stylize } = require('./colors') - -const BRIDGE_PREFIX = 'function:' - -let proxy - -let vm - -const handler = { - get (target, prop) { - if (!target[prop]) throw new Error(`Function "${prop}" not available`) - - return (...args) => target[prop](...args) - } -} - -let functions - -parentPort.on('message', (msg) => { - switch (msg.type) { - case 'setFunctions': - const parsed = JSON.parse(msg.jsonArray) - - functions = {} - - for (const eachFuntion of parsed) { - functions[eachFuntion] = (...args) => { - parentPort.postMessage({ type: 'socketEmit', data: [BRIDGE_PREFIX + eachFuntion, ...args] }) - - // how do i make thjis work - // return new Promise((resolve) => { - // parentPort.postMessage({ type: 'socketOnce', data: [`functionOutput:${eachFuntion}`, (message, parseJSON) => { - // if (parseJSON) resolve(JSON.parse(message)) - // else resolve(message) - // }]}) - // }) - } - } - - proxy = new Proxy(functions, handler) - - vm = new VM({ - timeout: 500, - sandbox: { - get bridge () { return proxy }, - randomstring, - ChatMessage, - mc, - moment, - crypto, - nbt - } - }) - - break - case 'runCode': - try { - const output = vm.run(msg.code) - - parentPort.postMessage({ type: 'codeOutput', output: util.inspect(output, { stylize }), error: false }) - } catch (e) { - parentPort.postMessage({ type: 'codeOutput', output: e.toString(), error: true }) - } - - break - } -}) - -process.on('uncaughtException', (e) => { - console.log(`Caught an uncaught exception in the worker!\n${e.stack}`) -})