mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
fix(websocket): add API Key query params support and OAuth2 inheritan… (#6271)
* fix(websocket): add API Key query params support and OAuth2 inheritance warning * add: playwright test
This commit is contained in:
@@ -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 (
|
||||
<>
|
||||
<div className="flex flex-row w-full mt-2 gap-2">
|
||||
OAuth 2 not <strong>yet</strong> supported by WebSockets. Using no auth instead.
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Only show inherited auth if it's one of the supported types
|
||||
if (source && supportedAuthModes.includes(source.auth?.mode)) {
|
||||
return (
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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())
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
'''
|
||||
}
|
||||
20
tests/websockets/query.spec.ts
Normal file
20
tests/websockets/query.spec.ts
Normal file
@@ -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\"/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user