isolated-vm

This commit is contained in:
Chayapak 2023-09-15 16:59:58 +07:00
parent 999cdb81ea
commit d9bc349b2c
3 changed files with 69 additions and 116 deletions

104
index.js
View file

@ -1,57 +1,89 @@
const { Isolate } = require('isolated-vm')
const { Server } = require('socket.io') const { Server } = require('socket.io')
const { Worker } = require('worker_threads') const util = require('util')
const path = require('path') 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) const io = new Server(3069)
io.on('connection', (socket) => { 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 () { return (...args) => target[prop](...args)
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
} }
reset() socket.on('setFunctions', (jsonArray) => {
const parsed = JSON.parse(jsonArray)
socket.on('setFunctions', (_jsonArray) => { functions = {}
jsonArray = _jsonArray
worker.postMessage({ type: 'setFunctions', jsonArray }) for (const eachFuntion of parsed) {
functions[eachFuntion] = (...args) => {
socket.emit(BRIDGE_PREFIX + eachFuntion, ...args)
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) => { const isolate = new Isolate({ memoryLimit: 256 })
worker.postMessage({ type: 'runCode', code })
worker.on('message', ({ type, error, output }) => { let context
if (type !== 'codeOutput') return 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) => { process.on('uncaughtException', (e) => {

View file

@ -10,6 +10,7 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"isolated-vm": "^4.6.0",
"minecraft-protocol": "^1.43.1", "minecraft-protocol": "^1.43.1",
"moment": "^2.29.4", "moment": "^2.29.4",
"moment-timezone": "^0.5.43", "moment-timezone": "^0.5.43",

80
vm.js
View file

@ -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}`)
})