From a6426bb8610df975a01ae6410da7a98fab20db5e Mon Sep 17 00:00:00 2001 From: assafenso Date: Sun, 10 Mar 2024 13:56:47 +0200 Subject: [PATCH 1/3] fix: url encoded header fix --- lib/common/relay/prepareRequest.ts | 4 +++- test/functional/server-client.test.ts | 1 - test/unit/relay-response-body-form-url-encoded.test.ts | 2 +- .../relay-response-body-universal-form-url-encoded.test.ts | 4 ++-- test/unit/relay-response-headers-form-url-headers.test.ts | 2 +- .../relay-response-headers-universal-form-url-headers.test.ts | 4 ++-- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/common/relay/prepareRequest.ts b/lib/common/relay/prepareRequest.ts index f8012e48a..f1c9ed60f 100644 --- a/lib/common/relay/prepareRequest.ts +++ b/lib/common/relay/prepareRequest.ts @@ -96,6 +96,8 @@ export const prepareRequestFromFilterResult = async ( ); // replace the variables undefsafe(parsedBody, path, source); // put it back in } + //Remove the BROKER_VAR_SUB for the request body + delete parsedBody.BROKER_VAR_SUB; payload.body = JSON.stringify(parsedBody); } } @@ -210,7 +212,7 @@ export const prepareRequestFromFilterResult = async ( payload.headers['x-broker-content-type'] === 'application/x-www-form-urlencoded' ) { - payload.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + payload.headers['content-type'] = 'application/x-www-form-urlencoded'; if (payload.body) { const jsonBody = JSON.parse(payload.body) as Record; const params = new URLSearchParams(); diff --git a/test/functional/server-client.test.ts b/test/functional/server-client.test.ts index ad7309226..067d8afc3 100644 --- a/test/functional/server-client.test.ts +++ b/test/functional/server-client.test.ts @@ -150,7 +150,6 @@ describe('proxy requests originating from behind the broker server', () => { expect(response.status).toEqual(200); expect(response.data).toStrictEqual({ - BROKER_VAR_SUB: ['swap.me'], swap: { me: 'client:broker-token-12345' }, }); }); diff --git a/test/unit/relay-response-body-form-url-encoded.test.ts b/test/unit/relay-response-body-form-url-encoded.test.ts index 89afa4e37..a9d44299e 100644 --- a/test/unit/relay-response-body-form-url-encoded.test.ts +++ b/test/unit/relay-response-body-form-url-encoded.test.ts @@ -110,7 +110,7 @@ describe('body relay', () => { expect(makeRequestToDownstream).toHaveBeenCalledTimes(1); const arg = mockedFn.mock.calls[0][0]; expect(arg.body).toEqual( - `BROKER_VAR_SUB=url&url=${config.HOST}%3A${config.PORT}%2Fwebhook`, + `url=${config.HOST}%3A${config.PORT}%2Fwebhook`, ); done(); diff --git a/test/unit/relay-response-body-universal-form-url-encoded.test.ts b/test/unit/relay-response-body-universal-form-url-encoded.test.ts index 703cd7e9e..501dc963c 100644 --- a/test/unit/relay-response-body-universal-form-url-encoded.test.ts +++ b/test/unit/relay-response-body-universal-form-url-encoded.test.ts @@ -116,11 +116,11 @@ describe('body relay', () => { expect(makeRequestToDownstream).toHaveBeenCalledTimes(1); const arg = mockedFn.mock.calls[0][0]; - expect(arg.headers['Content-Type']).toEqual( + expect(arg.headers['content-type']).toEqual( 'application/x-www-form-urlencoded', ); expect(arg.body).toEqual( - `BROKER_VAR_SUB=url&url=${config.connections.myconn.HOST}%3A${config.connections.myconn.PORT}%2Fwebhook`, + `url=${config.connections.myconn.HOST}%3A${config.connections.myconn.PORT}%2Fwebhook`, ); done(); diff --git a/test/unit/relay-response-headers-form-url-headers.test.ts b/test/unit/relay-response-headers-form-url-headers.test.ts index ab09d5d92..41bbacf99 100644 --- a/test/unit/relay-response-headers-form-url-headers.test.ts +++ b/test/unit/relay-response-headers-form-url-headers.test.ts @@ -102,7 +102,7 @@ describe('header relay', () => { () => { expect(makeRequestToDownstream).toHaveBeenCalledTimes(1); const arg = mockedFn.mock.calls[0][0]; - expect(arg.headers['Content-Type']).toEqual( + expect(arg.headers['content-type']).toEqual( 'application/x-www-form-urlencoded', ); expect(arg.headers['private-token']).toEqual( diff --git a/test/unit/relay-response-headers-universal-form-url-headers.test.ts b/test/unit/relay-response-headers-universal-form-url-headers.test.ts index 7c5aa52a4..ea6c186ea 100644 --- a/test/unit/relay-response-headers-universal-form-url-headers.test.ts +++ b/test/unit/relay-response-headers-universal-form-url-headers.test.ts @@ -108,7 +108,7 @@ describe('header relay', () => { () => { expect(makeRequestToDownstream).toHaveBeenCalledTimes(1); const arg = mockedFn.mock.calls[0][0]; - expect(arg.headers['Content-Type']).toEqual( + expect(arg.headers['content-type']).toEqual( 'application/x-www-form-urlencoded', ); expect(arg.headers['private-token']).toEqual( @@ -174,7 +174,7 @@ describe('header relay', () => { () => { expect(makeRequestToDownstream).toHaveBeenCalledTimes(1); const arg = mockedFn.mock.calls[0][0]; - expect(arg.headers['Content-Type']).toEqual( + expect(arg.headers['content-type']).toEqual( 'application/x-www-form-urlencoded', ); expect(arg.headers['private-token']).toEqual('Bearer ${SECRET_TOKEN}'); From 0bc15b088dc0b82e992f69e0a1c779f9d758f433 Mon Sep 17 00:00:00 2001 From: assafenso Date: Sun, 10 Mar 2024 14:05:31 +0200 Subject: [PATCH 2/3] fix: fix checkmarx rules in apprisk json --- defaultFilters/apprisk.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/defaultFilters/apprisk.json b/defaultFilters/apprisk.json index 2ae38928f..1f1c7f2fa 100644 --- a/defaultFilters/apprisk.json +++ b/defaultFilters/apprisk.json @@ -11,25 +11,25 @@ { "//": "Get All Project Details", "method": "GET", - "path": "/projects", + "path": "/cxrestapi/projects", "origin": "https://${CHECKMARX}" }, { "//": "Get Remote Source Settings for GIT", "method": "GET", - "path": "/projects/:id/sourceCode/remoteSettings/git", + "path": "/cxrestapi/projects/:id/sourceCode/remoteSettings/git", "origin": "https://${CHECKMARX}" }, { "//": "Get All Scans for Project", "method": "GET", - "path": "/sast/scans", + "path": "/cxrestapi/sast/scans", "origin": "https://${CHECKMARX}" }, { "//": "Get Statistic Results by Scan Id", "method": "GET", - "path": "/sast/scans/:id/resultsStatistics", + "path": "/cxrestapi/sast/scans/:id/resultsStatistics", "origin": "https://${CHECKMARX}" } ] From 05dd2fb32f4f1e95d5b9fbb555f9cfbf976db4dd Mon Sep 17 00:00:00 2001 From: assafenso Date: Sun, 10 Mar 2024 14:52:41 +0200 Subject: [PATCH 3/3] fix: avoid content type header duplications fix: update content length after converting body to query params fix: add test for content length fix fix: lint --- lib/common/relay/prepareRequest.ts | 18 +++++- ...se-body-universal-form-url-encoded.test.ts | 60 +++++++++++++++++++ ...headers-universal-form-url-headers.test.ts | 2 + 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/lib/common/relay/prepareRequest.ts b/lib/common/relay/prepareRequest.ts index f1c9ed60f..d88b49d02 100644 --- a/lib/common/relay/prepareRequest.ts +++ b/lib/common/relay/prepareRequest.ts @@ -207,12 +207,19 @@ export const prepareRequestFromFilterResult = async ( logger.error({ error }, 'error while signing github commit'); } } + const urlencoded = 'application/x-www-form-urlencoded'; if ( payload.headers && - payload.headers['x-broker-content-type'] === - 'application/x-www-form-urlencoded' + payload.headers['x-broker-content-type'] === urlencoded ) { - payload.headers['content-type'] = 'application/x-www-form-urlencoded'; + const contentTypeHeader = 'content-type'; + //avoid duplication for content-type headers + Object.keys(payload.headers).forEach((header) => { + if (header.toLowerCase() === contentTypeHeader) { + delete payload.headers[header]; + } + }); + payload.headers[contentTypeHeader] = urlencoded; if (payload.body) { const jsonBody = JSON.parse(payload.body) as Record; const params = new URLSearchParams(); @@ -220,6 +227,11 @@ export const prepareRequestFromFilterResult = async ( params.append(key, value.toString()); } payload.body = params.toString(); + + //updating the content length after converting the body + const encoder = new TextEncoder(); + const byteArray = encoder.encode(payload.body); + payload.headers['Content-length'] = byteArray.length; } } diff --git a/test/unit/relay-response-body-universal-form-url-encoded.test.ts b/test/unit/relay-response-body-universal-form-url-encoded.test.ts index 501dc963c..0b345e831 100644 --- a/test/unit/relay-response-body-universal-form-url-encoded.test.ts +++ b/test/unit/relay-response-body-universal-form-url-encoded.test.ts @@ -185,4 +185,64 @@ describe('body relay', () => { }, ); }); + + it('calculate content type after converting request body', (done) => { + expect.hasAssertions(); + + const brokerToken = 'test-broker'; + + const config = { + universalBrokerEnabled: true, + connections: { + myconn: { + identifier: brokerToken, + HOST: 'localhost', + PORT: '8001', + }, + }, + }; + const options: LoadedClientOpts | LoadedServerOpts = { + filters: { + private: [ + { + method: 'any', + url: '/*', + }, + ], + public: [], + }, + config, + port: 8001, + loadedFilters: dummyLoadedFilters, + }; + + const route = relay(options, dummyWebsocketHandler)(brokerToken); + + const body = { + BROKER_VAR_SUB: ['url'], + url: '${HOST}:${PORT}/webhook', + }; + const headers = { + 'x-broker-content-type': 'application/x-www-form-urlencoded', + }; + + route( + { + url: '/', + method: 'POST', + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + body: Buffer.from(JSON.stringify(body)), + headers: headers, + }, + () => { + expect(makeRequestToDownstream).toHaveBeenCalledTimes(1); + const arg = mockedFn.mock.calls[0][0]; + + expect(arg.headers['Content-length']).toEqual(arg.body.length); + + done(); + }, + ); + }); }); diff --git a/test/unit/relay-response-headers-universal-form-url-headers.test.ts b/test/unit/relay-response-headers-universal-form-url-headers.test.ts index ea6c186ea..8beff7c8e 100644 --- a/test/unit/relay-response-headers-universal-form-url-headers.test.ts +++ b/test/unit/relay-response-headers-universal-form-url-headers.test.ts @@ -93,6 +93,7 @@ describe('header relay', () => { const headers = { 'x-broker-content-type': 'application/x-www-form-urlencoded', + 'Content-Type': 'application/json', 'x-broker-var-sub': 'private-token,replaceme', donttouch: 'not to be changed ${VALUE}', 'private-token': 'Bearer ${SECRET_TOKEN}', @@ -108,6 +109,7 @@ describe('header relay', () => { () => { expect(makeRequestToDownstream).toHaveBeenCalledTimes(1); const arg = mockedFn.mock.calls[0][0]; + expect(arg.headers['Content-Type']).toBeUndefined(); expect(arg.headers['content-type']).toEqual( 'application/x-www-form-urlencoded', );