Replace # for privates

This commit is contained in:
Adria Navarro 2024-02-08 13:44:07 +01:00
parent 72c122105f
commit 57952131ac
2 changed files with 53 additions and 51 deletions

View File

@ -15,44 +15,44 @@ class ExecutionTimeoutError extends Error {
}
class ModuleHandler {
#modules: {
private modules: {
import: string
moduleKey: string
module: ivm.Module
}[] = []
#generateRandomKey = () => `i${crypto.randomUUID().replace(/-/g, "")}`
private generateRandomKey = () => `i${crypto.randomUUID().replace(/-/g, "")}`
registerModule(module: ivm.Module, imports: string) {
this.#modules.push({
moduleKey: this.#generateRandomKey(),
this.modules.push({
moduleKey: this.generateRandomKey(),
import: imports,
module: module,
})
}
generateImports() {
return this.#modules
return this.modules
.map(m => `import ${m.import} from "${m.moduleKey}"`)
.join(";")
}
getModule(key: string) {
const module = this.#modules.find(m => m.moduleKey === key)
const module = this.modules.find(m => m.moduleKey === key)
return module?.module
}
}
export class IsolatedVM implements VM {
#isolate: ivm.Isolate
#vm: ivm.Context
#jail: ivm.Reference
#timeout: number
#perRequestLimit?: number
private isolate: ivm.Isolate
private vm: ivm.Context
private jail: ivm.Reference
private timeout: number
private perRequestLimit?: number
#moduleHandler = new ModuleHandler()
private moduleHandler = new ModuleHandler()
readonly #resultKey = "results"
private readonly resultKey = "results"
constructor({
memoryLimit,
@ -63,30 +63,30 @@ export class IsolatedVM implements VM {
timeout: number
perRequestLimit?: number
}) {
this.#isolate = new ivm.Isolate({ memoryLimit })
this.#vm = this.#isolate.createContextSync()
this.#jail = this.#vm.global
this.#jail.setSync("global", this.#jail.derefInto())
this.isolate = new ivm.Isolate({ memoryLimit })
this.vm = this.isolate.createContextSync()
this.jail = this.vm.global
this.jail.setSync("global", this.jail.derefInto())
this.#addToContext({
[this.#resultKey]: { out: "" },
this.addToContext({
[this.resultKey]: { out: "" },
})
this.#timeout = timeout
this.#perRequestLimit = perRequestLimit
this.timeout = timeout
this.perRequestLimit = perRequestLimit
}
withHelpers() {
const urlModule = this.#registerCallbacks({
const urlModule = this.registerCallbacks({
resolve: url.resolve,
parse: url.parse,
})
const querystringModule = this.#registerCallbacks({
const querystringModule = this.registerCallbacks({
escape: querystring.escape,
})
this.#addToContext({
this.addToContext({
helpersStripProtocol: new ivm.Callback((str: string) => {
var parsed = url.parse(str) as any
parsed.protocol = ""
@ -101,19 +101,19 @@ export class IsolatedVM implements VM {
}
}`
const helpersSource = loadBundle(BundleType.HELPERS)
const helpersModule = this.#isolate.compileModuleSync(
const helpersModule = this.isolate.compileModuleSync(
`${injectedRequire};${helpersSource}`
)
helpersModule.instantiateSync(this.#vm, specifier => {
helpersModule.instantiateSync(this.vm, specifier => {
if (specifier === "crypto") {
const cryptoModule = this.#registerCallbacks({
const cryptoModule = this.registerCallbacks({
randomUUID: crypto.randomUUID,
})
const module = this.#isolate.compileModuleSync(
const module = this.isolate.compileModuleSync(
`export default ${cryptoModule}`
)
module.instantiateSync(this.#vm, specifier => {
module.instantiateSync(this.vm, specifier => {
throw new Error(`No imports allowed. Required: ${specifier}`)
})
return module
@ -121,20 +121,21 @@ export class IsolatedVM implements VM {
throw new Error(`No imports allowed. Required: ${specifier}`)
})
this.#moduleHandler.registerModule(helpersModule, "helpers")
this.moduleHandler.registerModule(helpersModule, "helpers")
return this
}
withContext(context: Record<string, any>) {
this.#addToContext(context)
debugger
this.addToContext(context)
return this
}
execute(code: string): string {
const perRequestLimit = this.#perRequestLimit
const perRequestLimit = this.perRequestLimit
if (perRequestLimit) {
const cpuMs = Number(this.#isolate.cpuTime) / 1e6
const cpuMs = Number(this.isolate.cpuTime) / 1e6
if (cpuMs > perRequestLimit) {
throw new ExecutionTimeoutError(
`CPU time limit exceeded (${cpuMs}ms > ${perRequestLimit}ms)`
@ -142,12 +143,12 @@ export class IsolatedVM implements VM {
}
}
code = `${this.#moduleHandler.generateImports()};results.out=${code};`
code = `${this.moduleHandler.generateImports()};results.out=${code};`
const script = this.#isolate.compileModuleSync(code)
const script = this.isolate.compileModuleSync(code)
script.instantiateSync(this.#vm, specifier => {
const module = this.#moduleHandler.getModule(specifier)
script.instantiateSync(this.vm, specifier => {
const module = this.moduleHandler.getModule(specifier)
if (module) {
return module
}
@ -155,13 +156,13 @@ export class IsolatedVM implements VM {
throw new Error(`"${specifier}" import not allowed`)
})
script.evaluateSync({ timeout: this.#timeout })
script.evaluateSync({ timeout: this.timeout })
const result = this.#getResult()
const result = this.getResult()
return result
}
#registerCallbacks(functions: Record<string, any>) {
private registerCallbacks(functions: Record<string, any>) {
const libId = crypto.randomUUID().replace(/-/g, "")
const x: Record<string, string> = {}
@ -169,7 +170,7 @@ export class IsolatedVM implements VM {
const key = `f${libId}${funcName}cb`
x[funcName] = key
this.#addToContext({
this.addToContext({
[key]: new ivm.Callback((...params: any[]) => (func as any)(...params)),
})
}
@ -183,17 +184,18 @@ export class IsolatedVM implements VM {
return mod
}
#addToContext(context: Record<string, any>) {
private addToContext(context: Record<string, any>) {
for (let key in context) {
this.#jail.setSync(
this.jail.setSync(
key,
new ivm.ExternalCopy(context[key]).copyInto({ release: true })
context[key]
//new ivm.ExternalCopy(context[key]).copyInto({ release: true })
)
}
}
#getResult() {
const ref = this.#vm.global.getSync(this.#resultKey, { reference: true })
private getResult() {
const ref = this.vm.global.getSync(this.resultKey, { reference: true })
const result = ref.copySync()
ref.release()
return result.out

View File

@ -3,19 +3,19 @@ import { IsolatedVM } from "../jsRunner/vm"
const JS_TIMEOUT_MS = 1000
class ScriptRunner {
#code
#vm
private code
private vm
constructor(script: string, context: any) {
this.#code = `(() => {${script}})();`
this.#vm = new IsolatedVM({
this.code = `(() => {${script}})();`
this.vm = new IsolatedVM({
memoryLimit: env.JS_RUNNER_MEMORY_LIMIT,
timeout: JS_TIMEOUT_MS,
}).withContext(context)
}
execute() {
const result = this.#vm.execute(this.#code)
const result = this.vm.execute(this.code)
return result
}
}