feat: safe mode updates (#2813)

* feat: safe mode updates
* feat: safe-mode updates
This commit is contained in:
lohit
2024-08-12 16:52:59 +05:30
committed by GitHub
parent 9955b8796e
commit bde2c57a23
3 changed files with 50 additions and 175 deletions

View File

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

View File

@@ -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 {

View 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;