UNPKG

hakojs

Version:

A secure, embeddable JavaScript engine that runs untrusted code inside WebAssembly sandboxes with fine-grained permissions and resource limits

283 lines (280 loc) 10.4 kB
var __dispose = Symbol.dispose || /* @__PURE__ */ Symbol.for("Symbol.dispose"); var __asyncDispose = Symbol.dispose || /* @__PURE__ */ Symbol.for("Symbol.dispose"); var __using = (stack, value, async) => { if (value != null) { if (typeof value !== "object" && typeof value !== "function") throw TypeError('Object expected to be assigned to "using" declaration'); var dispose; if (async) dispose = value[__asyncDispose]; if (dispose === undefined) dispose = value[__dispose]; if (typeof dispose !== "function") throw TypeError("Object not disposable"); stack.push([async, dispose, value]); } else if (async) { stack.push([async]); } return value; }; var __callDispose = (stack, error, hasError) => { var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) { return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _; }, fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e), next = (it) => { while (it = stack.pop()) { try { var result = it[1] && it[1].call(it[2]); if (it[0]) return Promise.resolve(result).then(next, (e) => (fail(e), next())); } catch (e) { fail(e); } } if (hasError) throw error; }; return next(); }; // src/vm/value-factory.ts import { HakoError } from "../etc/errors"; import { detectCircularReferences } from "../etc/types"; import { VMValue } from "./value"; class ValueFactory { context; container; constructor(context, container) { this.context = context; this.container = container; } getContext() { return this.context; } fromNativeValue(value, options = {}) { if (value === undefined) { return this.createUndefined(); } if (value === null) { return this.createNull(); } if (typeof value === "boolean") { return this.createBoolean(value); } if (typeof value === "number") { return this.createNumber(value); } if (typeof value === "string") { return this.createString(value); } if (typeof value === "bigint") { return this.createBigInt(value); } if (typeof value === "symbol") { return this.createSymbol(value, options); } if (typeof value === "function") { return this.createFunction(value, options); } if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) { return this.createArrayBuffer(value); } if (Array.isArray(value)) { return this.createArray(value); } if (value instanceof Date) { return this.createDate(value); } if (value instanceof Error) { return this.createError(value); } if (typeof value === "object") { return this.createObject(value, options); } throw new Error("Unsupported value type"); } createError(value) { let __stack2 = []; try { const errorPtr = this.container.exports.HAKO_NewError(this.context.pointer); const message = __using(__stack2, this.createString(value.message), 0); const name = __using(__stack2, this.createString(value.name), 0); const stack = __using(__stack2, this.createString(value.stack || ""), 0); const extractCause = (err) => { if (err.cause !== undefined) { return err.cause; } const errWithOptions = err; return errWithOptions.options?.cause; }; const causeValue = extractCause(value); const cause = __using(__stack2, causeValue !== undefined ? this.fromNativeValue(causeValue) : null, 0); const messageKey = __using(__stack2, this.createString("message"), 0); this.container.exports.HAKO_SetProp(this.context.pointer, errorPtr, messageKey.getHandle(), message.getHandle()); const nameKey = __using(__stack2, this.createString("name"), 0); this.container.exports.HAKO_SetProp(this.context.pointer, errorPtr, nameKey.getHandle(), name.getHandle()); if (cause) { let __stack = []; try { const causeKey = __using(__stack, this.createString("cause"), 0); this.container.exports.HAKO_SetProp(this.context.pointer, errorPtr, causeKey.getHandle(), cause.getHandle()); } catch (_catch) { var _err = _catch, _hasErr = 1; } finally { __callDispose(__stack, _err, _hasErr); } } const stackKey = __using(__stack2, this.createString("stack"), 0); this.container.exports.HAKO_SetProp(this.context.pointer, errorPtr, stackKey.getHandle(), stack.getHandle()); return new VMValue(this.context, errorPtr, "owned"); } catch (_catch2) { var _err2 = _catch2, _hasErr2 = 1; } finally { __callDispose(__stack2, _err2, _hasErr2); } } createFunction(callback, options) { if (!options.name || typeof options.name !== "string") { throw new Error("Function name is required"); } const functionId = this.container.callbacks.newFunction(this.context.pointer, callback, options.name); return new VMValue(this.context, functionId, "owned"); } createUndefined() { return new VMValue(this.context, this.container.exports.HAKO_GetUndefined(), "borrowed"); } createNull() { return new VMValue(this.context, this.container.exports.HAKO_GetNull(), "borrowed"); } createBoolean(value) { if (value === true) { return new VMValue(this.context, this.container.exports.HAKO_GetTrue(), "borrowed"); } return new VMValue(this.context, this.container.exports.HAKO_GetFalse(), "borrowed"); } createNumber(value) { const numPtr = this.container.exports.HAKO_NewFloat64(this.context.pointer, value); return new VMValue(this.context, numPtr, "owned"); } createString(value) { const strPtr = this.container.memory.allocateString(this.context.pointer, value); const jsStrPtr = this.container.exports.HAKO_NewString(this.context.pointer, strPtr); this.container.memory.freeMemory(this.context.pointer, strPtr); return new VMValue(this.context, jsStrPtr, "owned"); } createBigInt(value) { if (!this.context.container.utils.getBuildInfo().hasBignum) { throw new HakoError("This build of Hako does not have BigInt enabled."); } const isNegative = value < 0n; const absValue = isNegative ? -value : value; const low = Number(absValue & 0xffffffffn); const high = Number(absValue >> 32n); let bigIntPtr; if (isNegative) { bigIntPtr = this.container.exports.HAKO_NewBigInt(this.context.pointer, low, high); } else { bigIntPtr = this.container.exports.HAKO_NewBigUInt(this.context.pointer, low, high); } const lastError = this.context.getLastError(bigIntPtr); if (lastError) { this.container.memory.freeValuePointer(this.context.pointer, bigIntPtr); throw lastError; } return new VMValue(this.context, bigIntPtr, "owned"); } createSymbol(value, options) { const isGlobal = options.isGlobal || false; return this.createString(value.description || "").consume((value2) => { const jsSymbolPtr = this.container.exports.HAKO_NewSymbol(this.context.pointer, value2.getHandle(), isGlobal ? 1 : 0); return new VMValue(this.context, jsSymbolPtr, "owned"); }); } createArray(value) { const arrayPtr = this.container.exports.HAKO_NewArray(this.context.pointer); const jsArray = new VMValue(this.context, arrayPtr, "owned"); for (let i = 0;i < value.length; i++) { let __stack = []; try { const item = __using(__stack, this.fromNativeValue(value[i]), 0); if (item) { jsArray.setProperty(i, item); } } catch (_catch) { var _err = _catch, _hasErr = 1; } finally { __callDispose(__stack, _err, _hasErr); } } return jsArray; } createDate(value) { const date = this.container.exports.HAKO_NewDate(this.context.pointer, value.getTime()); const error = this.context.getLastError(date); if (error) { this.container.memory.freeValuePointer(this.context.pointer, date); throw error; } return new VMValue(this.context, date, "owned"); } createArrayBuffer(value) { let buffer; if (value instanceof ArrayBuffer) { buffer = new Uint8Array(value); } else { buffer = new Uint8Array(value.buffer, value.byteOffset, value.byteLength); } const valuePtr = this.container.memory.newArrayBuffer(this.context.pointer, buffer); const lastError = this.context.getLastError(valuePtr); if (lastError) { this.container.memory.freeValuePointer(this.context.pointer, valuePtr); throw lastError; } return new VMValue(this.context, valuePtr, "owned"); } createObject(value, options) { let __stack2 = []; try { detectCircularReferences(value); const objPtr = options.proto && options.proto instanceof VMValue ? this.container.exports.HAKO_NewObjectProto(this.context.pointer, options.proto.getHandle()) : this.container.exports.HAKO_NewObject(this.context.pointer); const lastError = this.context.getLastError(objPtr); if (lastError) { this.container.memory.freeValuePointer(this.context.pointer, objPtr); throw lastError; } const jsObj = __using(__stack2, new VMValue(this.context, objPtr, "owned"), 0); for (const key in value) { if (Object.hasOwn(value, key)) { let __stack = []; try { const propValue = __using(__stack, this.fromNativeValue(value[key]), 0); if (propValue) { jsObj.setProperty(key, propValue); } } catch (_catch) { var _err = _catch, _hasErr = 1; } finally { __callDispose(__stack, _err, _hasErr); } } } return jsObj.dup(); } catch (_catch2) { var _err2 = _catch2, _hasErr2 = 1; } finally { __callDispose(__stack2, _err2, _hasErr2); } } getGlobalObject() { return new VMValue(this.context, this.container.exports.HAKO_GetGlobalObject(this.context.pointer), "owned"); } dispose() {} [Symbol.dispose]() { this.dispose(); } } export { ValueFactory }; //# debugId=16C559CC6349F8A664756E2164756E21 //# sourceMappingURL=value-factory.js.map