mirror of
https://github.com/usebruno/bruno.git
synced 2025-08-19 00:46:06 +02:00
feat: safe mode updates (#2813)
* feat: safe mode updates * feat: safe-mode updates
This commit is contained in:
@@ -8,77 +8,13 @@ const addLibraryShimsToContext = require('./shims/lib');
|
||||
|
||||
// execute `npm run build:isolated-vm:inbuilt-modules` if the below file doesn't exist
|
||||
const getBundledCode = require('../../bundle-browser-rollup');
|
||||
const addSleepShimToContext = require('./shims/sleep');
|
||||
|
||||
const toNumber = (value) => {
|
||||
const num = Number(value);
|
||||
return Number.isInteger(num) ? parseInt(value, 10) : parseFloat(value);
|
||||
};
|
||||
|
||||
class IsolatedVMStrict {
|
||||
constructor() {
|
||||
this.result = null;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.isolate = new ivm.Isolate();
|
||||
this.context = this.isolate.createContextSync();
|
||||
this.context.global.setSync('global', this.context.global.derefInto());
|
||||
this.context.evalSync(`
|
||||
let bru = {};
|
||||
let req = {};
|
||||
let res = {};
|
||||
`);
|
||||
this.context.global.setSync('setResult', (arg) => {
|
||||
this.result = arg;
|
||||
});
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.isolate.dispose();
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.context.evalSync(`
|
||||
bru = {};
|
||||
req = {};
|
||||
res = {};
|
||||
`);
|
||||
}
|
||||
|
||||
execute({ script: externalScript, context: externalContext, scriptType = 'script' }) {
|
||||
if (!isNaN(Number(externalScript))) {
|
||||
return toNumber(externalScript);
|
||||
}
|
||||
try {
|
||||
const { bru, req, res } = externalContext;
|
||||
|
||||
bru && addBruShimToContext(this.context, bru);
|
||||
req && addBrunoRequestShimToContext(this.context, req);
|
||||
res && addBrunoResponseShimToContext(this.context, res);
|
||||
|
||||
const templateLiteralText = `
|
||||
global.value = \`${externalScript}\`;
|
||||
setResult(global.value);
|
||||
`;
|
||||
|
||||
const jsExpressionText = `
|
||||
global.value = ${externalScript};
|
||||
setResult(global.value);
|
||||
`;
|
||||
|
||||
let scriptText = scriptType === 'template-literal' ? templateLiteralText : jsExpressionText;
|
||||
|
||||
const script = this.isolate.compileScriptSync(scriptText);
|
||||
script.runSync(this.context);
|
||||
this.reset();
|
||||
return this.result;
|
||||
} catch (error) {
|
||||
console.error('Error executing the script!', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const executeInIsolatedVMStrict = ({ script: externalScript, context: externalContext, scriptType = 'script' }) => {
|
||||
if (!isNaN(Number(externalScript))) {
|
||||
return Number(externalScript);
|
||||
@@ -126,106 +62,6 @@ const executeInIsolatedVMStrict = ({ script: externalScript, context: externalCo
|
||||
isolate.dispose();
|
||||
};
|
||||
|
||||
class IsolatedVMAsync {
|
||||
constructor() {
|
||||
this.result;
|
||||
this.initPromise = this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.isolate = new ivm.Isolate();
|
||||
this.context = this.isolate.createContextSync();
|
||||
this.context.global.setSync('global', this.context.global.derefInto());
|
||||
this.context.evalSync(`
|
||||
let bru = {};
|
||||
let req = {};
|
||||
let res = {};
|
||||
let console = {};
|
||||
global.requireObject = {};
|
||||
global.require = (module) => {
|
||||
return global.requireObject[module];
|
||||
}
|
||||
`);
|
||||
|
||||
try {
|
||||
this.bundledCode = getBundledCode?.toString() || '';
|
||||
await this.context.eval(`(${this.bundledCode})()`);
|
||||
} catch (err) {
|
||||
console.debug('Error bundling libraries', err);
|
||||
}
|
||||
|
||||
await addLibraryShimsToContext(this.context);
|
||||
|
||||
this.context.global.setSync('setResult', (arg) => {
|
||||
this.result = arg;
|
||||
});
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.isolate.dispose();
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.context.evalSync(`
|
||||
bru = {};
|
||||
req = {};
|
||||
res = {};
|
||||
console = {};
|
||||
`);
|
||||
}
|
||||
|
||||
async execute({ script: externalScript, context: externalContext, scriptType = 'script' }) {
|
||||
await this.initPromise;
|
||||
if (!isNaN(Number(externalScript))) {
|
||||
return toNumber(externalScript);
|
||||
}
|
||||
let result;
|
||||
try {
|
||||
const { bru, req, res, test, __brunoTestResults, console: consoleFn } = externalContext;
|
||||
|
||||
bru && addBruShimToContext(this.context, bru);
|
||||
req && addBrunoRequestShimToContext(this.context, req);
|
||||
res && addBrunoResponseShimToContext(this.context, res);
|
||||
consoleFn && addConsoleShimToContext(this.context, consoleFn);
|
||||
|
||||
test && __brunoTestResults && (await addTestShimToContext(this.context, __brunoTestResults));
|
||||
|
||||
const jsScriptText = `
|
||||
new Promise(async (resolve, reject) => {
|
||||
console?.debug && console.debug('isolated-vm:execution-start:');
|
||||
try {
|
||||
${externalScript}
|
||||
} catch (error) {
|
||||
console?.debug && console.debug('isolated-vm:execution-end:with-error', error?.message);
|
||||
}
|
||||
console?.debug && console.debug('isolated-vm:execution-end:');
|
||||
resolve();
|
||||
});
|
||||
`;
|
||||
const templateLiteralText = `
|
||||
global.value = \`${externalScript}\`;
|
||||
setResult(global.value);
|
||||
`;
|
||||
const jsExpressionText = `
|
||||
global.value = ${externalScript};
|
||||
setResult(global.value);
|
||||
`;
|
||||
let scriptText =
|
||||
scriptType === 'template-literal'
|
||||
? templateLiteralText
|
||||
: scriptType === 'expression'
|
||||
? jsExpressionText
|
||||
: jsScriptText;
|
||||
const script = await this.isolate.compileScript(scriptText);
|
||||
await script.run(this.context);
|
||||
this.reset();
|
||||
return this.result;
|
||||
} catch (error) {
|
||||
console.error('Error executing the script!', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const executeInIsolatedVMAsync = async ({
|
||||
script: externalScript,
|
||||
context: externalContext,
|
||||
@@ -247,11 +83,7 @@ const executeInIsolatedVMAsync = async ({
|
||||
let res = {};
|
||||
let console = {};
|
||||
global.requireObject = {};
|
||||
global.require = (module) => {
|
||||
return global.requireObject[module];
|
||||
}
|
||||
`);
|
||||
await addLibraryShimsToContext(this.context);
|
||||
|
||||
context.global.setSync('log', function (...args) {
|
||||
console.debug(...args);
|
||||
@@ -270,6 +102,7 @@ const executeInIsolatedVMAsync = async ({
|
||||
req && addBrunoRequestShimToContext(context, req);
|
||||
res && addBrunoResponseShimToContext(context, res);
|
||||
consoleFn && addConsoleShimToContext(context, consoleFn);
|
||||
addSleepShimToContext(context);
|
||||
|
||||
await context.eval(
|
||||
`
|
||||
@@ -279,6 +112,8 @@ const executeInIsolatedVMAsync = async ({
|
||||
`
|
||||
);
|
||||
|
||||
await addLibraryShimsToContext(context);
|
||||
|
||||
test && __brunoTestResults && (await addTestShimToContext(context, __brunoTestResults));
|
||||
|
||||
context.global.setSync('setResult', function (arg) {
|
||||
@@ -287,6 +122,8 @@ const executeInIsolatedVMAsync = async ({
|
||||
|
||||
const jsScriptText = `
|
||||
new Promise(async (resolve, reject) => {
|
||||
// modify the setTimeout function with the shim to work-around the callback-function clone issues
|
||||
setTimeout = global.setTimeout;
|
||||
console?.debug && console.debug('isolated-vm:execution-start:');
|
||||
try {
|
||||
${externalScript}
|
||||
|
@@ -22,7 +22,8 @@ const addAxiosShimToContext = async (context) => {
|
||||
let args = argStrings?.map((arg) => JSON.parse(arg));
|
||||
const res = await axios(...args)
|
||||
.then((response) => {
|
||||
return cleanJson(response?.data);
|
||||
const { status, headers, data } = response || {};
|
||||
return cleanJson({ status, headers, data });
|
||||
})
|
||||
.catch((err) => {
|
||||
return {
|
||||
@@ -37,7 +38,8 @@ const addAxiosShimToContext = async (context) => {
|
||||
const res = await axios
|
||||
.get(...args)
|
||||
.then((response) => {
|
||||
return cleanJson(response?.data);
|
||||
const { status, headers, data } = response || {};
|
||||
return cleanJson({ status, headers, data });
|
||||
})
|
||||
.catch((err) => {
|
||||
return {
|
||||
@@ -52,7 +54,8 @@ const addAxiosShimToContext = async (context) => {
|
||||
const res = await axios
|
||||
.post(...args)
|
||||
.then((response) => {
|
||||
return cleanJson(response?.data);
|
||||
const { status, headers, data } = response || {};
|
||||
return cleanJson({ status, headers, data });
|
||||
})
|
||||
.catch((err) => {
|
||||
return {
|
||||
@@ -67,7 +70,8 @@ const addAxiosShimToContext = async (context) => {
|
||||
const res = await axios
|
||||
.put(...args)
|
||||
.then((response) => {
|
||||
return cleanJson(response?.data);
|
||||
const { status, headers, data } = response || {};
|
||||
return cleanJson({ status, headers, data });
|
||||
})
|
||||
.catch((err) => {
|
||||
return {
|
||||
@@ -82,7 +86,8 @@ const addAxiosShimToContext = async (context) => {
|
||||
const res = await axios
|
||||
.delete(...args)
|
||||
.then((response) => {
|
||||
return cleanJson(response?.data);
|
||||
const { status, headers, data } = response || {};
|
||||
return cleanJson({ status, headers, data });
|
||||
})
|
||||
.catch((err) => {
|
||||
return {
|
||||
@@ -97,7 +102,8 @@ const addAxiosShimToContext = async (context) => {
|
||||
const res = await axios
|
||||
.patch(...args)
|
||||
.then((response) => {
|
||||
return cleanJson(response?.data);
|
||||
const { status, headers, data } = response || {};
|
||||
return cleanJson({ status, headers, data });
|
||||
})
|
||||
.catch((err) => {
|
||||
return {
|
||||
|
32
packages/bruno-js/src/sandbox/isolatedvm/shims/sleep.js
Normal file
32
packages/bruno-js/src/sandbox/isolatedvm/shims/sleep.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const ivm = require('isolated-vm');
|
||||
const addSleepShimToContext = (context, console) => {
|
||||
context.evalClosureSync(
|
||||
`
|
||||
global.sleep = (...args) => $0.applySyncPromise(undefined, args?.map(arg=>JSON.stringify(arg)));
|
||||
`,
|
||||
[
|
||||
async (...argStrings) => {
|
||||
await new Promise((resolve) => {
|
||||
const timer = Number(argStrings?.[0]);
|
||||
if (!Number.isInteger(timer) || timer < 0) {
|
||||
resolve();
|
||||
}
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, timer);
|
||||
});
|
||||
return new ivm.ExternalCopy('done').copyInto({ release: true });
|
||||
}
|
||||
],
|
||||
{ arguments: { reference: true } }
|
||||
);
|
||||
|
||||
context.evalSync(`
|
||||
global.setTimeout = async (fn, timer) => {
|
||||
await sleep(timer);
|
||||
await fn.apply();
|
||||
}
|
||||
`);
|
||||
};
|
||||
|
||||
module.exports = addSleepShimToContext;
|
Reference in New Issue
Block a user