mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-24 00:43:46 +01:00
Feat/safe mode quickjs (#2825)
* feat: testing quickjs sanbox * feat: testing quickjs sanbox * feat: testing quickjs sanbox
This commit is contained in:
parent
bde2c57a23
commit
a18e5e5b94
@ -57,6 +57,9 @@ npm run build:graphql-docs
|
|||||||
npm run build:bruno-query
|
npm run build:bruno-query
|
||||||
npm run build:bruno-common
|
npm run build:bruno-common
|
||||||
|
|
||||||
|
# bundle js sandbox libraries
|
||||||
|
npm run sandbox:bundle-libraries --workspace=packages/bruno-js
|
||||||
|
|
||||||
# run next app (terminal 1)
|
# run next app (terminal 1)
|
||||||
npm run dev:web
|
npm run dev:web
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ const runSingleRequest = async function (
|
|||||||
// todo: allow to override from cli args
|
// todo: allow to override from cli args
|
||||||
// we will default to vm2 (developer-mode) for 1.x version for backward compatibility
|
// we will default to vm2 (developer-mode) for 1.x version for backward compatibility
|
||||||
// 2.x will default to isolated-vm (safe mode)
|
// 2.x will default to isolated-vm (safe mode)
|
||||||
scriptingConfig.runtime = 'vm2';
|
scriptingConfig.runtime = 'isolated-vm';
|
||||||
|
|
||||||
// make axios work in node using form data
|
// make axios work in node using form data
|
||||||
// reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427
|
// reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427
|
||||||
|
@ -83,7 +83,7 @@ const getEnvVars = (environment = {}) => {
|
|||||||
|
|
||||||
const getJsSandboxRuntime = (collection) => {
|
const getJsSandboxRuntime = (collection) => {
|
||||||
const securityConfig = get(collection, 'securityConfig', {});
|
const securityConfig = get(collection, 'securityConfig', {});
|
||||||
return securityConfig.jsSandboxMode === 'safe' ? 'isolated-vm' : 'vm2';
|
return securityConfig.jsSandboxMode === 'safe' ? 'quickjs' : 'vm2';
|
||||||
};
|
};
|
||||||
|
|
||||||
const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/;
|
const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/;
|
||||||
|
2
packages/bruno-js/.gitignore
vendored
2
packages/bruno-js/.gitignore
vendored
@ -1 +1 @@
|
|||||||
src/bundle-browser-rollup.js
|
src/sandbox/bundle-browser-rollup.js
|
@ -12,12 +12,10 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jest --testPathIgnorePatterns test.js",
|
"test": "jest --testPathIgnorePatterns test.js",
|
||||||
"rebuild:electron": "cd ./node_modules/isolated-vm && npx electron-rebuild",
|
"sandbox:bundle-libraries": "node ./src/sandbox/bundle-libraries.js",
|
||||||
"postinstall": "npm run isolated-vm:install && npm run isolated-vm:prebuild:dev && npm run isolated-vm:bundle-libraries",
|
|
||||||
"isolated-vm:install": "cd ./node_modules/isolated-vm && npm install",
|
"isolated-vm:install": "cd ./node_modules/isolated-vm && npm install",
|
||||||
"isolated-vm:prebuild:dev": "node ./scripts/prebuild-isolated-vm-for-dev.js",
|
"isolated-vm:prebuild:dev": "node ./scripts/prebuild-isolated-vm-for-dev.js",
|
||||||
"isolated-vm:prebuild:prod": "node ./scripts/prebuild-isolated-vm-for-prod-builds.js",
|
"isolated-vm:prebuild:prod": "node ./scripts/prebuild-isolated-vm-for-prod-builds.js"
|
||||||
"isolated-vm:bundle-libraries": "node ./src/sandbox/isolatedvm/utils/bundle-libraries.js"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@usebruno/common": "0.1.0",
|
"@usebruno/common": "0.1.0",
|
||||||
@ -37,6 +35,7 @@
|
|||||||
"nanoid": "3.3.4",
|
"nanoid": "3.3.4",
|
||||||
"node-fetch": "2.*",
|
"node-fetch": "2.*",
|
||||||
"node-vault": "^0.10.2",
|
"node-vault": "^0.10.2",
|
||||||
|
"quickjs-emscripten": "^0.29.2",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -31,6 +31,7 @@ const fetch = require('node-fetch');
|
|||||||
const CryptoJS = require('crypto-js');
|
const CryptoJS = require('crypto-js');
|
||||||
const NodeVault = require('node-vault');
|
const NodeVault = require('node-vault');
|
||||||
const { executeInIsolatedVMAsync } = require('../sandbox/isolatedvm');
|
const { executeInIsolatedVMAsync } = require('../sandbox/isolatedvm');
|
||||||
|
const { executeQuickJsVmAsync } = require('../sandbox/quickjs');
|
||||||
|
|
||||||
class TestRuntime {
|
class TestRuntime {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -108,61 +109,58 @@ class TestRuntime {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mode == 'safe') {
|
if (this.runtime === 'isolated-vm') {
|
||||||
await executeInIsolatedVMAsync({
|
await executeInIsolatedVMAsync({
|
||||||
script: testsFile,
|
script: testsFile,
|
||||||
context: context,
|
context: context,
|
||||||
modules: {},
|
modules: {},
|
||||||
scriptType: 'jsScript'
|
scriptType: 'jsScript'
|
||||||
});
|
});
|
||||||
|
} else if(this.runtime === 'quickjs') {
|
||||||
return {
|
await executeQuickJsVmAsync({
|
||||||
request,
|
script: testsFile,
|
||||||
envVariables: cleanJson(envVariables),
|
context: context
|
||||||
runtimeVariables: cleanJson(runtimeVariables),
|
});
|
||||||
results: cleanJson(__brunoTestResults.getResults()),
|
} else {
|
||||||
nextRequestName: bru.nextRequest
|
// default runtime is vm2
|
||||||
};
|
const vm = new NodeVM({
|
||||||
}
|
sandbox: context,
|
||||||
|
require: {
|
||||||
// default runtime is vm2
|
context: 'sandbox',
|
||||||
const vm = new NodeVM({
|
external: true,
|
||||||
sandbox: context,
|
root: [collectionPath, ...additionalContextRootsAbsolute],
|
||||||
require: {
|
mock: {
|
||||||
context: 'sandbox',
|
// node libs
|
||||||
external: true,
|
path,
|
||||||
root: [collectionPath, ...additionalContextRootsAbsolute],
|
stream,
|
||||||
mock: {
|
util,
|
||||||
// node libs
|
url,
|
||||||
path,
|
http,
|
||||||
stream,
|
https,
|
||||||
util,
|
punycode,
|
||||||
url,
|
zlib,
|
||||||
http,
|
// 3rd party libs
|
||||||
https,
|
ajv,
|
||||||
punycode,
|
'ajv-formats': addFormats,
|
||||||
zlib,
|
btoa,
|
||||||
// 3rd party libs
|
atob,
|
||||||
ajv,
|
lodash,
|
||||||
'ajv-formats': addFormats,
|
moment,
|
||||||
btoa,
|
uuid,
|
||||||
atob,
|
nanoid,
|
||||||
lodash,
|
axios,
|
||||||
moment,
|
chai,
|
||||||
uuid,
|
'node-fetch': fetch,
|
||||||
nanoid,
|
'crypto-js': CryptoJS,
|
||||||
axios,
|
...whitelistedModules,
|
||||||
chai,
|
fs: allowScriptFilesystemAccess ? fs : undefined,
|
||||||
'node-fetch': fetch,
|
'node-vault': NodeVault
|
||||||
'crypto-js': CryptoJS,
|
}
|
||||||
...whitelistedModules,
|
|
||||||
fs: allowScriptFilesystemAccess ? fs : undefined,
|
|
||||||
'node-vault': NodeVault
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
const asyncVM = vm.run(`module.exports = async () => { ${testsFile}}`, path.join(collectionPath, 'vm.js'));
|
||||||
const asyncVM = vm.run(`module.exports = async () => { ${testsFile}}`, path.join(collectionPath, 'vm.js'));
|
await asyncVM();
|
||||||
await asyncVM();
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
request,
|
request,
|
||||||
|
@ -11,13 +11,13 @@ const bundleLibraries = async () => {
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import btoa from "btoa";
|
import btoa from "btoa";
|
||||||
import atob from "atob";
|
import atob from "atob";
|
||||||
global.expect = expect;
|
globalThis.expect = expect;
|
||||||
global.assert = assert;
|
globalThis.assert = assert;
|
||||||
global.moment = moment;
|
globalThis.moment = moment;
|
||||||
global.btoa = btoa;
|
globalThis.btoa = btoa;
|
||||||
global.atob = atob;
|
globalThis.atob = atob;
|
||||||
global.Buffer = Buffer;
|
globalThis.Buffer = Buffer;
|
||||||
global.requireObject = {
|
globalThis.requireObject = {
|
||||||
'chai': { expect, assert },
|
'chai': { expect, assert },
|
||||||
'moment': moment,
|
'moment': moment,
|
||||||
'buffer': { Buffer },
|
'buffer': { Buffer },
|
||||||
@ -54,7 +54,7 @@ const bundleLibraries = async () => {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
file: './src/bundle-browser-rollup.js',
|
file: './src/sandbox/bundle-browser-rollup.js',
|
||||||
format: 'iife',
|
format: 'iife',
|
||||||
name: 'MyBundle'
|
name: 'MyBundle'
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ const bundleLibraries = async () => {
|
|||||||
const bundle = await rollup.rollup(config.input);
|
const bundle = await rollup.rollup(config.input);
|
||||||
const { output } = await bundle.generate(config.output);
|
const { output } = await bundle.generate(config.output);
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
'./src/bundle-browser-rollup.js',
|
'./src/sandbox/bundle-browser-rollup.js',
|
||||||
`
|
`
|
||||||
const getBundledCode = () => {
|
const getBundledCode = () => {
|
||||||
return function(){
|
return function(){
|
@ -7,7 +7,7 @@ const addTestShimToContext = require('./shims/test');
|
|||||||
const addLibraryShimsToContext = require('./shims/lib');
|
const addLibraryShimsToContext = require('./shims/lib');
|
||||||
|
|
||||||
// execute `npm run build:isolated-vm:inbuilt-modules` if the below file doesn't exist
|
// execute `npm run build:isolated-vm:inbuilt-modules` if the below file doesn't exist
|
||||||
const getBundledCode = require('../../bundle-browser-rollup');
|
const getBundledCode = require('../bundle-browser-rollup');
|
||||||
const addSleepShimToContext = require('./shims/sleep');
|
const addSleepShimToContext = require('./shims/sleep');
|
||||||
|
|
||||||
const toNumber = (value) => {
|
const toNumber = (value) => {
|
||||||
|
203
packages/bruno-js/src/sandbox/quickjs/index.js
Normal file
203
packages/bruno-js/src/sandbox/quickjs/index.js
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
const ivm = require('isolated-vm');
|
||||||
|
const addBruShimToContext = require('./shims/bru');
|
||||||
|
const addBrunoRequestShimToContext = require('./shims/bruno-request');
|
||||||
|
const addBrunoResponseShimToContext = require('./shims/bruno-response');
|
||||||
|
const addTestShimToContext = require('./shims/test');
|
||||||
|
const { newQuickJSAsyncWASMModule } = require('quickjs-emscripten');
|
||||||
|
|
||||||
|
// execute `npm run build:isolated-vm:inbuilt-modules` if the below file doesn't exist
|
||||||
|
const getBundledCode = require('../bundle-browser-rollup');
|
||||||
|
|
||||||
|
const toNumber = (value) => {
|
||||||
|
const num = Number(value);
|
||||||
|
return Number.isInteger(num) ? parseInt(value, 10) : parseFloat(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const executeQuickJsVm = ({ script: externalScript, context: externalContext }) => {
|
||||||
|
if (!isNaN(Number(externalScript))) {
|
||||||
|
return Number(externalScript);
|
||||||
|
}
|
||||||
|
let result;
|
||||||
|
const isolate = new ivm.Isolate();
|
||||||
|
try {
|
||||||
|
const context = isolate.createContextSync();
|
||||||
|
context.global.setSync('global', context.global.derefInto());
|
||||||
|
|
||||||
|
const { bru, req, res } = externalContext;
|
||||||
|
|
||||||
|
context.evalSync(`
|
||||||
|
let bru = {};
|
||||||
|
let req = {};
|
||||||
|
let res = {};
|
||||||
|
`);
|
||||||
|
|
||||||
|
bru && addBruShimToContext(context, bru);
|
||||||
|
req && addBrunoRequestShimToContext(context, req);
|
||||||
|
res && addBrunoResponseShimToContext(context, res);
|
||||||
|
|
||||||
|
context.global.setSync('setResult', function (arg) {
|
||||||
|
result = arg;
|
||||||
|
});
|
||||||
|
|
||||||
|
const templateLiteralText = `
|
||||||
|
let value = \`${externalScript}\`;
|
||||||
|
setResult(value);
|
||||||
|
`;
|
||||||
|
|
||||||
|
const jsExpressionText = `
|
||||||
|
let value = ${externalScript};
|
||||||
|
setResult(value);
|
||||||
|
`;
|
||||||
|
|
||||||
|
let scriptText = scriptType === 'template-literal' ? templateLiteralText : jsExpressionText;
|
||||||
|
|
||||||
|
const script = isolate.compileScriptSync(scriptText);
|
||||||
|
script.runSync(context);
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error executing the script!', error);
|
||||||
|
}
|
||||||
|
isolate.dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const executeQuickJsVmAsync = async ({
|
||||||
|
script: externalScript,
|
||||||
|
context: externalContext
|
||||||
|
}) => {
|
||||||
|
if (!isNaN(Number(externalScript))) {
|
||||||
|
return toNumber(externalScript);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const module = await newQuickJSAsyncWASMModule()
|
||||||
|
const runtime = module.newRuntime()
|
||||||
|
const vm = runtime.newContext()
|
||||||
|
|
||||||
|
const bundledCode = getBundledCode?.toString() || '';
|
||||||
|
let bundledScript = `(${bundledCode})()`;
|
||||||
|
|
||||||
|
bundledScript += `
|
||||||
|
globalThis.require = (module) => {
|
||||||
|
return globalThis.requireObject[module];
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
bundledScript += `
|
||||||
|
let bru = {
|
||||||
|
cwd: __bruno__cwd,
|
||||||
|
getEnvName: __bruno__getEnvName,
|
||||||
|
getProcessEnv: __bruno__getProcessEnv,
|
||||||
|
getEnvVar: __bruno__getEnvVar,
|
||||||
|
setEnvVar: __bruno__setEnvVar,
|
||||||
|
getVar: __bruno__getVar,
|
||||||
|
setVar: __bruno__setVar,
|
||||||
|
setNextRequest: __bruno__setNextRequest,
|
||||||
|
visualize: __bruno__visualize,
|
||||||
|
getSecretVar: __bruno__getSecretVar
|
||||||
|
};
|
||||||
|
let req = {
|
||||||
|
url: __bruno__req__url,
|
||||||
|
method: __bruno__req__method,
|
||||||
|
headers: __bruno__req__headers,
|
||||||
|
body: __bruno__req__body,
|
||||||
|
timeout: __bruno__req__timeout,
|
||||||
|
getUrl: __bruno__req__getUrl,
|
||||||
|
setUrl: __bruno__req__setUrl,
|
||||||
|
getMethod: __bruno__req__getMethod,
|
||||||
|
setMethod: __bruno__req__setMethod,
|
||||||
|
getAuthMode: __bruno__req__getAuthMode,
|
||||||
|
getHeaders: __bruno__req__getHeaders,
|
||||||
|
setHeaders: __bruno__req__setHeaders,
|
||||||
|
getHeader: __bruno__req__getHeader,
|
||||||
|
setHeader: __bruno__req__setHeader,
|
||||||
|
getBody: __bruno__req__getBody,
|
||||||
|
setBody: __bruno__req__setBody,
|
||||||
|
setMaxRedirects: __bruno__req__setMaxRedirects,
|
||||||
|
getTimeout: __bruno__req__getTimeout,
|
||||||
|
setTimeout: __bruno__req__setTimeout
|
||||||
|
};
|
||||||
|
let res = {
|
||||||
|
status: globalThis.__bruno__res__status,
|
||||||
|
headers: globalThis.__bruno__res__headers,
|
||||||
|
body: globalThis.__bruno__res__body,
|
||||||
|
responseTime: globalThis.__bruno__res__responseTime,
|
||||||
|
getStatus: globalThis.__bruno__res__getStatus,
|
||||||
|
getHeader: globalThis.__bruno__res__getHeader,
|
||||||
|
getHeaders: globalThis.__bruno__res__getHeaders,
|
||||||
|
getBody: globalThis.__bruno__res__getBody,
|
||||||
|
getResponseTime: globalThis.__bruno__res__getResponseTime
|
||||||
|
};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const { bru, req, res, test, __brunoTestResults, console: consoleFn } = externalContext;
|
||||||
|
|
||||||
|
bru && addBruShimToContext(vm, bru);
|
||||||
|
req && addBrunoRequestShimToContext(vm, req);
|
||||||
|
res && addBrunoResponseShimToContext(vm, res);
|
||||||
|
|
||||||
|
test && __brunoTestResults && addTestShimToContext(vm, __brunoTestResults);
|
||||||
|
|
||||||
|
bundledScript += `
|
||||||
|
globalThis.expect = require('chai').expect;
|
||||||
|
globalThis.assert = require('chai').assert;
|
||||||
|
|
||||||
|
globalThis.__brunoTestResults = {
|
||||||
|
addResult: globalThis.__bruno__addResult,
|
||||||
|
getResults: globalThis.__bruno__getResults,
|
||||||
|
}
|
||||||
|
|
||||||
|
globalThis.DummyChaiAssertionError = class DummyChaiAssertionError extends Error {
|
||||||
|
constructor(message, props, ssf) {
|
||||||
|
super(message);
|
||||||
|
this.name = "AssertionError";
|
||||||
|
Object.assign(this, props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
globalThis.Test = (__brunoTestResults) => (description, callback) => {
|
||||||
|
try {
|
||||||
|
callback();
|
||||||
|
__brunoTestResults.addResult({ description, status: "pass" });
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof DummyChaiAssertionError) {
|
||||||
|
const { message, actual, expected } = error;
|
||||||
|
__brunoTestResults.addResult({
|
||||||
|
description,
|
||||||
|
status: "fail",
|
||||||
|
error: message,
|
||||||
|
actual,
|
||||||
|
expected,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
__brunoTestResults.addResult({
|
||||||
|
description,
|
||||||
|
status: "fail",
|
||||||
|
error: error.message || "An unexpected error occurred.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
globalThis.test = Test(__brunoTestResults);
|
||||||
|
`;
|
||||||
|
|
||||||
|
bundledScript += externalScript;
|
||||||
|
|
||||||
|
const result = await vm.evalCodeAsync(bundledScript);
|
||||||
|
if (result.error) {
|
||||||
|
console.log("Execution failed:", vm.dump(result.error))
|
||||||
|
result.error.dispose()
|
||||||
|
} else {
|
||||||
|
result.value.dispose();
|
||||||
|
}
|
||||||
|
vm.dispose();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error executing the script!', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
executeQuickJsVm,
|
||||||
|
executeQuickJsVmAsync
|
||||||
|
};
|
65
packages/bruno-js/src/sandbox/quickjs/shims/bru.js
Normal file
65
packages/bruno-js/src/sandbox/quickjs/shims/bru.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
const { marshallToVm } = require('../utils');
|
||||||
|
|
||||||
|
const addBruShimToContext = (vm, bru) => {
|
||||||
|
let cwd = vm.newFunction('cwd', function () {
|
||||||
|
return marshallToVm(bru.cwd(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__cwd", cwd)
|
||||||
|
cwd.dispose();
|
||||||
|
|
||||||
|
let getEnvName = vm.newFunction('getEnvName', function () {
|
||||||
|
return marshallToVm(bru.getEnvName(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__getEnvName", getEnvName);
|
||||||
|
getEnvName.dispose();
|
||||||
|
|
||||||
|
let getProcessEnv = vm.newFunction('getProcessEnv', function (key) {
|
||||||
|
return marshallToVm(bru.getProcessEnv(vm.dump(key)), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__getProcessEnv", getProcessEnv);
|
||||||
|
getProcessEnv.dispose();
|
||||||
|
|
||||||
|
let getEnvVar = vm.newFunction('getEnvVar', function (key) {
|
||||||
|
return marshallToVm(bru.getEnvVar(vm.dump(key)), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__getEnvVar", getEnvVar);
|
||||||
|
getEnvVar.dispose();
|
||||||
|
|
||||||
|
let setEnvVar = vm.newFunction('setEnvVar', function (key, value) {
|
||||||
|
bru.setEnvVar(vm.dump(key), vm.dump(value));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__setEnvVar", setEnvVar);
|
||||||
|
setEnvVar.dispose();
|
||||||
|
|
||||||
|
let getVar = vm.newFunction('getVar', function (key) {
|
||||||
|
return marshallToVm(bru.getVar(vm.dump(key)), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__getVar", getVar);
|
||||||
|
getVar.dispose();
|
||||||
|
|
||||||
|
let setVar = vm.newFunction('setVar', function (key, value) {
|
||||||
|
bru.setVar(vm.dump(key), vm.dump(value));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__setVar", setVar);
|
||||||
|
setVar.dispose();
|
||||||
|
|
||||||
|
let setNextRequest = vm.newFunction('setNextRequest', function (nextRequest) {
|
||||||
|
bru.setNextRequest(vm.dump(nextRequest));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__setNextRequest", setNextRequest);
|
||||||
|
setNextRequest.dispose();
|
||||||
|
|
||||||
|
let visualize = vm.newFunction('visualize', function (htmlString) {
|
||||||
|
bru.visualize(vm.dump(htmlString));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__visualize", visualize);
|
||||||
|
visualize.dispose();
|
||||||
|
|
||||||
|
let getSecretVar = vm.newFunction('getSecretVar', function (key) {
|
||||||
|
return marshallToVm(bru.getSecretVar(vm.dump(key)), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__getSecretVar", getSecretVar);
|
||||||
|
getSecretVar.dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = addBruShimToContext;
|
107
packages/bruno-js/src/sandbox/quickjs/shims/bruno-request.js
Normal file
107
packages/bruno-js/src/sandbox/quickjs/shims/bruno-request.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
const { marshallToVm } = require('../utils');
|
||||||
|
|
||||||
|
const addBrunoRequestShimToContext = (vm, req) => {
|
||||||
|
const url = marshallToVm(req.getUrl(), vm);
|
||||||
|
const method = marshallToVm(req.getMethod(), vm);
|
||||||
|
const headers = marshallToVm(req.getHeaders(), vm);
|
||||||
|
const body = marshallToVm(req.getBody(), vm);
|
||||||
|
const timeout = marshallToVm(req.getTimeout(), vm);
|
||||||
|
|
||||||
|
vm.setProp(vm.global, '__bruno__req__url', url);
|
||||||
|
vm.setProp(vm.global, '__bruno__req__method', method);
|
||||||
|
vm.setProp(vm.global, '__bruno__req__headers', headers);
|
||||||
|
vm.setProp(vm.global, '__bruno__req__body', body);
|
||||||
|
vm.setProp(vm.global, '__bruno__req__timeout', timeout);
|
||||||
|
|
||||||
|
url.dispose();
|
||||||
|
method.dispose();
|
||||||
|
headers.dispose();
|
||||||
|
body.dispose();
|
||||||
|
timeout.dispose();
|
||||||
|
|
||||||
|
let getUrl = vm.newFunction('getUrl', function () {
|
||||||
|
return marshallToVm(req.getUrl(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__getUrl', getUrl);
|
||||||
|
getUrl.dispose();
|
||||||
|
|
||||||
|
let setUrl = vm.newFunction('setUrl', function (url) {
|
||||||
|
req.setUrl(vm.dump(url));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__setUrl', setUrl);
|
||||||
|
setUrl.dispose();
|
||||||
|
|
||||||
|
let getMethod = vm.newFunction('getMethod', function () {
|
||||||
|
return marshallToVm(req.getMethod(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__getMethod', getMethod);
|
||||||
|
getMethod.dispose();
|
||||||
|
|
||||||
|
let getAuthMode = vm.newFunction('getAuthMode', function () {
|
||||||
|
return marshallToVm(req.getAuthMode(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__getAuthMode', getAuthMode);
|
||||||
|
getAuthMode.dispose();
|
||||||
|
|
||||||
|
let setMethod = vm.newFunction('setMethod', function (method) {
|
||||||
|
req.setMethod(vm.dump(method));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__setMethod', setMethod);
|
||||||
|
setMethod.dispose();
|
||||||
|
|
||||||
|
let getHeaders = vm.newFunction('getHeaders', function () {
|
||||||
|
return marshallToVm(req.getHeaders(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__getHeaders', getHeaders);
|
||||||
|
getHeaders.dispose();
|
||||||
|
|
||||||
|
let setHeaders = vm.newFunction('setHeaders', function (headers) {
|
||||||
|
req.setHeaders(vm.dump(headers));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__setHeaders', setHeaders);
|
||||||
|
setHeaders.dispose();
|
||||||
|
|
||||||
|
let getHeader = vm.newFunction('getHeader', function (name) {
|
||||||
|
return marshallToVm(req.getHeader(vm.dump(name)), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__getHeader', getHeader);
|
||||||
|
getHeader.dispose();
|
||||||
|
|
||||||
|
let setHeader = vm.newFunction('setHeader', function (name, value) {
|
||||||
|
req.setHeader(vm.dump(name), vm.dump(value));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__setHeader', setHeader);
|
||||||
|
setHeader.dispose();
|
||||||
|
|
||||||
|
let getBody = vm.newFunction('getBody', function () {
|
||||||
|
return marshallToVm(req.getBody(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__getBody', getBody);
|
||||||
|
getBody.dispose();
|
||||||
|
|
||||||
|
let setBody = vm.newFunction('setBody', function (data) {
|
||||||
|
req.setBody(vm.dump(data));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__setBody', setBody);
|
||||||
|
setBody.dispose();
|
||||||
|
|
||||||
|
let setMaxRedirects = vm.newFunction('setMaxRedirects', function (maxRedirects) {
|
||||||
|
req.setMaxRedirects(vm.dump(maxRedirects));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__setMaxRedirects', setMaxRedirects);
|
||||||
|
setMaxRedirects.dispose();
|
||||||
|
|
||||||
|
let getTimeout = vm.newFunction('getTimeout', function () {
|
||||||
|
return marshallToVm(req.getTimeout(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__getTimeout', getTimeout);
|
||||||
|
getTimeout.dispose();
|
||||||
|
|
||||||
|
let setTimeout = vm.newFunction('setTimeout', function (timeout) {
|
||||||
|
req.setTimeout(vm.dump(timeout));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__req__setTimeout', setTimeout);
|
||||||
|
setTimeout.dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = addBrunoRequestShimToContext;
|
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
const { marshallToVm } = require('../utils');
|
||||||
|
|
||||||
|
const addBrunoResponseShimToContext = (vm, res) => {
|
||||||
|
const status = marshallToVm(res?.status, vm);
|
||||||
|
const headers = marshallToVm(res?.headers, vm);
|
||||||
|
const body = marshallToVm(res?.body, vm);
|
||||||
|
const responseTime = marshallToVm(res?.responseTime, vm);
|
||||||
|
|
||||||
|
vm.setProp(vm.global, '__bruno__res__status', status);
|
||||||
|
vm.setProp(vm.global, '__bruno__res__headers', headers);
|
||||||
|
vm.setProp(vm.global, '__bruno__res__body', body);
|
||||||
|
vm.setProp(vm.global, '__bruno__res__responseTime', responseTime);
|
||||||
|
|
||||||
|
status.dispose();
|
||||||
|
headers.dispose();
|
||||||
|
body.dispose();
|
||||||
|
responseTime.dispose();
|
||||||
|
|
||||||
|
let getStatus = vm.newFunction('getStatus', function () {
|
||||||
|
return marshallToVm(res.getStatus(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__res__getStatus', getStatus);
|
||||||
|
getStatus.dispose();
|
||||||
|
|
||||||
|
let getHeader = vm.newFunction('getHeader', function (name) {
|
||||||
|
return marshallToVm(res.getHeader(vm.dump(name)), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__res__getHeader', getHeader);
|
||||||
|
getHeader.dispose();
|
||||||
|
|
||||||
|
let getHeaders = vm.newFunction('getHeaders', function () {
|
||||||
|
return marshallToVm(res.getHeaders(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__res__getHeaders', getHeaders);
|
||||||
|
getHeaders.dispose();
|
||||||
|
|
||||||
|
let getBody = vm.newFunction('getBody', function () {
|
||||||
|
return marshallToVm(res.getBody(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__res__getBody', getBody);
|
||||||
|
getBody.dispose();
|
||||||
|
|
||||||
|
let getResponseTime = vm.newFunction('getResponseTime', function () {
|
||||||
|
return marshallToVm(res.getResponseTime(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, '__bruno__res__getResponseTime', getResponseTime);
|
||||||
|
getResponseTime.dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = addBrunoResponseShimToContext;
|
17
packages/bruno-js/src/sandbox/quickjs/shims/test.js
Normal file
17
packages/bruno-js/src/sandbox/quickjs/shims/test.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const { marshallToVm } = require('../utils');
|
||||||
|
|
||||||
|
const addBruShimToContext = (vm, __brunoTestResults) => {
|
||||||
|
let addResult = vm.newFunction('addResult', function (v) {
|
||||||
|
__brunoTestResults.addResult(vm.dump(v));
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__addResult", addResult);
|
||||||
|
addResult.dispose();
|
||||||
|
|
||||||
|
let getResults = vm.newFunction('getResults', function () {
|
||||||
|
return marshallToVm(__brunoTestResults.getResults(), vm);
|
||||||
|
});
|
||||||
|
vm.setProp(vm.global, "__bruno__getResults", getResults);
|
||||||
|
getResults.dispose();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = addBruShimToContext;
|
35
packages/bruno-js/src/sandbox/quickjs/utils/index.js
Normal file
35
packages/bruno-js/src/sandbox/quickjs/utils/index.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const marshallToVm = (value, vm) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return vm.undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null) {
|
||||||
|
return vm.null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === "string") {
|
||||||
|
return vm.newString(value);
|
||||||
|
} else if (typeof value === "number") {
|
||||||
|
return vm.newNumber(value);
|
||||||
|
} else if (typeof value === "boolean") {
|
||||||
|
return vm.newBoolean(value);
|
||||||
|
} else if (typeof value === "object") {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
const arr = vm.newArray();
|
||||||
|
for (let i = 0; i < value.length; i++) {
|
||||||
|
vm.setProp(arr, i, marshallToVm(value[i], vm));
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
} else {
|
||||||
|
const obj = vm.newObject();
|
||||||
|
for (const key in value) {
|
||||||
|
vm.setProp(obj, key, marshallToVm(value[key], vm));
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
marshallToVm
|
||||||
|
};
|
@ -8,6 +8,3 @@ vars {
|
|||||||
foo: bar
|
foo: bar
|
||||||
testSetEnvVar: bruno-29653
|
testSetEnvVar: bruno-29653
|
||||||
}
|
}
|
||||||
vars:secret [
|
|
||||||
bruno
|
|
||||||
]
|
|
||||||
|
@ -9,52 +9,3 @@ get {
|
|||||||
body: none
|
body: none
|
||||||
auth: none
|
auth: none
|
||||||
}
|
}
|
||||||
|
|
||||||
auth:awsv4 {
|
|
||||||
accessKeyId: a
|
|
||||||
secretAccessKey: b
|
|
||||||
sessionToken: c
|
|
||||||
service: d
|
|
||||||
region: e
|
|
||||||
profileName: f
|
|
||||||
}
|
|
||||||
|
|
||||||
vars:pre-request {
|
|
||||||
m4: true
|
|
||||||
pong: pong
|
|
||||||
}
|
|
||||||
|
|
||||||
assert {
|
|
||||||
res.status: eq 200
|
|
||||||
res.responseTime: lte 2000
|
|
||||||
res.body: eq {{pong}}
|
|
||||||
}
|
|
||||||
|
|
||||||
tests {
|
|
||||||
test("should ping pong", function() {
|
|
||||||
const data = res.getBody();
|
|
||||||
expect(data).to.equal(bru.getRequestVar("pong"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
docs {
|
|
||||||
# API Documentation
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Welcome to the API documentation for [Your API Name]. This document provides instructions on how to make requests to the API and covers available authentication methods.
|
|
||||||
|
|
||||||
## Authentication
|
|
||||||
|
|
||||||
Before making requests to the API, you need to authenticate your application. [Your API Name] supports the following authentication methods:
|
|
||||||
|
|
||||||
### API Key
|
|
||||||
|
|
||||||
To use API key authentication, include your API key in the request headers as follows:
|
|
||||||
|
|
||||||
```http
|
|
||||||
GET /api/endpoint
|
|
||||||
Host: api.example.com
|
|
||||||
Authorization: Bearer YOUR_API_KEY
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -10,7 +10,6 @@ get {
|
|||||||
auth: none
|
auth: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
script:pre-request {
|
script:pre-request {
|
||||||
const envName = bru.getEnvName();
|
const envName = bru.getEnvName();
|
||||||
bru.setVar("testEnvName", envName);
|
bru.setVar("testEnvName", envName);
|
||||||
@ -21,4 +20,4 @@ tests {
|
|||||||
const testEnvName = bru.getVar("testEnvName");
|
const testEnvName = bru.getVar("testEnvName");
|
||||||
expect(testEnvName).to.equal("Prod");
|
expect(testEnvName).to.equal("Prod");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ get {
|
|||||||
auth: none
|
auth: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
script:post-response {
|
script:post-response {
|
||||||
bru.setVar("testSetVar", "bruno-test-87267")
|
bru.setVar("testSetVar", "bruno-test-87267")
|
||||||
}
|
}
|
||||||
@ -20,4 +19,4 @@ tests {
|
|||||||
const testSetVar = bru.getVar("testSetVar");
|
const testSetVar = bru.getVar("testSetVar");
|
||||||
expect(testSetVar).to.equal("bruno-test-87267");
|
expect(testSetVar).to.equal("bruno-test-87267");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ get {
|
|||||||
auth: none
|
auth: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
assert {
|
assert {
|
||||||
res.status: eq 200
|
res.status: eq 200
|
||||||
res.body: eq pong
|
res.body: eq pong
|
||||||
@ -21,4 +20,4 @@ tests {
|
|||||||
const url = req.getUrl();
|
const url = req.getUrl();
|
||||||
expect(url).to.equal("https://testbench-sanity.usebruno.com/ping");
|
expect(url).to.equal("https://testbench-sanity.usebruno.com/ping");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user