{envVar.name} |
diff --git a/packages/bruno-app/src/providers/App/useTelemetry.js b/packages/bruno-app/src/providers/App/useTelemetry.js
index f89b1343ee..6b64e1279e 100644
--- a/packages/bruno-app/src/providers/App/useTelemetry.js
+++ b/packages/bruno-app/src/providers/App/useTelemetry.js
@@ -58,7 +58,7 @@ const trackStart = () => {
event: 'start',
properties: {
os: platformLib.os.family,
- version: '1.36.0'
+ version: '1.38.1'
}
});
};
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
index 10f552ec57..11f12026f7 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
@@ -473,6 +473,10 @@ export const collectionsSlice = createSlice({
item.draft.request.auth.mode = 'digest';
item.draft.request.auth.digest = action.payload.content;
break;
+ case 'ntlm':
+ item.draft.request.auth.mode = 'ntlm';
+ item.draft.request.auth.ntlm = action.payload.content;
+ break;
case 'oauth2':
item.draft.request.auth.mode = 'oauth2';
item.draft.request.auth.oauth2 = action.payload.content;
@@ -528,11 +532,16 @@ export const collectionsSlice = createSlice({
const { updateReorderedItem } = action.payload;
const params = item.draft.request.params;
- item.draft.request.params = updateReorderedItem.map((uid) => {
- return params.find((param) => param.uid === uid);
+ const queryParams = params.filter((param) => param.type === 'query');
+ const pathParams = params.filter((param) => param.type === 'path');
+
+ // Reorder only query params based on updateReorderedItem
+ const reorderedQueryParams = updateReorderedItem.map((uid) => {
+ return queryParams.find((param) => param.uid === uid);
});
-
- // update request url
+ item.draft.request.params = [...reorderedQueryParams, ...pathParams];
+
+ // Update request URL
const parts = splitOnFirst(item.draft.request.url, '?');
const query = stringifyQueryParams(filter(item.draft.request.params, (p) => p.enabled && p.type === 'query'));
if (query && query.length) {
@@ -690,6 +699,28 @@ export const collectionsSlice = createSlice({
}
}
},
+ moveRequestHeader: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+
+ if (collection) {
+ const item = findItemInCollection(collection, action.payload.itemUid);
+
+ if (item && isItemARequest(item)) {
+ // Ensure item.draft is a deep clone of item if not already present
+ if (!item.draft) {
+ item.draft = cloneDeep(item);
+ }
+
+ // Extract payload data
+ const { updateReorderedItem } = action.payload;
+ const params = item.draft.request.headers;
+
+ item.draft.request.headers = updateReorderedItem.map((uid) => {
+ return params.find((param) => param.uid === uid);
+ });
+ }
+ }
+ },
addFormUrlEncodedParam: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
@@ -748,6 +779,28 @@ export const collectionsSlice = createSlice({
}
}
},
+ moveFormUrlEncodedParam: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+
+ if (collection) {
+ const item = findItemInCollection(collection, action.payload.itemUid);
+
+ if (item && isItemARequest(item)) {
+ // Ensure item.draft is a deep clone of item if not already present
+ if (!item.draft) {
+ item.draft = cloneDeep(item);
+ }
+
+ // Extract payload data
+ const { updateReorderedItem } = action.payload;
+ const params = item.draft.request.body.formUrlEncoded;
+
+ item.draft.request.body.formUrlEncoded = updateReorderedItem.map((uid) => {
+ return params.find((param) => param.uid === uid);
+ });
+ }
+ }
+ },
addMultipartFormParam: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
@@ -810,6 +863,28 @@ export const collectionsSlice = createSlice({
}
}
},
+ moveMultipartFormParam: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+
+ if (collection) {
+ const item = findItemInCollection(collection, action.payload.itemUid);
+
+ if (item && isItemARequest(item)) {
+ // Ensure item.draft is a deep clone of item if not already present
+ if (!item.draft) {
+ item.draft = cloneDeep(item);
+ }
+
+ // Extract payload data
+ const { updateReorderedItem } = action.payload;
+ const params = item.draft.request.body.multipartForm;
+
+ item.draft.request.body.multipartForm = updateReorderedItem.map((uid) => {
+ return params.find((param) => param.uid === uid);
+ });
+ }
+ }
+ },
updateRequestAuthMode: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
@@ -1023,6 +1098,28 @@ export const collectionsSlice = createSlice({
}
}
},
+ moveAssertion: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+
+ if (collection) {
+ const item = findItemInCollection(collection, action.payload.itemUid);
+
+ if (item && isItemARequest(item)) {
+ // Ensure item.draft is a deep clone of item if not already present
+ if (!item.draft) {
+ item.draft = cloneDeep(item);
+ }
+
+ // Extract payload data
+ const { updateReorderedItem } = action.payload;
+ const params = item.draft.request.assertions;
+
+ item.draft.request.assertions = updateReorderedItem.map((uid) => {
+ return params.find((param) => param.uid === uid);
+ });
+ }
+ }
+ },
addVar: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
const type = action.payload.type;
@@ -1117,6 +1214,37 @@ export const collectionsSlice = createSlice({
}
}
},
+ moveVar: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+ const type = action.payload.type;
+
+ if (collection) {
+ const item = findItemInCollection(collection, action.payload.itemUid);
+
+ if (item && isItemARequest(item)) {
+ // Ensure item.draft is a deep clone of item if not already present
+ if (!item.draft) {
+ item.draft = cloneDeep(item);
+ }
+
+ // Extract payload data
+ const { updateReorderedItem } = action.payload;
+ if(type == "request"){
+ const params = item.draft.request.vars.req;
+
+ item.draft.request.vars.req = updateReorderedItem.map((uid) => {
+ return params.find((param) => param.uid === uid);
+ });
+ } else if (type === 'response') {
+ const params = item.draft.request.vars.res;
+
+ item.draft.request.vars.res = updateReorderedItem.map((uid) => {
+ return params.find((param) => param.uid === uid);
+ });
+ }
+ }
+ }
+ },
updateCollectionAuthMode: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
@@ -1144,6 +1272,9 @@ export const collectionsSlice = createSlice({
case 'digest':
set(collection, 'root.request.auth.digest', action.payload.content);
break;
+ case 'ntlm':
+ set(collection, 'root.request.auth.ntlm', action.payload.content);
+ break;
case 'oauth2':
set(collection, 'root.request.auth.oauth2', action.payload.content);
break;
@@ -1794,12 +1925,15 @@ export const {
addRequestHeader,
updateRequestHeader,
deleteRequestHeader,
+ moveRequestHeader,
addFormUrlEncodedParam,
updateFormUrlEncodedParam,
deleteFormUrlEncodedParam,
+ moveFormUrlEncodedParam,
addMultipartFormParam,
updateMultipartFormParam,
deleteMultipartFormParam,
+ moveMultipartFormParam,
updateRequestAuthMode,
updateRequestBodyMode,
updateRequestBody,
@@ -1812,9 +1946,11 @@ export const {
addAssertion,
updateAssertion,
deleteAssertion,
+ moveAssertion,
addVar,
updateVar,
deleteVar,
+ moveVar,
addFolderHeader,
updateFolderHeader,
deleteFolderHeader,
diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js
index d770c60a3c..bc6c731f4d 100644
--- a/packages/bruno-app/src/utils/collections/index.js
+++ b/packages/bruno-app/src/utils/collections/index.js
@@ -340,6 +340,13 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
password: get(si.request, 'auth.digest.password', '')
};
break;
+ case 'ntlm':
+ di.request.auth.ntlm = {
+ username: get(si.request, 'auth.ntlm.username', ''),
+ password: get(si.request, 'auth.ntlm.password', ''),
+ domain: get(si.request, 'auth.ntlm.domain', '')
+ };
+ break;
case 'oauth2':
let grantType = get(si.request, 'auth.oauth2.grantType', '');
switch (grantType) {
@@ -680,6 +687,10 @@ export const humanizeRequestAuthMode = (mode) => {
label = 'Digest Auth';
break;
}
+ case 'ntlm': {
+ label = 'NTLM';
+ break;
+ }
case 'oauth2': {
label = 'OAuth 2.0';
break;
diff --git a/packages/bruno-cli/package.json b/packages/bruno-cli/package.json
index adfc936589..8353e8ba83 100644
--- a/packages/bruno-cli/package.json
+++ b/packages/bruno-cli/package.json
@@ -50,8 +50,10 @@
"@usebruno/common": "0.1.0",
"@usebruno/js": "0.12.0",
"@usebruno/lang": "0.12.0",
+ "@usebruno/vm2": "^3.9.13",
"aws4-axios": "^3.3.0",
"axios": "1.7.5",
+ "axios-ntlm": "^1.4.2",
"chai": "^4.3.7",
"chalk": "^3.0.0",
"decomment": "^0.9.5",
diff --git a/packages/bruno-cli/src/runner/interpolate-vars.js b/packages/bruno-cli/src/runner/interpolate-vars.js
index 8e0ff300c5..88cee00cb5 100644
--- a/packages/bruno-cli/src/runner/interpolate-vars.js
+++ b/packages/bruno-cli/src/runner/interpolate-vars.js
@@ -165,6 +165,13 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc
request.awsv4config.profileName = _interpolate(request.awsv4config.profileName) || '';
}
+ // interpolate vars for ntlmConfig auth
+ if (request.ntlmConfig) {
+ request.ntlmConfig.username = _interpolate(request.ntlmConfig.username) || '';
+ request.ntlmConfig.password = _interpolate(request.ntlmConfig.password) || '';
+ request.ntlmConfig.domain = _interpolate(request.ntlmConfig.domain) || '';
+ }
+
if (request) return request;
};
diff --git a/packages/bruno-cli/src/runner/prepare-request.js b/packages/bruno-cli/src/runner/prepare-request.js
index 0ed8667609..11963bd296 100644
--- a/packages/bruno-cli/src/runner/prepare-request.js
+++ b/packages/bruno-cli/src/runner/prepare-request.js
@@ -36,7 +36,7 @@ const prepareRequest = (item = {}, collection = {}) => {
};
const collectionAuth = get(collection, 'root.request.auth');
- if (collectionAuth && request.auth.mode === 'inherit') {
+ if (collectionAuth && request.auth?.mode === 'inherit') {
if (collectionAuth.mode === 'basic') {
axiosRequest.auth = {
username: get(collectionAuth, 'basic.username'),
@@ -47,9 +47,27 @@ const prepareRequest = (item = {}, collection = {}) => {
if (collectionAuth.mode === 'bearer') {
axiosRequest.headers['Authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`;
}
+
+ if (collectionAuth.mode === 'apikey') {
+ if (collectionAuth.apikey?.placement === 'header') {
+ axiosRequest.headers[collectionAuth.apikey?.key] = collectionAuth.apikey?.value;
+ }
+
+ if (collectionAuth.apikey?.placement === 'queryparams') {
+ if (axiosRequest.url && collectionAuth.apikey?.key) {
+ try {
+ const urlObj = new URL(request.url);
+ urlObj.searchParams.set(collectionAuth.apikey?.key, collectionAuth.apikey?.value);
+ axiosRequest.url = urlObj.toString();
+ } catch (error) {
+ console.error('Invalid URL:', request.url, error);
+ }
+ }
+ }
+ }
}
- if (request.auth) {
+ if (request.auth && request.auth.mode !== 'inherit') {
if (request.auth.mode === 'basic') {
axiosRequest.auth = {
username: get(request, 'auth.basic.username'),
@@ -68,6 +86,14 @@ const prepareRequest = (item = {}, collection = {}) => {
};
}
+ if (request.auth.mode === 'ntlm') {
+ axiosRequest.ntlmConfig = {
+ username: get(request, 'auth.ntlm.username'),
+ password: get(request, 'auth.ntlm.password'),
+ domain: get(request, 'auth.ntlm.domain')
+ };
+ }
+
if (request.auth.mode === 'bearer') {
axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`;
}
diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js
index 29ed749b94..b2bbc3795d 100644
--- a/packages/bruno-cli/src/runner/run-single-request.js
+++ b/packages/bruno-cli/src/runner/run-single-request.js
@@ -23,6 +23,8 @@ const { parseDataFromResponse } = require('../utils/common');
const { getCookieStringForUrl, saveCookies, shouldUseCookies } = require('../utils/cookies');
const { createFormData } = require('../utils/form-data');
const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/;
+const { NtlmClient } = require('axios-ntlm');
+
const onConsoleLog = (type, args) => {
console[type](...args);
@@ -250,8 +252,13 @@ const runSingleRequest = async function (
let response, responseTime;
try {
- // run request
- const axiosInstance = makeAxiosInstance();
+
+ let axiosInstance = makeAxiosInstance();
+ if (request.ntlmConfig) {
+ axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance.defaults)
+ delete request.ntlmConfig;
+ }
+
if (request.awsv4config) {
// todo: make this happen in prepare-request.js
diff --git a/packages/bruno-cli/tests/runner/prepare-request.spec.js b/packages/bruno-cli/tests/runner/prepare-request.spec.js
index 37d3e34d30..ffc9986dfd 100644
--- a/packages/bruno-cli/tests/runner/prepare-request.spec.js
+++ b/packages/bruno-cli/tests/runner/prepare-request.spec.js
@@ -1,5 +1,4 @@
-const { describe, it, expect } = require('@jest/globals');
-
+const { describe, it, expect, beforeEach } = require('@jest/globals');
const prepareRequest = require('../../src/runner/prepare-request');
describe('prepare-request: prepareRequest', () => {
@@ -22,4 +21,144 @@ describe('prepare-request: prepareRequest', () => {
expect(result.data).toEqual(expected);
});
});
+
+ describe('Properly maps inherited auth from collectionRoot', () => {
+ // Initialize Test Fixtures
+ let collection, item;
+
+ beforeEach(() => {
+ collection = {
+ name: 'Test Collection',
+ root: {
+ request: {
+ auth: {}
+ }
+ }
+ };
+
+ item = {
+ name: 'Test Request',
+ type: 'http-request',
+ request: {
+ method: 'GET',
+ headers: [],
+ params: [],
+ url: 'https://usebruno.com',
+ auth: {
+ mode: 'inherit'
+ },
+ script: {
+ req: 'console.log("Pre Request")',
+ res: 'console.log("Post Response")'
+ }
+ }
+ };
+ });
+
+ describe('API Key Authentication', () => {
+ it('If collection auth is apikey in header', () => {
+ collection.root.request.auth = {
+ mode: "apikey",
+ apikey: {
+ key: "x-api-key",
+ value: "{{apiKey}}",
+ placement: "header"
+ }
+ };
+
+ const result = prepareRequest(item, collection);
+ expect(result.headers).toHaveProperty('x-api-key', '{{apiKey}}');
+ });
+
+ it('If collection auth is apikey in header and request has existing headers', () => {
+ collection.root.request.auth = {
+ mode: "apikey",
+ apikey: {
+ key: "x-api-key",
+ value: "{{apiKey}}",
+ placement: "header"
+ }
+ };
+
+ item.request.headers.push({ name: 'Content-Type', value: 'application/json', enabled: true });
+ const result = prepareRequest(item, collection);
+ expect(result.headers).toHaveProperty('Content-Type', 'application/json');
+ expect(result.headers).toHaveProperty('x-api-key', '{{apiKey}}');
+ });
+
+ it('If collection auth is apikey in query parameters', () => {
+ collection.root.request.auth = {
+ mode: "apikey",
+ apikey: {
+ key: "x-api-key",
+ value: "{{apiKey}}",
+ placement: "queryparams"
+ }
+ };
+
+ const urlObj = new URL(item.request.url);
+ urlObj.searchParams.set(collection.root.request.auth.apikey.key, collection.root.request.auth.apikey.value);
+
+ const expected = urlObj.toString();
+ const result = prepareRequest(item, collection);
+ expect(result.url).toEqual(expected);
+ });
+ });
+
+ describe('Basic Authentication', () => {
+ it('If collection auth is basic auth', () => {
+ collection.root.request.auth = {
+ mode: 'basic',
+ basic: {
+ username: 'testUser',
+ password: 'testPass123'
+ }
+ };
+
+ const result = prepareRequest(item, collection);
+ const expected = { username: 'testUser', password: 'testPass123' };
+ expect(result.auth).toEqual(expected);
+ });
+ });
+
+ describe('Bearer Token Authentication', () => {
+ it('If collection auth is bearer token', () => {
+ collection.root.request.auth = {
+ mode: 'bearer',
+ bearer: {
+ token: 'token'
+ }
+ };
+
+ const result = prepareRequest(item, collection);
+ expect(result.headers).toHaveProperty('Authorization', 'Bearer token');
+ });
+
+ it('If collection auth is bearer token and request has existing headers', () => {
+ collection.root.request.auth = {
+ mode: 'bearer',
+ bearer: {
+ token: 'token'
+ }
+ };
+
+ item.request.headers.push({ name: 'Content-Type', value: 'application/json', enabled: true });
+
+ const result = prepareRequest(item, collection);
+ expect(result.headers).toHaveProperty('Authorization', 'Bearer token');
+ expect(result.headers).toHaveProperty('Content-Type', 'application/json');
+ });
+ });
+
+ describe('No Authentication', () => {
+ it('If request does not have auth configured', () => {
+ delete item.request.auth;
+ let result;
+ expect(() => {
+ result = prepareRequest(item, collection);
+ }).not.toThrow();
+ expect(result).toBeDefined();
+ });
+ });
+ });
});
diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json
index 7e8e255649..16a032b3a8 100644
--- a/packages/bruno-electron/package.json
+++ b/packages/bruno-electron/package.json
@@ -1,5 +1,5 @@
{
- "version": "v1.36.0",
+ "version": "v1.38.1",
"name": "bruno",
"description": "Opensource API Client for Exploring and Testing APIs",
"homepage": "https://www.usebruno.com",
@@ -19,7 +19,9 @@
"test": "node --experimental-vm-modules $(npx which jest)"
},
"jest": {
- "modulePaths": ["node_modules"]
+ "modulePaths": [
+ "node_modules"
+ ]
},
"dependencies": {
"@aws-sdk/credential-providers": "3.658.1",
@@ -28,9 +30,11 @@
"@usebruno/lang": "0.12.0",
"@usebruno/node-machine-id": "^2.0.0",
"@usebruno/schema": "0.7.0",
+ "@usebruno/vm2": "^3.9.13",
"about-window": "^1.15.2",
"aws4-axios": "^3.3.0",
"axios": "1.7.5",
+ "axios-ntlm": "^1.4.2",
"chai": "^4.3.7",
"chokidar": "^3.5.3",
"content-disposition": "^0.5.4",
@@ -55,7 +59,6 @@
"socks-proxy-agent": "^8.0.2",
"tough-cookie": "^4.1.3",
"uuid": "^9.0.0",
- "@usebruno/vm2": "^3.9.13",
"yup": "^0.32.11"
},
"optionalDependencies": {
diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js
index 782878c59a..218fadf380 100644
--- a/packages/bruno-electron/src/ipc/network/index.js
+++ b/packages/bruno-electron/src/ipc/network/index.js
@@ -40,6 +40,7 @@ const iconv = require('iconv-lite');
const FormData = require('form-data');
const { createFormData } = require('../../utils/form-data');
const { findItemInCollectionByPathname } = require('../../utils/collection');
+const { NtlmClient } = require('axios-ntlm');
const safeStringifyJSON = (data) => {
try {
@@ -272,7 +273,15 @@ const configureRequest = async (
...httpsAgentRequestFields
});
}
- const axiosInstance = makeAxiosInstance();
+
+
+ let axiosInstance = makeAxiosInstance();
+
+ if (request.ntlmConfig) {
+ axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance.defaults)
+ delete request.ntlmConfig;
+ }
+
if (request.oauth2) {
let requestCopy = cloneDeep(request);
diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
index d9833f59a0..2b46327afb 100644
--- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js
+++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
@@ -231,6 +231,14 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc
request.wsse.password = _interpolate(request.wsse.password) || '';
}
+
+ // interpolate vars for ntlmConfig auth
+ if (request.ntlmConfig) {
+ request.ntlmConfig.username = _interpolate(request.ntlmConfig.username) || '';
+ request.ntlmConfig.password = _interpolate(request.ntlmConfig.password) || '';
+ request.ntlmConfig.domain = _interpolate(request.ntlmConfig.domain) || '';
+ }
+
return request;
};
diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js
index 69825bc4e1..6c7672e7d6 100644
--- a/packages/bruno-electron/src/ipc/network/prepare-request.js
+++ b/packages/bruno-electron/src/ipc/network/prepare-request.js
@@ -5,6 +5,7 @@ const { getTreePathFromCollectionToItem, mergeHeaders, mergeScripts, mergeVars }
const { buildFormUrlEncodedPayload, createFormData } = require('../../utils/form-data');
const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
+
const collectionAuth = get(collectionRoot, 'request.auth');
if (collectionAuth && request.auth.mode === 'inherit') {
switch (collectionAuth.mode) {
@@ -33,6 +34,13 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
password: get(collectionAuth, 'digest.password')
};
break;
+ case 'ntlm':
+ axiosRequest.ntlmConfig = {
+ username: get(collectionAuth, 'ntlm.username'),
+ password: get(collectionAuth, 'ntlm.password'),
+ domain: get(collectionAuth, 'ntlm.domain')
+ };
+ break;
case 'wsse':
const username = get(request, 'auth.wsse.username', '');
const password = get(request, 'auth.wsse.password', '');
@@ -89,6 +97,13 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
password: get(request, 'auth.digest.password')
};
break;
+ case 'ntlm':
+ axiosRequest.ntlmConfig = {
+ username: get(request, 'auth.ntlm.username'),
+ password: get(request, 'auth.ntlm.password'),
+ domain: get(request, 'auth.ntlm.domain')
+ };
+ break;
case 'oauth2':
const grantType = get(request, 'auth.oauth2.grantType');
switch (grantType) {
diff --git a/packages/bruno-js/src/sandbox/quickjs/index.js b/packages/bruno-js/src/sandbox/quickjs/index.js
index d5fe5e8f3b..58ccd885d0 100644
--- a/packages/bruno-js/src/sandbox/quickjs/index.js
+++ b/packages/bruno-js/src/sandbox/quickjs/index.js
@@ -22,12 +22,6 @@ const toNumber = (value) => {
return Number.isInteger(num) ? parseInt(value, 10) : parseFloat(value);
};
-const removeQuotes = (str) => {
- if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) {
- return str.slice(1, -1);
- }
- return str;
-};
const executeQuickJsVm = ({ script: externalScript, context: externalContext, scriptType = 'template-literal' }) => {
if (!externalScript?.length || typeof externalScript !== 'string') {
@@ -44,7 +38,6 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc
if (externalScript === 'null') return null;
if (externalScript === 'undefined') return undefined;
- externalScript = removeQuotes(externalScript);
const vm = QuickJSSyncContext;
@@ -94,7 +87,6 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external
if (externalScript === 'null') return null;
if (externalScript === 'undefined') return undefined;
- externalScript = removeQuotes(externalScript);
try {
const module = await newQuickJSWASMModule();
diff --git a/packages/bruno-js/src/utils.js b/packages/bruno-js/src/utils.js
index 55b454d02a..6b5ecacb57 100644
--- a/packages/bruno-js/src/utils.js
+++ b/packages/bruno-js/src/utils.js
@@ -85,14 +85,6 @@ const evaluateJsTemplateLiteral = (templateLiteral, context) => {
return undefined;
}
- if (templateLiteral.startsWith('"') && templateLiteral.endsWith('"')) {
- return templateLiteral.slice(1, -1);
- }
-
- if (templateLiteral.startsWith("'") && templateLiteral.endsWith("'")) {
- return templateLiteral.slice(1, -1);
- }
-
if (!isNaN(templateLiteral)) {
const number = Number(templateLiteral);
// Check if the number is too high. Too high number might get altered, see #1000
diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js
index 228691c1b2..2fe5fb472a 100644
--- a/packages/bruno-lang/v2/src/bruToJson.js
+++ b/packages/bruno-lang/v2/src/bruToJson.js
@@ -23,7 +23,7 @@ const { outdentString } = require('../../v1/src/utils');
*/
const grammar = ohm.grammar(`Bru {
BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs)*
- auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2 | authwsse | authapikey
+ auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM | authOAuth2 | authwsse | authapikey
bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body
bodyforms = bodyformurlencoded | bodymultipart
params = paramspath | paramsquery
@@ -87,6 +87,7 @@ const grammar = ohm.grammar(`Bru {
authbasic = "auth:basic" dictionary
authbearer = "auth:bearer" dictionary
authdigest = "auth:digest" dictionary
+ authNTLM = "auth:ntlm" dictionary
authOAuth2 = "auth:oauth2" dictionary
authwsse = "auth:wsse" dictionary
authapikey = "auth:apikey" dictionary
@@ -450,6 +451,26 @@ const sem = grammar.createSemantics().addAttribute('ast', {
}
};
},
+ authNTLM(_1, dictionary) {
+ const auth = mapPairListToKeyValPairs(dictionary.ast, false);
+ const usernameKey = _.find(auth, { name: 'username' });
+ const passwordKey = _.find(auth, { name: 'password' });
+ const domainKey = _.find(auth, { name: 'domain' });
+
+ const username = usernameKey ? usernameKey.value : '';
+ const password = passwordKey ? passwordKey.value : '';
+ const domain = passwordKey ? domainKey.value : '';
+
+ return {
+ auth: {
+ ntlm: {
+ username,
+ password,
+ domain
+ }
+ }
+ };
+ },
authOAuth2(_1, dictionary) {
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
const grantTypeKey = _.find(auth, { name: 'grant_type' });
diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js
index 5180f0193d..61d373d91e 100644
--- a/packages/bruno-lang/v2/src/collectionBruToJson.js
+++ b/packages/bruno-lang/v2/src/collectionBruToJson.js
@@ -4,7 +4,7 @@ const { outdentString } = require('../../v1/src/utils');
const grammar = ohm.grammar(`Bru {
BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs)*
- auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2 | authwsse | authapikey
+ auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM |authOAuth2 | authwsse | authapikey
nl = "\\r"? "\\n"
st = " " | "\\t"
@@ -42,6 +42,7 @@ const grammar = ohm.grammar(`Bru {
authbasic = "auth:basic" dictionary
authbearer = "auth:bearer" dictionary
authdigest = "auth:digest" dictionary
+ authNTLM = "auth:ntlm" dictionary
authOAuth2 = "auth:oauth2" dictionary
authwsse = "auth:wsse" dictionary
authapikey = "auth:apikey" dictionary
@@ -245,6 +246,26 @@ const sem = grammar.createSemantics().addAttribute('ast', {
}
};
},
+ authNTLM(_1, dictionary) {
+ const auth = mapPairListToKeyValPairs(dictionary.ast, false);
+ const usernameKey = _.find(auth, { name: 'username' });
+ const passwordKey = _.find(auth, { name: 'password' });
+ const domainKey = _.find(auth, { name: 'domain' });
+
+ const username = usernameKey ? usernameKey.value : '';
+ const password = passwordKey ? passwordKey.value : '';
+ const domain = domainKey ? domainKey.value : '';
+
+ return {
+ auth: {
+ ntlm: {
+ username,
+ password,
+ domain
+ }
+ }
+ };
+ },
authOAuth2(_1, dictionary) {
const auth = mapPairListToKeyValPairs(dictionary.ast, false);
const grantTypeKey = _.find(auth, { name: 'grant_type' });
diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js
index 5c8a573b62..62b31c2f99 100644
--- a/packages/bruno-lang/v2/src/jsonToBru.js
+++ b/packages/bruno-lang/v2/src/jsonToBru.js
@@ -165,6 +165,18 @@ ${indentString(`password: ${auth?.digest?.password || ''}`)}
`;
}
+
+ if (auth && auth.ntlm) {
+ bru += `auth:ntlm {
+${indentString(`username: ${auth?.ntlm?.username || ''}`)}
+${indentString(`password: ${auth?.ntlm?.password || ''}`)}
+${indentString(`domain: ${auth?.ntlm?.domain || ''}`)}
+
+}
+
+`;
+ }
+
if (auth && auth.oauth2) {
switch (auth?.oauth2?.grantType) {
case 'password':
diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js
index 8b162b7a6f..c2a843dc6e 100644
--- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js
+++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js
@@ -120,6 +120,17 @@ ${indentString(`username: ${auth.digest.username}`)}
${indentString(`password: ${auth.digest.password}`)}
}
+`;
+ }
+
+if (auth && auth.ntlm) {
+ bru += `auth:ntlm {
+${indentString(`username: ${auth.ntlm.username}`)}
+${indentString(`password: ${auth.ntlm.password}`)}
+${indentString(`domain: ${auth.ntlm.domain}`)}
+
+}
+
`;
}
diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js
index 3d5959f15d..b6e044ae47 100644
--- a/packages/bruno-schema/src/collections/index.js
+++ b/packages/bruno-schema/src/collections/index.js
@@ -127,6 +127,17 @@ const authDigestSchema = Yup.object({
.noUnknown(true)
.strict();
+
+
+ const authNTLMSchema = Yup.object({
+ username: Yup.string().nullable(),
+ password: Yup.string().nullable(),
+ domain: Yup.string().nullable()
+
+ })
+ .noUnknown(true)
+ .strict();
+
const authApiKeySchema = Yup.object({
key: Yup.string().nullable(),
value: Yup.string().nullable(),
@@ -195,11 +206,12 @@ const oauth2Schema = Yup.object({
const authSchema = Yup.object({
mode: Yup.string()
- .oneOf(['inherit', 'none', 'awsv4', 'basic', 'bearer', 'digest', 'oauth2', 'wsse', 'apikey'])
+ .oneOf(['inherit', 'none', 'awsv4', 'basic', 'bearer', 'digest', 'ntlm', 'oauth2', 'wsse', 'apikey'])
.required('mode is required'),
awsv4: authAwsV4Schema.nullable(),
basic: authBasicSchema.nullable(),
bearer: authBearerSchema.nullable(),
+ ntlm: authNTLMSchema.nullable(),
digest: authDigestSchema.nullable(),
oauth2: oauth2Schema.nullable(),
wsse: authWsseSchema.nullable(),
|