Add @usebruno/requests package with digest authentication support (#4417)

* Add @usebruno/requests package with digest authentication support
---------

Co-authored-by: sanjai0py <sanjailucifer666@gmail.com>
Co-authored-by: ramki-bruno <ramki@usebruno.com>
This commit is contained in:
Sanjai Kumar 2025-04-10 14:49:21 +05:30 committed by GitHub
parent 838f25b9db
commit 2dd0424d8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 209 additions and 7 deletions

View File

@ -29,6 +29,7 @@ jobs:
npm run build --workspace=packages/bruno-query npm run build --workspace=packages/bruno-query
npm run sandbox:bundle-libraries --workspace=packages/bruno-js npm run sandbox:bundle-libraries --workspace=packages/bruno-js
npm run build --workspace=packages/bruno-converters npm run build --workspace=packages/bruno-converters
npm run build --workspace=packages/bruno-requests
# tests # tests
- name: Test Package bruno-js - name: Test Package bruno-js
@ -75,6 +76,7 @@ jobs:
npm run build --workspace=packages/bruno-common npm run build --workspace=packages/bruno-common
npm run sandbox:bundle-libraries --workspace=packages/bruno-js npm run sandbox:bundle-libraries --workspace=packages/bruno-js
npm run build --workspace=packages/bruno-converters npm run build --workspace=packages/bruno-converters
npm run build --workspace=packages/bruno-requests
- name: Run tests - name: Run tests
run: | run: |

23
package-lock.json generated
View File

@ -17,7 +17,8 @@
"packages/bruno-lang", "packages/bruno-lang",
"packages/bruno-tests", "packages/bruno-tests",
"packages/bruno-toml", "packages/bruno-toml",
"packages/bruno-graphql-docs" "packages/bruno-graphql-docs",
"packages/bruno-requests"
], ],
"devDependencies": { "devDependencies": {
"@faker-js/faker": "^7.6.0", "@faker-js/faker": "^7.6.0",
@ -7992,6 +7993,10 @@
"resolved": "packages/bruno-query", "resolved": "packages/bruno-query",
"link": true "link": true
}, },
"node_modules/@usebruno/requests": {
"resolved": "packages/bruno-requests",
"link": true
},
"node_modules/@usebruno/schema": { "node_modules/@usebruno/schema": {
"resolved": "packages/bruno-schema", "resolved": "packages/bruno-schema",
"link": true "link": true
@ -26431,6 +26436,7 @@
"@usebruno/js": "0.12.0", "@usebruno/js": "0.12.0",
"@usebruno/lang": "0.12.0", "@usebruno/lang": "0.12.0",
"@usebruno/node-machine-id": "^2.0.0", "@usebruno/node-machine-id": "^2.0.0",
"@usebruno/requests": "^0.1.0",
"@usebruno/schema": "0.7.0", "@usebruno/schema": "0.7.0",
"@usebruno/vm2": "^3.9.13", "@usebruno/vm2": "^3.9.13",
"about-window": "^1.15.2", "about-window": "^1.15.2",
@ -27705,6 +27711,21 @@
"typescript": "^4.8.4" "typescript": "^4.8.4"
} }
}, },
"packages/bruno-requests": {
"name": "@usebruno/requests",
"version": "0.1.0",
"license": "MIT",
"devDependencies": {
"@rollup/plugin-commonjs": "^23.0.2",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-typescript": "^9.0.2",
"rollup": "3.29.5",
"rollup-plugin-dts": "^5.0.0",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-terser": "^7.0.2",
"typescript": "^4.8.4"
}
},
"packages/bruno-schema": { "packages/bruno-schema": {
"name": "@usebruno/schema", "name": "@usebruno/schema",
"version": "0.7.0", "version": "0.7.0",

View File

@ -13,7 +13,8 @@
"packages/bruno-lang", "packages/bruno-lang",
"packages/bruno-tests", "packages/bruno-tests",
"packages/bruno-toml", "packages/bruno-toml",
"packages/bruno-graphql-docs" "packages/bruno-graphql-docs",
"packages/bruno-requests"
], ],
"homepage": "https://usebruno.com", "homepage": "https://usebruno.com",
"devDependencies": { "devDependencies": {
@ -39,6 +40,7 @@
"dev:electron": "npm run dev --workspace=packages/bruno-electron", "dev:electron": "npm run dev --workspace=packages/bruno-electron",
"dev:electron:debug": "npm run debug --workspace=packages/bruno-electron", "dev:electron:debug": "npm run debug --workspace=packages/bruno-electron",
"build:bruno-common": "npm run build --workspace=packages/bruno-common", "build:bruno-common": "npm run build --workspace=packages/bruno-common",
"build:bruno-requests": "npm run build --workspace=packages/bruno-requests",
"build:bruno-converters": "npm run build --workspace=packages/bruno-converters", "build:bruno-converters": "npm run build --workspace=packages/bruno-converters",
"build:bruno-query": "npm run build --workspace=packages/bruno-query", "build:bruno-query": "npm run build --workspace=packages/bruno-query",
"build:graphql-docs": "npm run build --workspace=packages/bruno-graphql-docs", "build:graphql-docs": "npm run build --workspace=packages/bruno-graphql-docs",

View File

@ -51,6 +51,7 @@
"@usebruno/js": "0.12.0", "@usebruno/js": "0.12.0",
"@usebruno/lang": "0.12.0", "@usebruno/lang": "0.12.0",
"@usebruno/vm2": "^3.9.13", "@usebruno/vm2": "^3.9.13",
"@usebruno/requests": "^0.1.0",
"aws4-axios": "^3.3.0", "aws4-axios": "^3.3.0",
"axios": "^1.8.3", "axios": "^1.8.3",
"axios-ntlm": "^1.4.2", "axios-ntlm": "^1.4.2",

View File

@ -65,6 +65,13 @@ const prepareRequest = (item = {}, collection = {}) => {
} }
} }
} }
if (collectionAuth.mode === 'digest') {
axiosRequest.digestConfig = {
username: get(collectionAuth, 'digest.username'),
password: get(collectionAuth, 'digest.password')
};
}
} }
if (request.auth && request.auth.mode !== 'inherit') { if (request.auth && request.auth.mode !== 'inherit') {
@ -115,6 +122,13 @@ const prepareRequest = (item = {}, collection = {}) => {
'X-WSSE' 'X-WSSE'
] = `UsernameToken Username="${username}", PasswordDigest="${digest}", Nonce="${nonce}", Created="${ts}"`; ] = `UsernameToken Username="${username}", PasswordDigest="${digest}", Nonce="${nonce}", Created="${ts}"`;
} }
if (request.auth.mode === 'digest') {
axiosRequest.digestConfig = {
username: get(request, 'auth.digest.username'),
password: get(request, 'auth.digest.password')
};
}
} }
request.body = request.body || {}; request.body = request.body || {};

