isolated-vm
This commit is contained in:
parent
999cdb81ea
commit
d9bc349b2c
3 changed files with 69 additions and 116 deletions
104
index.js
104
index.js
|
@ -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) => {
|
||||||
|
|
|
@ -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
80
vm.js
|
@ -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}`)
|
|
||||||
})
|
|
Loading…
Reference in a new issue