From d2c2b526fa7d57e866278dd0fc8f2840ad5a3b24 Mon Sep 17 00:00:00 2001 From: Mateusz Pietryga Date: Mon, 6 May 2024 20:45:25 +0200 Subject: [PATCH] feat: OAuth2: display token request and response details on the timeline --- .../components/ResponsePane/Timeline/index.js | 43 +++++++++++++++++++ .../bruno-electron/src/ipc/network/index.js | 42 +++++++++++++++--- .../src/ipc/network/oauth2-helper.js | 25 +++++------ 3 files changed, 91 insertions(+), 19 deletions(-) diff --git a/packages/bruno-app/src/components/ResponsePane/Timeline/index.js b/packages/bruno-app/src/components/ResponsePane/Timeline/index.js index d8a4770a53..8405cb6573 100644 --- a/packages/bruno-app/src/components/ResponsePane/Timeline/index.js +++ b/packages/bruno-app/src/components/ResponsePane/Timeline/index.js @@ -7,6 +7,11 @@ const Timeline = ({ request, response }) => { const requestHeaders = []; const responseHeaders = typeof response.headers === 'object' ? Object.entries(response.headers) : []; + const authRequest = request.authRequest; + const authResponse = request.authResponse; + const authRequestHeaders = typeof authRequest?.headers === 'object' ? Object.entries(authRequest.headers) : []; + const authResponseHeaders = typeof authResponse?.headers === 'object' ? Object.entries(authResponse?.headers) : []; + request = request || {}; response = response || {}; @@ -18,9 +23,47 @@ const Timeline = ({ request, response }) => { }); let requestData = safeStringifyJSON(request.data); + let authRequestData = safeStringifyJSON(authRequest?.data); return ( + {authRequest ? ( + <> +
+
+              {'>'} {authRequest.method} {authRequest.url}
+            
+ {authRequestHeaders.map((h) => { + return ( +
+                  {'>'} {h[0]}: {h[1]}
+                
+ ); + })} + {authRequestData ? ( +
+                {'>'} data {authRequestData}
+              
+ ) : null} +
+ {authResponse ? ( +
+
+                {'<'} {authResponse.status} {authResponse.statusText}
+              
+ {authResponseHeaders.map((h) => { + return ( +
+                    {'<'} {h[0]}: {h[1]}
+                  
+ ); + })} +
+ ) : null} +
+ + ) : null} +
           {'>'} {request.method} {request.url}
diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js
index e02afe0d0c..2f42f3c2a8 100644
--- a/packages/bruno-electron/src/ipc/network/index.js
+++ b/packages/bruno-electron/src/ipc/network/index.js
@@ -209,23 +209,33 @@ const configureRequest = async (
   if (request.oauth2) {
     let requestCopy = cloneDeep(request);
     interpolateVars(requestCopy, envVars, runtimeVariables, processEnvVars);
-    let credentials, response;
+    let credentials, authResponse, authRequest;
     switch (request?.oauth2?.grantType) {
       case 'authorization_code': {
-        ({ credentials, response } = await oauth2AuthorizeWithAuthorizationCode(requestCopy, collectionUid));
+        ({ credentials, authRequest, authResponse } = await oauth2AuthorizeWithAuthorizationCode(
+          requestCopy,
+          collectionUid
+        ));
         break;
       }
       case 'client_credentials': {
-        ({ credentials, response } = await oauth2AuthorizeWithClientCredentials(requestCopy, collectionUid));
+        ({ credentials, authRequest, authResponse } = await oauth2AuthorizeWithClientCredentials(
+          requestCopy,
+          collectionUid
+        ));
         break;
       }
       case 'password': {
-        ({ credentials, response } = await oauth2AuthorizeWithPasswordCredentials(requestCopy, collectionUid));
+        ({ credentials, authRequest, authResponse } = await oauth2AuthorizeWithPasswordCredentials(
+          requestCopy,
+          collectionUid
+        ));
         break;
       }
     }
     request.credentials = credentials;
-    request.authRequestResponse = response;
+    request.authRequest = authRequest;
+    request.authResponse = authResponse;
 
     // Bruno can handle bearer token type automatically.
     // Other - more exotic token types are not touched
@@ -488,6 +498,24 @@ const registerNetworkIpc = (mainWindow) => {
           method: request.method,
           headers: request.headers,
           data: safeParseJSON(safeStringifyJSON(request.data)),
+          authRequest: request.authRequest
+            ? {
+                url: request.authRequest.url,
+                method: request.authRequest.method,
+                headers: request.authRequest.headers,
+                data: request.authRequest.data,
+                timestamp: request.authRequest.timestamp
+              }
+            : null,
+          authResponse: request.authResponse
+            ? {
+                headers: request.authResponse ? request.authResponse.headers : [],
+                data: request.authResponse.data ? parseDataFromResponse(request.authResponse).data : {},
+                status: request.authResponse.status,
+                statusText: request.authResponse.statusText,
+                timestamp: request.authResponse.timestamp
+              }
+            : null,
           timestamp: Date.now()
         },
         collectionUid,
@@ -682,8 +710,8 @@ const registerNetworkIpc = (mainWindow) => {
         collectionPath
       );
 
-      const response = request.authRequestResponse;
-      // When credentials are loaded from cache, authRequestResponse has no data
+      const response = request.authResponse;
+      // When credentials are loaded from cache, authResponse has no data
       if (response.data) {
         const { data } = parseDataFromResponse(response);
         response.data = data;
diff --git a/packages/bruno-electron/src/ipc/network/oauth2-helper.js b/packages/bruno-electron/src/ipc/network/oauth2-helper.js
index a1a0e9fba2..3480704e06 100644
--- a/packages/bruno-electron/src/ipc/network/oauth2-helper.js
+++ b/packages/bruno-electron/src/ipc/network/oauth2-helper.js
@@ -58,7 +58,7 @@ const oauth2AuthorizeWithAuthorizationCode = async (request, collectionUid) => {
   const { cachedCredentials } = getPersistedOauth2Credentials(collectionUid);
   if (cachedCredentials?.access_token) {
     console.log('Reusing Stored access token');
-    return { credentials: cachedCredentials, response: {} };
+    return { credentials: cachedCredentials, authRequest: null, authResponse: null };
   }
 
   let codeVerifier = generateCodeVerifier();
@@ -90,10 +90,11 @@ const oauth2AuthorizeWithAuthorizationCode = async (request, collectionUid) => {
   setClientCredentials(clientId, clientSecret, clientSecretMethod, request);
 
   const axiosInstance = makeAxiosInstance();
-  const response = await axiosInstance(request);
-  const credentials = JSON.parse(response.data);
+  const authResponse = await axiosInstance(request);
+  const credentials = JSON.parse(authResponse.data);
   persistOauth2Credentials(credentials, collectionUid);
-  return { credentials, response };
+
+  return { credentials, authRequest: request, authResponse };
 };
 
 const getOAuth2AuthorizationCode = (request, codeChallenge, collectionUid) => {
@@ -136,7 +137,7 @@ const oauth2AuthorizeWithClientCredentials = async (request, collectionUid) => {
   const { cachedCredentials } = getPersistedOauth2Credentials(collectionUid);
   if (cachedCredentials?.access_token) {
     console.log('Reusing Stored access token');
-    return { credentials: cachedCredentials, response: {} };
+    return { credentials: cachedCredentials, authRequest: null, authResponse: null };
   }
 
   let requestCopy = cloneDeep(request);
@@ -157,10 +158,10 @@ const oauth2AuthorizeWithClientCredentials = async (request, collectionUid) => {
   setClientCredentials(clientId, clientSecret, clientSecretMethod, request);
 
   const axiosInstance = makeAxiosInstance();
-  let response = await axiosInstance(request);
-  let credentials = JSON.parse(response.data);
+  let authResponse = await axiosInstance(request);
+  let credentials = JSON.parse(authResponse.data);
   persistOauth2Credentials(credentials, collectionUid);
-  return { credentials, response };
+  return { credentials, authRequest: request, authResponse };
 };
 
 // PASSWORD CREDENTIALS
@@ -169,7 +170,7 @@ const oauth2AuthorizeWithPasswordCredentials = async (request, collectionUid) =>
   const { cachedCredentials } = getPersistedOauth2Credentials(collectionUid);
   if (cachedCredentials?.access_token) {
     console.log('Reusing Stored access token');
-    return { credentials: cachedCredentials, response: {} };
+    return { credentials: cachedCredentials, authRequest: null, authResponse: null };
   }
 
   const oAuth = get(request, 'oauth2', {});
@@ -191,10 +192,10 @@ const oauth2AuthorizeWithPasswordCredentials = async (request, collectionUid) =>
   setClientCredentials(clientId, clientSecret, clientSecretMethod, request);
 
   const axiosInstance = makeAxiosInstance();
-  let response = await axiosInstance(request);
-  let credentials = JSON.parse(response.data);
+  let authResponse = await axiosInstance(request);
+  let credentials = JSON.parse(authResponse.data);
   persistOauth2Credentials(credentials, collectionUid);
-  return { credentials, response };
+  return { credentials, authRequest: request, authResponse };
 };
 module.exports = {
   oauth2AuthorizeWithAuthorizationCode,