mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-15 20:01:28 +00:00
377 lines
11 KiB
JavaScript
377 lines
11 KiB
JavaScript
const { get, each, filter, find, compact } = require('lodash');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
var JSONbig = require('json-bigint');
|
|
const decomment = require('decomment');
|
|
const crypto = require('node:crypto');
|
|
|
|
const mergeHeaders = (collection, request, requestTreePath) => {
|
|
let headers = new Map();
|
|
|
|
let collectionHeaders = get(collection, 'root.request.headers', []);
|
|
collectionHeaders.forEach((header) => {
|
|
if (header.enabled) {
|
|
headers.set(header.name, header.value);
|
|
}
|
|
});
|
|
|
|
for (let i of requestTreePath) {
|
|
if (i.type === 'folder') {
|
|
let _headers = get(i, 'root.request.headers', []);
|
|
_headers.forEach((header) => {
|
|
if (header.enabled) {
|
|
headers.set(header.name, header.value);
|
|
}
|
|
});
|
|
} else {
|
|
const _headers = i?.draft ? get(i, 'draft.request.headers', []) : get(i, 'request.headers', []);
|
|
_headers.forEach((header) => {
|
|
if (header.enabled) {
|
|
headers.set(header.name, header.value);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
request.headers = Array.from(headers, ([name, value]) => ({ name, value, enabled: true }));
|
|
};
|
|
|
|
const mergeVars = (collection, request, requestTreePath) => {
|
|
let reqVars = new Map();
|
|
let collectionRequestVars = get(collection, 'root.request.vars.req', []);
|
|
let collectionVariables = {};
|
|
collectionRequestVars.forEach((_var) => {
|
|
if (_var.enabled) {
|
|
reqVars.set(_var.name, _var.value);
|
|
collectionVariables[_var.name] = _var.value;
|
|
}
|
|
});
|
|
let folderVariables = {};
|
|
let requestVariables = {};
|
|
for (let i of requestTreePath) {
|
|
if (i.type === 'folder') {
|
|
let vars = get(i, 'root.request.vars.req', []);
|
|
vars.forEach((_var) => {
|
|
if (_var.enabled) {
|
|
reqVars.set(_var.name, _var.value);
|
|
folderVariables[_var.name] = _var.value;
|
|
}
|
|
});
|
|
} else {
|
|
const vars = i?.draft ? get(i, 'draft.request.vars.req', []) : get(i, 'request.vars.req', []);
|
|
vars.forEach((_var) => {
|
|
if (_var.enabled) {
|
|
reqVars.set(_var.name, _var.value);
|
|
requestVariables[_var.name] = _var.value;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
request.collectionVariables = collectionVariables;
|
|
request.folderVariables = folderVariables;
|
|
request.requestVariables = requestVariables;
|
|
|
|
if(request?.vars) {
|
|
request.vars.req = Array.from(reqVars, ([name, value]) => ({
|
|
name,
|
|
value,
|
|
enabled: true,
|
|
type: 'request'
|
|
}));
|
|
}
|
|
|
|
let resVars = new Map();
|
|
let collectionResponseVars = get(collection, 'root.request.vars.res', []);
|
|
collectionResponseVars.forEach((_var) => {
|
|
if (_var.enabled) {
|
|
resVars.set(_var.name, _var.value);
|
|
}
|
|
});
|
|
for (let i of requestTreePath) {
|
|
if (i.type === 'folder') {
|
|
let vars = get(i, 'root.request.vars.res', []);
|
|
vars.forEach((_var) => {
|
|
if (_var.enabled) {
|
|
resVars.set(_var.name, _var.value);
|
|
}
|
|
});
|
|
} else {
|
|
const vars = i?.draft ? get(i, 'draft.request.vars.res', []) : get(i, 'request.vars.res', []);
|
|
vars.forEach((_var) => {
|
|
if (_var.enabled) {
|
|
resVars.set(_var.name, _var.value);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if(request?.vars) {
|
|
request.vars.res = Array.from(resVars, ([name, value]) => ({
|
|
name,
|
|
value,
|
|
enabled: true,
|
|
type: 'response'
|
|
}));
|
|
}
|
|
};
|
|
|
|
const mergeScripts = (collection, request, requestTreePath, scriptFlow) => {
|
|
let collectionPreReqScript = get(collection, 'root.request.script.req', '');
|
|
let collectionPostResScript = get(collection, 'root.request.script.res', '');
|
|
let collectionTests = get(collection, 'root.request.tests', '');
|
|
|
|
let combinedPreReqScript = [];
|
|
let combinedPostResScript = [];
|
|
let combinedTests = [];
|
|
for (let i of requestTreePath) {
|
|
if (i.type === 'folder') {
|
|
let preReqScript = get(i, 'root.request.script.req', '');
|
|
if (preReqScript && preReqScript.trim() !== '') {
|
|
combinedPreReqScript.push(preReqScript);
|
|
}
|
|
|
|
let postResScript = get(i, 'root.request.script.res', '');
|
|
if (postResScript && postResScript.trim() !== '') {
|
|
combinedPostResScript.push(postResScript);
|
|
}
|
|
|
|
let tests = get(i, 'root.request.tests', '');
|
|
if (tests && tests?.trim?.() !== '') {
|
|
combinedTests.push(tests);
|
|
}
|
|
}
|
|
}
|
|
|
|
request.script.req = compact([collectionPreReqScript, ...combinedPreReqScript, request?.script?.req || '']).join(os.EOL);
|
|
|
|
if (scriptFlow === 'sequential') {
|
|
request.script.res = compact([collectionPostResScript, ...combinedPostResScript, request?.script?.res || '']).join(os.EOL);
|
|
} else {
|
|
request.script.res = compact([request?.script?.res || '', ...combinedPostResScript.reverse(), collectionPostResScript]).join(os.EOL);
|
|
}
|
|
|
|
if (scriptFlow === 'sequential') {
|
|
request.tests = compact([collectionTests, ...combinedTests, request?.tests || '']).join(os.EOL);
|
|
} else {
|
|
request.tests = compact([request?.tests || '', ...combinedTests.reverse(), collectionTests]).join(os.EOL);
|
|
}
|
|
};
|
|
|
|
const findItem = (items = [], pathname) => {
|
|
return find(items, (i) => i.pathname === pathname);
|
|
};
|
|
|
|
const findItemInCollection = (collection, pathname) => {
|
|
let flattenedItems = flattenItems(collection.items);
|
|
|
|
return findItem(flattenedItems, pathname);
|
|
};
|
|
|
|
const findParentItemInCollection = (collection, pathname) => {
|
|
let flattenedItems = flattenItems(collection.items);
|
|
|
|
return find(flattenedItems, (item) => {
|
|
return item.items && find(item.items, (i) => i.pathname === pathname);
|
|
});
|
|
};
|
|
|
|
const flattenItems = (items = []) => {
|
|
const flattenedItems = [];
|
|
|
|
const flatten = (itms, flattened) => {
|
|
each(itms, (i) => {
|
|
flattened.push(i);
|
|
|
|
if (i.items && i.items.length) {
|
|
flatten(i.items, flattened);
|
|
}
|
|
});
|
|
};
|
|
|
|
flatten(items, flattenedItems);
|
|
|
|
return flattenedItems;
|
|
};
|
|
|
|
const getTreePathFromCollectionToItem = (collection, _item) => {
|
|
let path = [];
|
|
let item = findItemInCollection(collection, _item.pathname);
|
|
while (item) {
|
|
path.unshift(item);
|
|
item = findParentItemInCollection(collection, item.pathname);
|
|
}
|
|
return path;
|
|
};
|
|
|
|
const prepareRequest = (item = {}, collection = {}) => {
|
|
const request = item?.request;
|
|
const brunoConfig = get(collection, 'brunoConfig', {});
|
|
const headers = {};
|
|
let contentTypeDefined = false;
|
|
|
|
const scriptFlow = brunoConfig?.scripts?.flow ?? 'sandwich';
|
|
const requestTreePath = getTreePathFromCollectionToItem(collection, item);
|
|
if (requestTreePath && requestTreePath.length > 0) {
|
|
mergeHeaders(collection, request, requestTreePath);
|
|
mergeScripts(collection, request, requestTreePath, scriptFlow);
|
|
mergeVars(collection, request, requestTreePath);
|
|
}
|
|
|
|
each(get(request, 'headers', []), (h) => {
|
|
if (h.enabled) {
|
|
headers[h.name] = h.value;
|
|
if (h.name.toLowerCase() === 'content-type') {
|
|
contentTypeDefined = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
let axiosRequest = {
|
|
method: request.method,
|
|
url: request.url,
|
|
headers: headers,
|
|
pathParams: request?.params?.filter((param) => param.type === 'path')
|
|
};
|
|
|
|
const collectionAuth = get(collection, 'root.request.auth');
|
|
if (collectionAuth && request.auth.mode === 'inherit') {
|
|
if (collectionAuth.mode === 'basic') {
|
|
axiosRequest.auth = {
|
|
username: get(collectionAuth, 'basic.username'),
|
|
password: get(collectionAuth, 'basic.password')
|
|
};
|
|
}
|
|
|
|
if (collectionAuth.mode === 'bearer') {
|
|
axiosRequest.headers['Authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`;
|
|
}
|
|
}
|
|
|
|
if (request.auth) {
|
|
if (request.auth.mode === 'basic') {
|
|
axiosRequest.auth = {
|
|
username: get(request, 'auth.basic.username'),
|
|
password: get(request, 'auth.basic.password')
|
|
};
|
|
}
|
|
|
|
if (request.auth.mode === 'awsv4') {
|
|
axiosRequest.awsv4config = {
|
|
accessKeyId: get(request, 'auth.awsv4.accessKeyId'),
|
|
secretAccessKey: get(request, 'auth.awsv4.secretAccessKey'),
|
|
sessionToken: get(request, 'auth.awsv4.sessionToken'),
|
|
service: get(request, 'auth.awsv4.service'),
|
|
region: get(request, 'auth.awsv4.region'),
|
|
profileName: get(request, 'auth.awsv4.profileName')
|
|
};
|
|
}
|
|
|
|
if (request.auth.mode === 'bearer') {
|
|
axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
|
|
}
|
|
|
|
if (request.auth.mode === 'wsse') {
|
|
const username = get(request, 'auth.wsse.username', '');
|
|
const password = get(request, 'auth.wsse.password', '');
|
|
|
|
const ts = new Date().toISOString();
|
|
const nonce = crypto.randomBytes(16).toString('hex');
|
|
|
|
// Create the password digest using SHA-1 as required for WSSE
|
|
const hash = crypto.createHash('sha1');
|
|
hash.update(nonce + ts + password);
|
|
const digest = Buffer.from(hash.digest('hex').toString('utf8')).toString('base64');
|
|
|
|
// Construct the WSSE header
|
|
axiosRequest.headers[
|
|
'X-WSSE'
|
|
] = `UsernameToken Username="${username}", PasswordDigest="${digest}", Nonce="${nonce}", Created="${ts}"`;
|
|
}
|
|
}
|
|
|
|
request.body = request.body || {};
|
|
|
|
if (request.body.mode === 'json') {
|
|
if (!contentTypeDefined) {
|
|
axiosRequest.headers['content-type'] = 'application/json';
|
|
}
|
|
let jsonBody;
|
|
try {
|
|
jsonBody = decomment(request?.body?.json);
|
|
} catch (error) {
|
|
jsonBody = request?.body?.json;
|
|
}
|
|
try {
|
|
axiosRequest.data = JSONbig.parse(jsonBody);
|
|
} catch (error) {
|
|
axiosRequest.data = jsonBody;
|
|
}
|
|
}
|
|
|
|
if (request.body.mode === 'text') {
|
|
if (!contentTypeDefined) {
|
|
axiosRequest.headers['content-type'] = 'text/plain';
|
|
}
|
|
axiosRequest.data = request.body.text;
|
|
}
|
|
|
|
if (request.body.mode === 'xml') {
|
|
if (!contentTypeDefined) {
|
|
axiosRequest.headers['content-type'] = 'text/xml';
|
|
}
|
|
axiosRequest.data = request.body.xml;
|
|
}
|
|
|
|
if (request.body.mode === 'sparql') {
|
|
if (!contentTypeDefined) {
|
|
axiosRequest.headers['content-type'] = 'application/sparql-query';
|
|
}
|
|
axiosRequest.data = request.body.sparql;
|
|
}
|
|
|
|
if (request.body.mode === 'formUrlEncoded') {
|
|
axiosRequest.headers['content-type'] = 'application/x-www-form-urlencoded';
|
|
const params = {};
|
|
const enabledParams = filter(request.body.formUrlEncoded, (p) => p.enabled);
|
|
each(enabledParams, (p) => (params[p.name] = p.value));
|
|
axiosRequest.data = params;
|
|
}
|
|
|
|
if (request.body.mode === 'multipartForm') {
|
|
axiosRequest.headers['content-type'] = 'multipart/form-data';
|
|
const params = {};
|
|
const enabledParams = filter(request.body.multipartForm, (p) => p.enabled);
|
|
each(enabledParams, (p) => (params[p.name] = p.value));
|
|
axiosRequest.data = params;
|
|
}
|
|
|
|
if (request.body.mode === 'graphql') {
|
|
const graphqlQuery = {
|
|
query: get(request, 'body.graphql.query'),
|
|
variables: JSON.parse(decomment(get(request, 'body.graphql.variables') || '{}'))
|
|
};
|
|
if (!contentTypeDefined) {
|
|
axiosRequest.headers['content-type'] = 'application/json';
|
|
}
|
|
axiosRequest.data = graphqlQuery;
|
|
}
|
|
|
|
if (request.script) {
|
|
axiosRequest.script = request.script;
|
|
}
|
|
|
|
if (request.tests) {
|
|
axiosRequest.tests = request.tests;
|
|
}
|
|
|
|
axiosRequest.vars = request.vars;
|
|
axiosRequest.collectionVariables = request.collectionVariables;
|
|
axiosRequest.folderVariables = request.folderVariables;
|
|
axiosRequest.requestVariables = request.requestVariables;
|
|
|
|
return axiosRequest;
|
|
};
|
|
|
|
module.exports = prepareRequest;
|