diff --git a/package-lock.json b/package-lock.json
index e2a22b456a..47beab0320 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"packages/bruno-graphql-docs"
],
"dependencies": {
+ "axios-ntlm": "^1.4.2",
"json-bigint": "^1.0.0",
"lossless-json": "^4.0.1"
},
@@ -7158,6 +7159,18 @@
"proxy-from-env": "^1.1.0"
}
},
+ "node_modules/axios-ntlm": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/axios-ntlm/-/axios-ntlm-1.4.2.tgz",
+ "integrity": "sha512-8mS/uhmSWiRBiFKQvysPbX1eDBp6e+eXskmasuAXRHrn1Zjgji3O/oGXzXLw7tOhyD9nho1vGjZ2OYOD3cCvHg==",
+ "license": "MIT",
+ "dependencies": {
+ "axios": "^1.6.1",
+ "des.js": "^1.1.0",
+ "dev-null": "^0.1.1",
+ "js-md4": "^0.3.2"
+ }
+ },
"node_modules/babel-jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
@@ -9240,6 +9253,16 @@
"node": ">=6"
}
},
+ "node_modules/des.js": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
+ "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
@@ -9279,6 +9302,12 @@
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
},
+ "node_modules/dev-null": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz",
+ "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==",
+ "license": "MIT"
+ },
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -13146,6 +13175,12 @@
"jiti": "bin/jiti.js"
}
},
+ "node_modules/js-md4": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz",
+ "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==",
+ "license": "MIT"
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -14033,6 +14068,12 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "license": "ISC"
+ },
"node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
@@ -19830,7 +19871,7 @@
},
"packages/bruno-electron": {
"name": "bruno",
- "version": "v1.33.0",
+ "version": "v1.33.1",
"dependencies": {
"@aws-sdk/credential-providers": "3.658.1",
"@usebruno/common": "0.1.0",
diff --git a/package.json b/package.json
index 3d8a31df2b..1732bb1769 100644
--- a/package.json
+++ b/package.json
@@ -51,9 +51,10 @@
"prepare": "husky install"
},
"overrides": {
- "rollup":"3.29.5"
+ "rollup": "3.29.5"
},
"dependencies": {
+ "axios-ntlm": "^1.4.2",
"json-bigint": "^1.0.0",
"lossless-json": "^4.0.1"
}
diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js
index 7dabb4c71a..2c541cc289 100644
--- a/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js
+++ b/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js
@@ -79,6 +79,15 @@ const AuthMode = ({ collection }) => {
>
Digest Auth
+
{
+ dropdownTippyRef.current.hide();
+ onModeChange('ntlm');
+ }}
+ >
+ NTLM Auth
+
{
diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js
new file mode 100644
index 0000000000..316d3a7c5f
--- /dev/null
+++ b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js
@@ -0,0 +1,17 @@
+import styled from 'styled-components';
+
+const Wrapper = styled.div`
+ label {
+ font-size: 0.8125rem;
+ }
+
+ .single-line-editor-wrapper {
+ max-width: 400px;
+ padding: 0.15rem 0.4rem;
+ border-radius: 3px;
+ border: solid 1px ${(props) => props.theme.input.border};
+ background-color: ${(props) => props.theme.input.bg};
+ }
+`;
+
+export default Wrapper;
diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js
new file mode 100644
index 0000000000..341c805dcf
--- /dev/null
+++ b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js
@@ -0,0 +1,110 @@
+import React from 'react';
+import get from 'lodash/get';
+import { useTheme } from 'providers/Theme';
+import { useDispatch } from 'react-redux';
+import SingleLineEditor from 'components/SingleLineEditor';
+import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections';
+import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
+import StyledWrapper from './StyledWrapper';
+
+
+
+
+
+const NTLMAuth = ({ collection }) => {
+
+
+ const dispatch = useDispatch();
+ const { storedTheme } = useTheme();
+
+ const ntlmAuth = get(collection, 'root.request.auth.ntlm', {});
+
+ const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
+
+
+ const handleUsernameChange = (username) => {
+ dispatch(
+ updateCollectionAuth({
+ mode: 'ntlm',
+ collectionUid: collection.uid,
+ content: {
+ username: username,
+ password: ntlmAuth.password,
+ domain: ntlmAuth.domain
+
+ }
+ })
+ );
+ };
+
+ const handlePasswordChange = (password) => {
+ dispatch(
+ updateCollectionAuth({
+ mode: 'ntlm',
+ collectionUid: collection.uid,
+ content: {
+ username: ntlmAuth.username,
+ password: password,
+ domain: ntlmAuth.domain
+ }
+ })
+ );
+ };
+
+ const handleDomainChange = (domain) => {
+ dispatch(
+ updateCollectionAuth({
+ mode: 'ntlm',
+ collectionUid: collection.uid,
+ content: {
+ username: ntlmAuth.username,
+ password: ntlmAuth.password,
+ domain: domain
+ }
+ })
+ );
+ };
+
+
+
+
+ return (
+
+
+
+ handleUsernameChange(val)}
+ collection={collection}
+ />
+
+
+
+
+ handlePasswordChange(val)}
+ collection={collection}
+ isSecret={true}
+ />
+
+
+
+
+ handleDomainChange(val)}
+ collection={collection}
+ />
+
+
+ );
+};
+
+export default NTLMAuth;
diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/index.js
index 05efc17b23..c19ae98738 100644
--- a/packages/bruno-app/src/components/CollectionSettings/Auth/index.js
+++ b/packages/bruno-app/src/components/CollectionSettings/Auth/index.js
@@ -11,6 +11,8 @@ import ApiKeyAuth from './ApiKeyAuth/';
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
import OAuth2 from './OAuth2';
+import NTLMAuth from './NTLMAuth';
+
const Auth = ({ collection }) => {
const authMode = get(collection, 'root.request.auth.mode');
@@ -32,6 +34,9 @@ const Auth = ({ collection }) => {
case 'digest': {
return
;
}
+ case 'ntlm': {
+ return
;
+ }
case 'oauth2': {
return
;
}
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js
index dfbaba7fa0..1e3bedc2f3 100644
--- a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js
+++ b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js
@@ -70,6 +70,15 @@ const AuthMode = ({ item, collection }) => {
>
Digest Auth
+ {
+ dropdownTippyRef?.current?.hide();
+ onModeChange('ntlm');
+ }}
+ >
+ NTLM Auth
+
{
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js
new file mode 100644
index 0000000000..316d3a7c5f
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js
@@ -0,0 +1,17 @@
+import styled from 'styled-components';
+
+const Wrapper = styled.div`
+ label {
+ font-size: 0.8125rem;
+ }
+
+ .single-line-editor-wrapper {
+ max-width: 400px;
+ padding: 0.15rem 0.4rem;
+ border-radius: 3px;
+ border: solid 1px ${(props) => props.theme.input.border};
+ background-color: ${(props) => props.theme.input.bg};
+ }
+`;
+
+export default Wrapper;
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js
new file mode 100644
index 0000000000..65e7560418
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js
@@ -0,0 +1,110 @@
+import React from 'react';
+import get from 'lodash/get';
+import { useTheme } from 'providers/Theme';
+import { useDispatch } from 'react-redux';
+import SingleLineEditor from 'components/SingleLineEditor';
+import { updateAuth } from 'providers/ReduxStore/slices/collections';
+import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
+import StyledWrapper from './StyledWrapper';
+
+const NTLMAuth = ({ item, collection }) => {
+ const dispatch = useDispatch();
+ const { storedTheme } = useTheme();
+
+ const ntlmAuth = item.draft ? get(item, 'draft.request.auth.ntlm', {}) : get(item, 'request.auth.ntlm', {});
+
+ const handleRun = () => dispatch(sendRequest(item, collection.uid));
+ const handleSave = () => dispatch(saveRequest(item.uid, collection.uid));
+
+ const handleUsernameChange = (username) => {
+ dispatch(
+ updateAuth({
+ mode: 'ntlm',
+ collectionUid: collection.uid,
+ itemUid: item.uid,
+ content: {
+ username: username,
+ password: ntlmAuth.password,
+ domain: ntlmAuth.domain
+
+ }
+ })
+ );
+ };
+
+ const handlePasswordChange = (password) => {
+ dispatch(
+ updateAuth({
+ mode: 'ntlm',
+ collectionUid: collection.uid,
+ itemUid: item.uid,
+ content: {
+ username: ntlmAuth.username,
+ password: password,
+ domain: ntlmAuth.domain
+ }
+ })
+ );
+ };
+
+ const handleDomainChange = (domain) => {
+ dispatch(
+ updateAuth({
+ mode: 'ntlm',
+ collectionUid: collection.uid,
+ itemUid: item.uid,
+ content: {
+ username: ntlmAuth.username,
+ password: ntlmAuth.password,
+ domain: domain
+ }
+ })
+ );
+ };
+
+ return (
+
+
+
+ handleUsernameChange(val)}
+ onRun={handleRun}
+ collection={collection}
+ item={item}
+ />
+
+
+
+
+ handlePasswordChange(val)}
+ onRun={handleRun}
+ collection={collection}
+ item={item}
+ isSecret={true}
+ />
+
+
+
+
+ handleDomainChange(val)}
+ onRun={handleRun}
+ collection={collection}
+ item={item}
+ />
+
+
+ );
+};
+
+export default NTLMAuth;
diff --git a/packages/bruno-app/src/components/RequestPane/Auth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/index.js
index 1515e5224f..743d23267e 100644
--- a/packages/bruno-app/src/components/RequestPane/Auth/index.js
+++ b/packages/bruno-app/src/components/RequestPane/Auth/index.js
@@ -6,6 +6,8 @@ import BearerAuth from './BearerAuth';
import BasicAuth from './BasicAuth';
import DigestAuth from './DigestAuth';
import WsseAuth from './WsseAuth';
+import NTLMAuth from './NTLMAuth';
+
import ApiKeyAuth from './ApiKeyAuth';
import StyledWrapper from './StyledWrapper';
import { humanizeRequestAuthMode } from 'utils/collections/index';
@@ -31,6 +33,9 @@ const Auth = ({ item, collection }) => {
case 'digest': {
return
;
}
+ case 'ntlm': {
+ return
;
+ }
case 'oauth2': {
return
;
}
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 b7ef2f86e5..1f7b026e17 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;
@@ -1142,6 +1146,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;
diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js
index cd925054d4..d206981c0b 100644
--- a/packages/bruno-app/src/utils/collections/index.js
+++ b/packages/bruno-app/src/utils/collections/index.js
@@ -339,6 +339,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) {
@@ -674,6 +681,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 5020f8475a..167706f618 100644
--- a/packages/bruno-cli/package.json
+++ b/packages/bruno-cli/package.json
@@ -28,8 +28,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",
@@ -41,7 +43,6 @@
"lodash": "^4.17.21",
"qs": "^6.11.0",
"socks-proxy-agent": "^8.0.2",
- "@usebruno/vm2": "^3.9.13",
"xmlbuilder": "^15.1.1",
"yargs": "^17.6.2"
}
diff --git a/packages/bruno-cli/src/runner/interpolate-vars.js b/packages/bruno-cli/src/runner/interpolate-vars.js
index 2b727e671f..e41e489e85 100644
--- a/packages/bruno-cli/src/runner/interpolate-vars.js
+++ b/packages/bruno-cli/src/runner/interpolate-vars.js
@@ -158,6 +158,13 @@ const interpolateVars = (request, envVars = {}, runtimeVariables = {}, processEn
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 bc2b228866..69c98dd57d 100644
--- a/packages/bruno-cli/src/runner/prepare-request.js
+++ b/packages/bruno-cli/src/runner/prepare-request.js
@@ -67,6 +67,14 @@ const prepareRequest = (request, collectionRoot) => {
};
}
+ 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 cb59c78ba5..330eac26b0 100644
--- a/packages/bruno-cli/src/runner/run-single-request.js
+++ b/packages/bruno-cli/src/runner/run-single-request.js
@@ -21,6 +21,8 @@ const { shouldUseProxy, PatchedHttpsProxyAgent } = require('../utils/proxy-util'
const path = require('path');
const { createFormData } = require('../utils/common');
const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/;
+const { NtlmClient } = require('axios-ntlm');
+
const onConsoleLog = (type, args) => {
console[type](...args);
@@ -193,8 +195,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)
+ delete request.ntlmConfig;
+ }
+
if (request.awsv4config) {
// todo: make this happen in prepare-request.js
diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json
index 9c4307a5df..26715d0132 100644
--- a/packages/bruno-electron/package.json
+++ b/packages/bruno-electron/package.json
@@ -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",
@@ -56,7 +60,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 97e3b8557a..53261aaa0a 100644
--- a/packages/bruno-electron/src/ipc/network/index.js
+++ b/packages/bruno-electron/src/ipc/network/index.js
@@ -39,6 +39,7 @@ const Oauth2Store = require('../../store/oauth2');
const iconv = require('iconv-lite');
const FormData = require('form-data');
const { createFormData } = prepareRequest;
+const { NtlmClient } = require('axios-ntlm');
const safeStringifyJSON = (data) => {
try {
@@ -263,7 +264,15 @@ const configureRequest = async (
...httpsAgentRequestFields
});
}
- const axiosInstance = makeAxiosInstance();
+
+
+ let axiosInstance = makeAxiosInstance();
+
+ if (request.ntlmConfig) {
+ axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance)
+ 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 59f4944169..1f2b0b2ff2 100644
--- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js
+++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
@@ -230,6 +230,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 c8b36bb89f..e920e2f15e 100644
--- a/packages/bruno-electron/src/ipc/network/prepare-request.js
+++ b/packages/bruno-electron/src/ipc/network/prepare-request.js
@@ -191,6 +191,7 @@ const createFormData = (datas, collectionPath) => {
};
const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
+
const collectionAuth = get(collectionRoot, 'request.auth');
if (collectionAuth && request.auth.mode === 'inherit') {
switch (collectionAuth.mode) {
@@ -219,6 +220,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', '');
@@ -275,6 +283,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-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js
index c84d36d073..e0b0cf58ad 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
@@ -435,6 +436,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 8d3a5fdee8..8be05c50d0 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 11561c5284..4a812e35a4 100644
--- a/packages/bruno-schema/src/collections/index.js
+++ b/packages/bruno-schema/src/collections/index.js
@@ -126,6 +126,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(),
@@ -194,11 +205,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(),