From 688fe95d78643b6f15858af3334be26676300907 Mon Sep 17 00:00:00 2001 From: Raghav Sethi Date: Sat, 7 Dec 2024 06:17:48 -0500 Subject: [PATCH 1/2] adding dynamic variable support --- .../bruno-electron/src/ipc/network/index.js | 4 + .../src/ipc/network/interpolate-random.js | 196 ++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 packages/bruno-electron/src/ipc/network/interpolate-random.js diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 9e37c8289d..584a551fee 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -17,6 +17,7 @@ const prepareGqlIntrospectionRequest = require('./prepare-gql-introspection-requ const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../utils/cancel-token'); const { uuid } = require('../../utils/common'); const interpolateVars = require('./interpolate-vars'); +const interpolateRandom = require('./interpolate-random'); const { interpolateString } = require('./interpolate-string'); const { sortFolder, getAllRequestsInFolderRecursively } = require('./helper'); const { preferencesUtil } = require('../../store/preferences'); @@ -423,6 +424,9 @@ const registerNetworkIpc = (mainWindow) => { }); } + // interpolate random/dynamic values inside request + interpolateRandom(request); + // interpolate variables inside request interpolateVars(request, envVars, runtimeVariables, processEnvVars); diff --git a/packages/bruno-electron/src/ipc/network/interpolate-random.js b/packages/bruno-electron/src/ipc/network/interpolate-random.js new file mode 100644 index 0000000000..1e51bfdb30 --- /dev/null +++ b/packages/bruno-electron/src/ipc/network/interpolate-random.js @@ -0,0 +1,196 @@ +// Import faker.js +const { faker } = require('@faker-js/faker'); +const { each, forOwn } = require('lodash'); +const FormData = require('form-data'); + +const getContentType = (headers = {}) => { + let contentType = ''; + forOwn(headers, (value, key) => { + if (key && key.toLowerCase() === 'content-type') { + contentType = value; + } + }); + + return contentType; + }; + + const interpolateRandom = (request) => { + + const _interpolate = (str) => { + if (!str || !str.length || typeof str !== 'string') { + return str; + } + + let resultStr = str; + let matchFound = true; + + while (matchFound) { + const patternRegex = /\{\{\$([^}]+)\}\}/g; + matchFound = false; + resultStr = resultStr.replace(patternRegex, (_, placeholder) => { + const replacement = getRandomValue(placeholder); + matchFound = true; + return replacement; + }); + } + + return resultStr; + }; + + request.url = _interpolate(request.url); + + const contentType = getContentType(request.headers); + + if (contentType.includes('json')) { + if (typeof request.data === 'string') { + if (request.data.length) { + request.data = _interpolate(request.data); + } + } else if (typeof request.data === 'object') { + try { + let parsed = JSON.stringify(request.data); + parsed = _interpolate(parsed); + request.data = JSON.parse(parsed); + } catch (err) {} + } + } else if (contentType === 'application/x-www-form-urlencoded') { + if (typeof request.data === 'object') { + try { + forOwn(request?.data, (value, key) => { + request.data[key] = _interpolate(value); + }); + } catch (err) {} + } + } else if (contentType === 'multipart/form-data') { + if (typeof request.data === 'object' && !(request.data instanceof FormData)) { + try { + forOwn(request?.data, (value, key) => { + request.data[key] = _interpolate(value); + }); + } catch (err) {} + } + } else { + request.data = _interpolate(request.data); + } + + each(request.pathParams, (param) => { + param.value = _interpolate(param.value); + }); + + if (request?.pathParams?.length) { + let url = request.url; + + if (!url.startsWith('http://') && !url.startsWith('https://')) { + url = `http://${url}`; + } + + try { + url = new URL(url); + } catch (e) { + throw { message: 'Invalid URL format', originalError: e.message }; + } + + const urlPathnameInterpolatedWithPathParams = url.pathname + .split('/') + .filter((path) => path !== '') + .map((path) => { + if (path[0] !== ':') { + return '/' + path; + } else { + const name = path.slice(1); + const existingPathParam = request.pathParams.find((param) => param.type === 'path' && param.name === name); + return existingPathParam ? '/' + existingPathParam.value : ''; + } + }) + .join(''); + + const trailingSlash = url.pathname.endsWith('/') ? '/' : ''; + request.url = url.origin + urlPathnameInterpolatedWithPathParams + trailingSlash + url.search; + } + + return request; + }; + +// Function to get random values based on the variable name +function getRandomValue(variableName) { + switch(variableName) { + case "guid": + return faker.datatype.uuid(); // Generates a UUID + case "timestamp": + return Math.floor(Date.now() / 1000); // Current UNIX timestamp + case "isoTimestamp": + return new Date().toISOString(); // Current ISO timestamp + case "randomUUID": + return faker.datatype.uuid(); // Random 36-character UUID + case "randomAlphaNumeric": + return faker.random.alphaNumeric(1); // Random alphanumeric character + case "$randomBoolean": + return faker.datatype.boolean(); // Random boolean + case "randomInt": + return faker.datatype.number({ min: 0, max: 1000 }); // Random integer between 0 and 1000 + case "randomColor": + return faker.color.human(); // Random color name (human-readable) + case "$randomHexColor": + return faker.internet.color(); // Random hex color code + case "$randomAbbreviation": + return faker.random.arrayElement(['SQL', 'PCI', 'JSON', 'HTTP', 'XML']); // Random abbreviation + case "randomIP": + return faker.internet.ip(); // Random IPv4 address + case "randomIPV6": + return faker.internet.ipv6(); // Random IPv6 address + case "randomMACAddress": + return faker.internet.mac(); // Random MAC address + case "randomPassword": + return faker.internet.password(); // Random password (default 8 characters) + case "randomLocale": + return faker.random.locale(); // Random two-letter language code (ISO 639-1) + case "randomUserAgent": + return faker.internet.userAgent(); // Random user agent string + case "$randomProtocol": + return faker.internet.protocol(); // Random internet protocol (http, https) + case "randomSemver": + return faker.system.semver(); // Random semantic version + case "randomFirstName": + return faker.name.firstName(); // Random first name + case "randomLastName": + return faker.name.lastName(); // Random last name + case "randomFullName": + return faker.name.findName(); // Random full name + case "randomNamePrefix": + return faker.name.prefix(); // Random name prefix (e.g., Mr., Ms.) + case "randomNameSuffix": + return faker.name.suffix(); // Random name suffix (e.g., MD, Jr.) + case "randomPhoneNumber": + return faker.phone.phoneNumber(); // Random phone number + case "randomCity": + return faker.address.city(); // Random city name + case "randomStreetName": + return faker.address.streetName(); // Random street name + case "randomStreetAddress": + return faker.address.streetAddress(); // Random street address + case "randomCountry": + return faker.address.country(); // Random country name + case "randomCountryCode": + return faker.address.countryCode(); // Random two-letter country code + case "randomLatitude": + return faker.address.latitude(); // Random latitude coordinate + case "randomLongitude": + return faker.address.longitude(); // Random longitude coordinate + case "randomAvatarImage": + return faker.image.avatar(); // Random avatar image URL + case "randomImageUrl": + return faker.image.imageUrl(); // Random image URL + case "randomPrice": + return faker.commerce.price(); // Random price between 0.00 and 1000.00 + case "randomProduct": + return faker.commerce.productName(); // Random product name + case "randomCompanyName": + return faker.company.companyName(); // Random company name + case "randomEmail": + return faker.internet.email(); // Random email address + default: + return null; // If no match found, return null + } +} + +module.exports = interpolateRandom; From e12104561e4d68924f817b4f2b99e4e77905495a Mon Sep 17 00:00:00 2001 From: Raghav Sethi Date: Tue, 17 Dec 2024 21:57:12 -0500 Subject: [PATCH 2/2] update deprecated methods --- .../bruno-electron/src/ipc/network/interpolate-random.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/bruno-electron/src/ipc/network/interpolate-random.js b/packages/bruno-electron/src/ipc/network/interpolate-random.js index 1e51bfdb30..d500ece911 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-random.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-random.js @@ -155,13 +155,13 @@ function getRandomValue(variableName) { case "randomLastName": return faker.name.lastName(); // Random last name case "randomFullName": - return faker.name.findName(); // Random full name + return faker.name.fullName(); // Random full name case "randomNamePrefix": return faker.name.prefix(); // Random name prefix (e.g., Mr., Ms.) case "randomNameSuffix": return faker.name.suffix(); // Random name suffix (e.g., MD, Jr.) case "randomPhoneNumber": - return faker.phone.phoneNumber(); // Random phone number + return faker.phone.number(); // Random phone number case "randomCity": return faker.address.city(); // Random city name case "randomStreetName": @@ -185,7 +185,7 @@ function getRandomValue(variableName) { case "randomProduct": return faker.commerce.productName(); // Random product name case "randomCompanyName": - return faker.company.companyName(); // Random company name + return faker.company.name(); // Random company name case "randomEmail": return faker.internet.email(); // Random email address default: