From 9e2982101288e77f627034e7f8fbd29f07e78f2a Mon Sep 17 00:00:00 2001 From: pooja-bruno Date: Tue, 6 May 2025 17:56:34 +0530 Subject: [PATCH] feat: extend support for more auth in folder level --- .../components/FolderSettings/Auth/index.js | 91 +++++++++++++++++++ .../FolderSettings/AuthMode/index.js | 72 +++++++++++++++ .../RequestPane/Auth/BasicAuth/index.js | 9 +- .../RequestPane/Auth/BearerAuth/index.js | 12 ++- .../src/components/RequestPane/Auth/index.js | 16 +++- .../CollectionItem/GenerateCodeItem/index.js | 67 +++++++++++--- .../ReduxStore/slices/collections/index.js | 21 +++++ 7 files changed, 267 insertions(+), 21 deletions(-) diff --git a/packages/bruno-app/src/components/FolderSettings/Auth/index.js b/packages/bruno-app/src/components/FolderSettings/Auth/index.js index 360d5c64f..27cd03380 100644 --- a/packages/bruno-app/src/components/FolderSettings/Auth/index.js +++ b/packages/bruno-app/src/components/FolderSettings/Auth/index.js @@ -9,6 +9,13 @@ import OAuth2PasswordCredentials from 'components/RequestPane/Auth/OAuth2/Passwo import OAuth2ClientCredentials from 'components/RequestPane/Auth/OAuth2/ClientCredentials/index'; import GrantTypeSelector from 'components/RequestPane/Auth/OAuth2/GrantTypeSelector/index'; import AuthMode from '../AuthMode'; +import BasicAuth from 'components/RequestPane/Auth/BasicAuth'; +import BearerAuth from 'components/RequestPane/Auth/BearerAuth'; +import DigestAuth from 'components/RequestPane/Auth/DigestAuth'; +import NTLMAuth from 'components/RequestPane/Auth/NTLMAuth'; +import WsseAuth from 'components/RequestPane/Auth/WsseAuth'; +import ApiKeyAuth from 'components/RequestPane/Auth/ApiKeyAuth'; +import AwsV4Auth from 'components/RequestPane/Auth/AwsV4Auth'; const GrantTypeComponentMap = ({ collection, folder }) => { const dispatch = useDispatch(); @@ -43,6 +50,83 @@ const Auth = ({ collection, folder }) => { const getAuthView = () => { switch (authMode) { + case 'basic': { + return ( + handleSave()} + /> + ); + } + case 'bearer': { + return ( + handleSave()} + /> + ); + } + case 'digest': { + return ( + handleSave()} + /> + ); + } + case 'ntlm': { + return ( + handleSave()} + /> + ); + } + case 'wsse': { + return ( + handleSave()} + /> + ); + } + case 'apikey': { + return ( + handleSave()} + /> + ); + } + case 'awsv4': { + return ( + handleSave()} + /> + ); + } case 'oauth2': { return ( <> @@ -56,6 +140,13 @@ const Auth = ({ collection, folder }) => { ); } + case 'inherit': { + return ( +
+ Authentication settings will be inherited from the collection. +
+ ); + } case 'none': { return null; } diff --git a/packages/bruno-app/src/components/FolderSettings/AuthMode/index.js b/packages/bruno-app/src/components/FolderSettings/AuthMode/index.js index e6e48f110..36377973a 100644 --- a/packages/bruno-app/src/components/FolderSettings/AuthMode/index.js +++ b/packages/bruno-app/src/components/FolderSettings/AuthMode/index.js @@ -35,6 +35,51 @@ const AuthMode = ({ collection, folder }) => {
} placement="bottom-end"> +
{ + dropdownTippyRef.current.hide(); + onModeChange('awsv4'); + }} + > + AWS Sig v4 +
+
{ + dropdownTippyRef.current.hide(); + onModeChange('basic'); + }} + > + Basic Auth +
+
{ + dropdownTippyRef.current.hide(); + onModeChange('bearer'); + }} + > + Bearer Token +
+
{ + dropdownTippyRef.current.hide(); + onModeChange('digest'); + }} + > + Digest Auth +
+
{ + dropdownTippyRef.current.hide(); + onModeChange('ntlm'); + }} + > + NTLM Auth +
{ @@ -44,6 +89,33 @@ const AuthMode = ({ collection, folder }) => { > OAuth 2.0
+
{ + dropdownTippyRef.current.hide(); + onModeChange('wsse'); + }} + > + WSSE Auth +
+
{ + dropdownTippyRef.current.hide(); + onModeChange('apikey'); + }} + > + API Key +
+
{ + dropdownTippyRef.current.hide(); + onModeChange('inherit'); + }} + > + Inherit +
{ diff --git a/packages/bruno-app/src/components/RequestPane/Auth/BasicAuth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/BasicAuth/index.js index 8582a53cd..ef714f528 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/BasicAuth/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/BasicAuth/index.js @@ -7,14 +7,17 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; -const BasicAuth = ({ item, collection }) => { +const BasicAuth = ({ item, collection, updateAuth, request, save }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); - const basicAuth = item.draft ? get(item, 'draft.request.auth.basic', {}) : get(item, 'request.auth.basic', {}); + const basicAuth = get(request, 'auth.basic', {}); const handleRun = () => dispatch(sendRequest(item, collection.uid)); - const handleSave = () => dispatch(saveRequest(item.uid, collection.uid)); + + const handleSave = () => { + save(); + }; const handleUsernameChange = (username) => { dispatch( diff --git a/packages/bruno-app/src/components/RequestPane/Auth/BearerAuth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/BearerAuth/index.js index bef4d062a..c8ba9d1c6 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/BearerAuth/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/BearerAuth/index.js @@ -7,16 +7,18 @@ import { updateAuth } from 'providers/ReduxStore/slices/collections'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; -const BearerAuth = ({ item, collection }) => { +const BearerAuth = ({ item, collection, updateAuth, request, save }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); - const bearerToken = item.draft - ? get(item, 'draft.request.auth.bearer.token', '') - : get(item, 'request.auth.bearer.token', ''); + // Use the request prop directly like OAuth2ClientCredentials does + const bearerToken = get(request, 'auth.bearer.token', ''); const handleRun = () => dispatch(sendRequest(item, collection.uid)); - const handleSave = () => dispatch(saveRequest(item.uid, collection.uid)); + + const handleSave = () => { + save(); + }; const handleTokenChange = (token) => { dispatch( diff --git a/packages/bruno-app/src/components/RequestPane/Auth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/index.js index 4cb8897d3..a1469675a 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/index.js @@ -7,6 +7,8 @@ import BasicAuth from './BasicAuth'; import DigestAuth from './DigestAuth'; import WsseAuth from './WsseAuth'; import NTLMAuth from './NTLMAuth'; +import { updateAuth } from 'providers/ReduxStore/slices/collections'; +import { saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import ApiKeyAuth from './ApiKeyAuth'; import StyledWrapper from './StyledWrapper'; @@ -27,6 +29,16 @@ const getTreePathFromCollectionToItem = (collection, _item) => { const Auth = ({ item, collection }) => { const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode'); const requestTreePath = getTreePathFromCollectionToItem(collection, item); + + // Create a request object to pass to the auth components + const request = item.draft + ? get(item, 'draft.request', {}) + : get(item, 'request', {}); + + // Save function for request level + const save = () => { + return saveRequest(item.uid, collection.uid); + }; const getEffectiveAuthSource = () => { if (authMode !== 'inherit') return null; @@ -62,10 +74,10 @@ const Auth = ({ item, collection }) => { return ; } case 'basic': { - return ; + return ; } case 'bearer': { - return ; + return ; } case 'digest': { return ; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index.js index 42f0bc8ca..5c5640ca0 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index.js @@ -4,12 +4,60 @@ import CodeView from './CodeView'; import StyledWrapper from './StyledWrapper'; import { isValidUrl } from 'utils/url'; import { get } from 'lodash'; -import { findEnvironmentInCollection } from 'utils/collections'; +import { findEnvironmentInCollection, findItemInCollection, findParentItemInCollection } from 'utils/collections'; import { interpolateUrl, interpolateUrlPathParams } from 'utils/url/index'; import { getLanguages } from 'utils/codegenerator/targets'; import { useSelector } from 'react-redux'; import { getGlobalEnvironmentVariables } from 'utils/collections/index'; +const getTreePathFromCollectionToItem = (collection, _itemUid) => { + let path = []; + let item = findItemInCollection(collection, _itemUid); + while (item) { + path.unshift(item); + item = findParentItemInCollection(collection, item?.uid); + } + return path; +}; + +// Function to resolve inherited auth +const resolveInheritedAuth = (item, collection) => { + const request = item.draft?.request || item.request; + const authMode = request?.auth?.mode; + + // If auth is not inherit or no auth defined, return the request as is + if (!authMode || authMode !== 'inherit') { + return { + ...request + }; + } + + // Get the tree path from collection to item + const requestTreePath = getTreePathFromCollectionToItem(collection, item.uid); + + // Default to collection auth + const collectionAuth = get(collection, 'root.request.auth'); + let effectiveAuth = collectionAuth; + let source = 'collection'; + + // Check folders in reverse to find the closest auth configuration + for (let i of [...requestTreePath].reverse()) { + if (i.type === 'folder') { + const folderAuth = get(i, 'root.request.auth'); + if (folderAuth && folderAuth.mode && folderAuth.mode !== 'none' && folderAuth.mode !== 'inherit') { + effectiveAuth = folderAuth; + source = 'folder'; + break; + } + } + } + + return { + ...request, + auth: effectiveAuth + }; +}; + const GenerateCodeItem = ({ collectionUid, item, onClose }) => { const languages = getLanguages(); @@ -46,6 +94,9 @@ const GenerateCodeItem = ({ collectionUid, item, onClose }) => { get(item, 'draft.request.params') !== undefined ? get(item, 'draft.request.params') : get(item, 'request.params') ); + // Resolve auth inheritance + const resolvedRequest = resolveInheritedAuth(item, collection); + const [selectedLanguage, setSelectedLanguage] = useState(languages[0]); return ( @@ -94,16 +145,10 @@ const GenerateCodeItem = ({ collectionUid, item, onClose }) => { language={selectedLanguage} item={{ ...item, - request: - item.request.url !== '' - ? { - ...item.request, - url: finalUrl - } - : { - ...item.draft.request, - url: finalUrl - } + request: { + ...resolvedRequest, + url: finalUrl + } }} /> ) : ( 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 d3098a936..95287000a 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -1593,6 +1593,27 @@ export const collectionsSlice = createSlice({ case 'oauth2': set(folder, 'root.request.auth.oauth2', action.payload.content); break; + case 'basic': + set(folder, 'root.request.auth.basic', action.payload.content); + break; + case 'bearer': + set(folder, 'root.request.auth.bearer', action.payload.content); + break; + case 'digest': + set(folder, 'root.request.auth.digest', action.payload.content); + break; + case 'ntlm': + set(folder, 'root.request.auth.ntlm', action.payload.content); + break; + case 'apikey': + set(folder, 'root.request.auth.apikey', action.payload.content); + break; + case 'awsv4': + set(folder, 'root.request.auth.awsv4', action.payload.content); + break; + case 'wsse': + set(folder, 'root.request.auth.wsse', action.payload.content); + break; } } },