From 3c0d0c95ea55489fac321aea215f40729e8e1066 Mon Sep 17 00:00:00 2001 From: lohxt1 Date: Wed, 2 Apr 2025 19:42:15 +0530 Subject: [PATCH] oauth2 changes --- .../Auth/OAuth2/AdditionalParams/index.js | 216 ++++++++++++++++++ .../Auth/OAuth2/AuthorizationCode/index.js | 2 + packages/bruno-lang/v2/src/bruToJson.js | 161 ++++++++++++- .../bruno-lang/v2/src/collectionBruToJson.js | 145 +++++++++++- packages/bruno-lang/v2/src/jsonToBru.js | 29 +++ 5 files changed, 549 insertions(+), 4 deletions(-) create mode 100644 packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js new file mode 100644 index 000000000..cdee10a49 --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AdditionalParams/index.js @@ -0,0 +1,216 @@ +import { useDispatch } from "react-redux"; +import React, { useRef, forwardRef, useState } from 'react'; +import get from 'lodash/get'; +import { useTheme } from 'providers/Theme'; +import { IconPlus } from '@tabler/icons'; +import Dropdown from 'components/Dropdown'; +import { cloneDeep } from "lodash"; + +const AdditionalParams = ({ item = {}, request, updateAuth, collection }) => { + const dispatch = useDispatch(); + const { storedTheme } = useTheme(); + const dropdownTippyRef = useRef(); + const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); + const [activeTab, setActiveTab] = useState('authorization'); + + const oAuth = get(request, 'auth.oauth2', {}); + const { + grantType, + callbackUrl, + authorizationUrl, + accessTokenUrl, + clientId, + clientSecret, + scope, + credentialsPlacement, + state, + pkce, + credentialsId, + tokenPlacement, + tokenHeaderPrefix, + tokenQueryKey, + refreshTokenUrl, + autoRefreshToken, + autoFetchToken, + additionalParams = {} + } = oAuth; + + const handleUpdateAdditionalParam = ({ paramType, key, paramIndex, value }) => { + const updatedAdditionalParams = cloneDeep(additionalParams); + + updatedAdditionalParams[paramType][paramIndex][key] = value; + + dispatch( + updateAuth({ + mode: 'oauth2', + collectionUid: collection.uid, + itemUid: item.uid, + content: { + grantType, + callbackUrl, + authorizationUrl, + accessTokenUrl, + clientId, + clientSecret, + state, + scope, + pkce, + credentialsPlacement, + credentialsId, + tokenPlacement, + tokenHeaderPrefix, + tokenQueryKey, + refreshTokenUrl, + autoRefreshToken, + autoFetchToken, + additionalParams: updatedAdditionalParams, + } + }) + ); + } + + const handleAddNewAdditionalParam = () => { + const paramType = activeTab; + const updatedAdditionalParams = cloneDeep(additionalParams); + if (!updatedAdditionalParams?.[paramType]) { + updatedAdditionalParams[paramType] = []; + } + updatedAdditionalParams[paramType] = [ + ...updatedAdditionalParams[paramType], + { + name: '', + value: '', + sendIn: 'header' + } + ]; + + dispatch( + updateAuth({ + mode: 'oauth2', + collectionUid: collection.uid, + itemUid: item.uid, + content: { + grantType, + callbackUrl, + authorizationUrl, + accessTokenUrl, + clientId, + clientSecret, + state, + scope, + pkce, + credentialsPlacement, + credentialsId, + tokenPlacement, + tokenHeaderPrefix, + tokenQueryKey, + refreshTokenUrl, + autoRefreshToken, + autoFetchToken, + additionalParams: updatedAdditionalParams, + } + }) + ); + } + return ( +
+
+
Authorization
+
Token
+
Refresh
+
+ + + + + + + + + + {additionalParams?.[activeTab]?.map((param, index) => + + + + } placement="bottom-end"> +
{ + dropdownTippyRef.current.hide(); + handleUpdateAdditionalParam({ + paramType: activeTab, + key: 'sendIn', + paramIndex: index, + value: 'header' + }) + }} + > + Header +
+
{ + dropdownTippyRef.current.hide(); + handleUpdateAdditionalParam({ + paramType: activeTab, + key: 'sendIn', + paramIndex: index, + value: 'queryparams' + }) + }} + > + Query Params +
+
{ + dropdownTippyRef.current.hide(); + handleUpdateAdditionalParam({ + paramType: activeTab, + key: 'sendIn', + paramIndex: index, + value: 'body' + }) + }} + > + Body +
+
+ + )} + +
KeyValueSend In
+ handleUpdateAdditionalParam({ + paramType: activeTab, + key: 'name', + paramIndex: index, + value + })} + collection={collection} + /> + + handleUpdateAdditionalParam({ + paramType: activeTab, + key: 'value', + paramIndex: index, + value + })} + collection={collection} + /> +
+
+ +
+
+ ) +} + +export default AdditionalParams; \ No newline at end of file diff --git a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js index c00964d82..bc2feb019 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/OAuth2/AuthorizationCode/index.js @@ -9,6 +9,7 @@ import StyledWrapper from './StyledWrapper'; import { inputsConfig } from './inputsConfig'; import Oauth2TokenViewer from '../Oauth2TokenViewer/index'; import Oauth2ActionButtons from '../Oauth2ActionButtons/index'; +import AdditionalParams from '../AdditionalParams/index'; const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAuth, collection, folder }) => { const dispatch = useDispatch(); @@ -326,6 +327,7 @@ const OAuth2AuthorizationCode = ({ save, item = {}, request, handleRun, updateAu + ); diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index 819272240..7c84c7e8a 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -22,12 +22,18 @@ const { safeParseJson, outdentString } = require('./utils'); * */ const grammar = ohm.grammar(`Bru { - BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs)* + BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs | authOAuth2Configs)* auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM | authOAuth2 | authwsse | authapikey bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body bodyforms = bodyformurlencoded | bodymultipart | bodyfile params = paramspath | paramsquery - + + // Oauth2 additional parameters + authOAuth2Configs = oAuth2AuthorizationConfig | oAuth2TokenConfig | oAuth2RefreshConfig + oAuth2AuthorizationConfig = oAuth2AuthorizationHeaders | oAuth2AuthorizationQueryParams + oAuth2TokenConfig = oAuth2TokenHeaders | oAuth2TokenQueryParams | oAuth2TokenBodyValues + oAuth2RefreshConfig = oAuth2RefreshHeaders | oAuth2RefreshQueryParams | oAuth2RefreshBodyValues + nl = "\\r"? "\\n" st = " " | "\\t" stnl = st | nl @@ -92,6 +98,15 @@ const grammar = ohm.grammar(`Bru { authwsse = "auth:wsse" dictionary authapikey = "auth:apikey" dictionary + oAuth2AuthorizationHeaders = "auth:oauth2:authorization_headers" dictionary + oAuth2AuthorizationQueryParams = "auth:oauth2:authorization_queryparams" dictionary + oAuth2TokenHeaders = "auth:oauth2:token_headers" dictionary + oAuth2TokenQueryParams = "auth:oauth2:token_queryparams" dictionary + oAuth2TokenBodyValues = "auth:oauth2:token_bodyvalues" dictionary + oAuth2RefreshHeaders = "auth:oauth2:authorization_headers" dictionary + oAuth2RefreshQueryParams = "auth:oauth2:authorization_queryparams" dictionary + oAuth2RefreshBodyValues = "auth:oauth2:authorization_bodyvalues" dictionary + body = "body" st* "{" nl* textblock tagend bodyjson = "body:json" st* "{" nl* textblock tagend bodytext = "body:text" st* "{" nl* textblock tagend @@ -588,6 +603,146 @@ const sem = grammar.createSemantics().addAttribute('ast', { } }; }, + oAuth2AuthorizationHeaders(_1, dictionary) { + const authorizationHeaders = [...mapPairListToKeyValPairs(dictionary.ast)]?.map(_ => ({ + ..._, + sendIn: 'headers' + })); + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + authorization: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.authorization || []), + ...authorizationHeaders + ] + } + } + } + }; + }, + oAuth2AuthorizationQueryParams(_1, dictionary) { + const authorizationQueryParams = [...mapPairListToKeyValPairs(dictionary.ast)]?.map(_ => ({ + ..._, + sendIn: 'queryparams' + })); + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + authorization: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.authorization || []), + ...authorizationQueryParams + ] + } + } + } + }; + }, + oAuth2TokenHeaders(_1, dictionary) { + const tokenHeaders = [...mapPairListToKeyValPairs(dictionary.ast)]?.map(_ => ({ + ..._, + sendIn: 'headers' + })); + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + token: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.token || []), + ...tokenHeaders + ] + } + } + } + }; + }, + oAuth2TokenQueryParams(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + tokenQueryParams: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenQueryParams || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2TokenBodyValues(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + tokenBodyValues: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenBodyValues || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2RefreshHeaders(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + refreshHeaders: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshHeaders || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2RefreshQueryParams(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + refreshQueryParams: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshQueryParams || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2RefreshBodyValues(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + refreshBodyValues: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshBodyValues || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, authwsse(_1, dictionary) { const auth = mapPairListToKeyValPairs(dictionary.ast, false); @@ -782,4 +937,4 @@ const parser = (input) => { }; module.exports = parser; - \ No newline at end of file + diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js index 16a0c8d79..4c49fc39f 100644 --- a/packages/bruno-lang/v2/src/collectionBruToJson.js +++ b/packages/bruno-lang/v2/src/collectionBruToJson.js @@ -3,9 +3,15 @@ const _ = require('lodash'); const { safeParseJson, outdentString } = require('./utils'); const grammar = ohm.grammar(`Bru { - BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs)* + BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs | authOAuth2Configs)* auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM |authOAuth2 | authwsse | authapikey + // Oauth2 additional parameters + authOAuth2Configs = oAuth2AuthorizationConfig | oAuth2TokenConfig | oAuth2RefreshConfig + oAuth2AuthorizationConfig = oAuth2AuthorizationHeaders | oAuth2AuthorizationQueryParams + oAuth2TokenConfig = oAuth2TokenHeaders | oAuth2TokenQueryParams | oAuth2TokenBodyValues + oAuth2RefreshConfig = oAuth2RefreshHeaders | oAuth2RefreshQueryParams | oAuth2RefreshBodyValues + nl = "\\r"? "\\n" st = " " | "\\t" stnl = st | nl @@ -30,6 +36,15 @@ const grammar = ohm.grammar(`Bru { auth = "auth" dictionary + oAuth2AuthorizationHeaders = "auth:oauth2:authorization_headers" dictionary + oAuth2AuthorizationQueryParams = "auth:oauth2:authorization_queryparams" dictionary + oAuth2TokenHeaders = "auth:oauth2:token_headers" dictionary + oAuth2TokenQueryParams = "auth:oauth2:token_queryparams" dictionary + oAuth2TokenBodyValues = "auth:oauth2:token_bodyvalues" dictionary + oAuth2RefreshHeaders = "auth:oauth2:authorization_headers" dictionary + oAuth2RefreshQueryParams = "auth:oauth2:authorization_queryparams" dictionary + oAuth2RefreshBodyValues = "auth:oauth2:authorization_bodyvalues" dictionary + headers = "headers" dictionary query = "query" dictionary @@ -348,6 +363,134 @@ const sem = grammar.createSemantics().addAttribute('ast', { } }; }, + oAuth2AuthorizationHeaders(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + authorizationHeaders: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.authorizationHeaders || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2AuthorizationQueryParams(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + authorizationQueryParams: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.authorizationQueryParams || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2TokenHeaders(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + tokenHeaders: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenHeaders || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2TokenQueryParams(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + tokenQueryParams: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenQueryParams || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2TokenBodyValues(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + tokenBodyValues: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.tokenBodyValues || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2RefreshHeaders(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + refreshHeaders: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshHeaders || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2RefreshQueryParams(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + refreshQueryParams: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshQueryParams || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, + oAuth2RefreshBodyValues(_1, dictionary) { + return { + auth: { + oauth2: { + ...(dictionary?.ast?.auth?.oauth2 || {}), + additionalParameters: { + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters || {}), + refreshBodyValues: [ + ...(dictionary?.ast?.auth?.oauth2?.additionalParameters?.refreshBodyValues || []), + ...mapPairListToKeyValPairs(dictionary.ast) + ] + } + } + } + }; + }, authwsse(_1, dictionary) { const auth = mapPairListToKeyValPairs(dictionary.ast, false); const userKey = _.find(auth, { name: 'username' }); diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index 776cca7d5..d8a7b13a3 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -249,6 +249,35 @@ ${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false). `; break; } + + if (auth?.oauth2?.additionalParameters) { + switch(auth?.oauth2?.additionalParameters) { + case 'authorizationHeaders' : + let authorizationHeaders = auth?.oauth2?.additionalParameters?.authorizationHeaders; + bru += `auth:oauth2:authorization_headers { +${enabled(authorizationHeaders) + .map((item) => `${item.name}: ${item.value}`) + .join('\n')} +}`; + break; + case 'authorizationQueryParams' : + let authorizationQueryParams = auth?.oauth2?.additionalParameters?.authorizationQueryParams; + bru += `auth:oauth2:authorization_queryparams { +${enabled(authorizationQueryParams) + .map((item) => `${item.name}: ${item.value}`) + .join('\n')} +}`; + break; + case 'authorizationBodyValues' : + let authorizationBodyValues = auth?.oauth2?.additionalParameters?.authorizationBodyValues; + bru += `auth:oauth2:authorization_queryparams { + ${enabled(authorizationBodyValues) + .map((item) => `${item.name}: ${item.value}`) + .join('\n')} + }`; + break; + } + } } if (auth && auth.apikey) {