View File

@ -24,7 +24,7 @@ const { getCookieStringForUrl, saveCookies, shouldUseCookies } = require('../uti
const { createFormData } = require('../utils/form-data'); const { createFormData } = require('../utils/form-data');
const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/; const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/;
const { NtlmClient } = require('axios-ntlm'); const { NtlmClient } = require('axios-ntlm');
const { addDigestInterceptor } = require('@usebruno/requests');
const onConsoleLog = (type, args) => { const onConsoleLog = (type, args) => {
console[type](...args); console[type](...args);
@ -333,6 +333,11 @@ const runSingleRequest = async function (
delete request.awsv4config; delete request.awsv4config;
} }
if (request.digestConfig) {
addDigestInterceptor(axiosInstance, request);
delete request.digestConfig;
}
/** @type {import('axios').AxiosResponse} */ /** @type {import('axios').AxiosResponse} */
response = await axiosInstance(request); response = await axiosInstance(request);

View File

@ -33,6 +33,7 @@
"@usebruno/node-machine-id": "^2.0.0", "@usebruno/node-machine-id": "^2.0.0",
"@usebruno/schema": "0.7.0", "@usebruno/schema": "0.7.0",
"@usebruno/vm2": "^3.9.13", "@usebruno/vm2": "^3.9.13",
"@usebruno/requests": "^0.1.0",
"about-window": "^1.15.2", "about-window": "^1.15.2",
"aws4-axios": "^3.3.0", "aws4-axios": "^3.3.0",
"axios": "^1.8.3", "axios": "^1.8.3",

View File

@ -14,7 +14,7 @@ const { NtlmClient } = require('axios-ntlm');
const { VarsRuntime, AssertRuntime, ScriptRuntime, TestRuntime } = require('@usebruno/js'); const { VarsRuntime, AssertRuntime, ScriptRuntime, TestRuntime } = require('@usebruno/js');
const { interpolateString } = require('./interpolate-string'); const { interpolateString } = require('./interpolate-string');
const { resolveAwsV4Credentials, addAwsV4Interceptor } = require('./awsv4auth-helper'); const { resolveAwsV4Credentials, addAwsV4Interceptor } = require('./awsv4auth-helper');
const { addDigestInterceptor } = require('./digestauth-helper'); const { addDigestInterceptor } = require('@usebruno/requests');
const prepareGqlIntrospectionRequest = require('./prepare-gql-introspection-request'); const prepareGqlIntrospectionRequest = require('./prepare-gql-introspection-request');
const { prepareRequest } = require('./prepare-request'); const { prepareRequest } = require('./prepare-request');
const interpolateVars = require('./interpolate-vars'); const interpolateVars = require('./interpolate-vars');

22
packages/bruno-requests/.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
# dependencies
node_modules
yarn.lock
pnpm-lock.yaml
package-lock.json
.pnp
.pnp.js
# testing
coverage
# production
dist
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@ -0,0 +1,32 @@
{
"name": "@usebruno/requests",
"version": "0.1.0",
"license": "MIT",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/index.d.js",
"files": [
"dist",
"src",
"package.json"
],
"scripts": {
"clean": "rimraf dist",
"prebuild": "npm run clean",
"build": "rollup -c",
"prepack": "npm run test && npm run build"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^23.0.2",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-typescript": "^9.0.2",
"rollup": "3.29.5",
"rollup-plugin-dts": "^5.0.0",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-terser": "^7.0.2",
"typescript": "^4.8.4"
},
"overrides": {
"rollup": "3.29.5"
}
}

View File

@ -0,0 +1,37 @@
const { nodeResolve } = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
const typescript = require('@rollup/plugin-typescript');
const dts = require('rollup-plugin-dts');
const { terser } = require('rollup-plugin-terser');
const peerDepsExternal = require('rollup-plugin-peer-deps-external');
const packageJson = require('./package.json');
module.exports = [
{
input: 'src/index.ts',
output: [
{
file: packageJson.main,
format: 'cjs',
sourcemap: true,
exports: 'named'
},
{
file: packageJson.module,
format: 'esm',
sourcemap: true,
exports: 'named'
}
],
plugins: [
peerDepsExternal(),
nodeResolve({
extensions: ['.js', '.ts', '.tsx', '.json', '.css']
}),
commonjs(),
typescript({ tsconfig: './tsconfig.json' }),
terser()
]
}
];

View File

@ -25,7 +25,7 @@ function md5(input) {
return crypto.createHash('md5').update(input).digest('hex'); return crypto.createHash('md5').update(input).digest('hex');
} }
function addDigestInterceptor(axiosInstance, request) { export function addDigestInterceptor(axiosInstance, request) {
const { username, password } = request.digestConfig; const { username, password } = request.digestConfig;
console.debug('Digest Auth Interceptor Initialized'); console.debug('Digest Auth Interceptor Initialized');
@ -122,5 +122,3 @@ function addDigestInterceptor(axiosInstance, request) {
} }
); );
} }
module.exports = { addDigestInterceptor };

View File

@ -0,0 +1 @@
export { addDigestInterceptor } from './digestauth-helper';

View File

@ -0,0 +1 @@
export { addDigestInterceptor } from './auth';

View File

@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist",
"rootDir": "./src",
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"declaration": true,
"declarationDir": "./dist/types",
"allowJs": true,
"checkJs": false
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js"],
"exclude": ["node_modules", "dist"]
}

View File

@ -0,0 +1,21 @@
meta {
name: Digest Auth 200
type: http
seq: 1
}
get {
url: https://httpbin.org/digest-auth/auth/foo/passwd
body: none
auth: digest
}
auth:digest {
username: foo
password: passwd
}
assert {
res.status: eq 200
res.body.authenticated: isTruthy
}

View File

@ -0,0 +1,20 @@
meta {
name: Digest Auth 401
type: http
seq: 2
}
get {
url: https://httpbin.org/digest-auth/auth/foo/passw
body: none
auth: digest
}
auth:digest {
username: foo
password: passwd
}
assert {
res.status: eq 401
}

View File

@ -0,0 +1,3 @@
meta {
name: digest
}