From a22eb43a27b5af3a18f2440f3ee394c5722e2298 Mon Sep 17 00:00:00 2001 From: Pooja Date: Wed, 21 Jan 2026 18:56:46 +0530 Subject: [PATCH] =?UTF-8?q?fix(websocket):=20add=20API=20Key=20query=20par?= =?UTF-8?q?ams=20support=20and=20OAuth2=20inheritan=E2=80=A6=20(#6271)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(websocket): add API Key query params support and OAuth2 inheritance warning * add: playwright test --- .../RequestPane/WSRequestPane/WSAuth/index.js | 11 ++++ .../src/ipc/network/ws-event-handlers.js | 31 ++++++++++- .../tests/network/prepare-ws-request.spec.js | 55 +++++++++++++++++++ packages/bruno-tests/src/ws/index.js | 6 ++ .../collection/ws-test-request-with-query.bru | 19 +++++++ tests/websockets/query.spec.ts | 20 +++++++ 6 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 packages/bruno-electron/tests/network/prepare-ws-request.spec.js create mode 100644 tests/websockets/fixtures/collection/ws-test-request-with-query.bru create mode 100644 tests/websockets/query.spec.ts diff --git a/packages/bruno-app/src/components/RequestPane/WSRequestPane/WSAuth/index.js b/packages/bruno-app/src/components/RequestPane/WSRequestPane/WSAuth/index.js index 187df08fd..2ca88195f 100644 --- a/packages/bruno-app/src/components/RequestPane/WSRequestPane/WSAuth/index.js +++ b/packages/bruno-app/src/components/RequestPane/WSRequestPane/WSAuth/index.js @@ -93,6 +93,17 @@ const WSAuth = ({ item, collection }) => { case 'inherit': { const source = getEffectiveAuthSource(); + // Check if inherited auth is OAuth2 - not supported for WebSockets + if (source?.auth?.mode === 'oauth2') { + return ( + <> +
+ OAuth 2 not yet supported by WebSockets. Using no auth instead. +
+ + ); + } + // Only show inherited auth if it's one of the supported types if (source && supportedAuthModes.includes(source.auth?.mode)) { return ( diff --git a/packages/bruno-electron/src/ipc/network/ws-event-handlers.js b/packages/bruno-electron/src/ipc/network/ws-event-handlers.js index 3f24ad8ba..e11aadaf6 100644 --- a/packages/bruno-electron/src/ipc/network/ws-event-handlers.js +++ b/packages/bruno-electron/src/ipc/network/ws-event-handlers.js @@ -249,6 +249,34 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables, } } + // Add API key to the URL if placement is queryparams + if (wsRequest.apiKeyAuthValueForQueryParams && wsRequest.apiKeyAuthValueForQueryParams.placement === 'queryparams') { + try { + const urlObj = new URL(wsRequest.url); + + const globalEnvironmentVariables = request.globalEnvironmentVariables; + const promptVariables = collection?.promptVariables || {}; + + const interpolationOptions = { + globalEnvironmentVariables, + envVars, + runtimeVariables, + promptVariables, + processEnvVars + }; + + const key = interpolateString(wsRequest.apiKeyAuthValueForQueryParams.key, interpolationOptions); + const value = interpolateString(wsRequest.apiKeyAuthValueForQueryParams.value, interpolationOptions); + + urlObj.searchParams.set(key, value); + wsRequest.url = urlObj.toString(); + } catch (error) { + console.error('Error adding API key to WebSocket URL:', error); + } + } + + delete wsRequest.apiKeyAuthValueForQueryParams; + interpolateVars(wsRequest, envVars, runtimeVariables, processEnvVars); return wsRequest; @@ -462,5 +490,6 @@ const registerWsEventHandlers = (window) => { module.exports = { registerWsEventHandlers, - wsClient + wsClient, + prepareWsRequest }; diff --git a/packages/bruno-electron/tests/network/prepare-ws-request.spec.js b/packages/bruno-electron/tests/network/prepare-ws-request.spec.js new file mode 100644 index 000000000..89ea77efb --- /dev/null +++ b/packages/bruno-electron/tests/network/prepare-ws-request.spec.js @@ -0,0 +1,55 @@ +// Mock dependencies before requiring the module +const { prepareWsRequest } = require('../../src/ipc/network/ws-event-handlers'); + +describe('prepareWsRequest: API Key Query Params', () => { + const createMockItem = (authConfig = {}) => ({ + uid: 'test-item-uid', + request: { + url: 'ws://localhost:3001', + headers: [], + body: { + mode: 'raw', + ws: [] + }, + auth: authConfig, + vars: { req: [], res: [] }, + script: { req: '', res: '' } + } + }); + + const createMockCollection = (collectionAuth = null) => ({ + uid: 'test-collection-uid', + pathname: '/test/path', + root: { + request: { + headers: [], + auth: collectionAuth || { mode: 'none' } + } + }, + brunoConfig: {}, + globalEnvironmentVariables: {}, + promptVariables: {}, + items: [] + }); + + describe('API Key with Query Params placement', () => { + it('should append API key to URL when placement is queryparams', async () => { + const item = createMockItem({ + mode: 'apikey', + apikey: { + key: 'apiKey', + value: 'test-api-key-123', + placement: 'queryparams' + } + }); + const collection = createMockCollection(); + const environment = { variables: [] }; + const runtimeVariables = {}; + + const result = await prepareWsRequest(item, collection, environment, runtimeVariables); + + expect(result.url).toContain('apiKey=test-api-key-123'); + expect(result.url).toBe('ws://localhost:3001/?apiKey=test-api-key-123'); + }); + }); +}); diff --git a/packages/bruno-tests/src/ws/index.js b/packages/bruno-tests/src/ws/index.js index d89973dc2..8ed0f4d46 100644 --- a/packages/bruno-tests/src/ws/index.js +++ b/packages/bruno-tests/src/ws/index.js @@ -33,6 +33,12 @@ wss.on('connection', function connection(ws, request) { return ws.send(JSON.stringify({ headers: request.headers })); + } else if ('func' in obj && obj.func === 'query') { + const url = new URL(request.url, `http://${request.headers.host}`); + const query = Object.fromEntries(url.searchParams.entries()); + return ws.send(JSON.stringify({ + query: query + })); } else { return ws.send(JSON.stringify({ data: JSON.parse(Buffer.from(data).toString()) diff --git a/tests/websockets/fixtures/collection/ws-test-request-with-query.bru b/tests/websockets/fixtures/collection/ws-test-request-with-query.bru new file mode 100644 index 000000000..1dbc55384 --- /dev/null +++ b/tests/websockets/fixtures/collection/ws-test-request-with-query.bru @@ -0,0 +1,19 @@ +meta { + name: ws-test-request-with-query + type: ws + seq: 3 +} + +ws { + url: ws://localhost:8081/ws?testParam=testValue&anotherParam={{variable}} + auth: inherit +} + +body:ws { + name: message 1 + content: ''' + { + "func":"query" + } + ''' +} diff --git a/tests/websockets/query.spec.ts b/tests/websockets/query.spec.ts new file mode 100644 index 000000000..85241cc31 --- /dev/null +++ b/tests/websockets/query.spec.ts @@ -0,0 +1,20 @@ +import { test, expect } from '../../playwright'; +import { buildWebsocketCommonLocators } from '../utils/page/locators'; + +const BRU_REQ_NAME = /^ws-test-request-with-query$/; + +test.describe.serial('query params', () => { + test('query params are returned if passed', async ({ pageWithUserData: page }) => { + const locators = buildWebsocketCommonLocators(page); + + // Open the most recent collection + await page.locator('#sidebar-collection-name').click(); + + // Click on the required request + await page.getByTitle(BRU_REQ_NAME).click(); + await locators.runner().click(); + + // Check if the message has the query params + await expect(locators.messages().nth(2).locator('.text-ellipsis')).toHaveText(/\"(testParam)\"\:\s+\"testValue\"/); + }); +});