From e5c2091e4aa12b2ba442d3441fa668c868fa126c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= <33655937+jkoenig134@users.noreply.github.com> Date: Mon, 3 Jun 2024 18:26:37 +0200 Subject: [PATCH] Fix/set proxy in axios default to false to prevent double proxying (#153) * chore: bump axios * fix: set proxy in axios default config to false to prevent double proxying * chore: update test * chore: version bumps * fix: update tests --- package-lock.json | 14 ++--- packages/runtime/package.json | 4 +- packages/transport/package.json | 4 +- .../transport/src/core/backbone/AuthClient.ts | 4 +- .../transport/src/core/backbone/RESTClient.ts | 59 +++++++++---------- .../test/core/backbone/Authentication.test.ts | 8 +-- .../modules/account/AccountController.test.ts | 6 +- .../test/testHelpers/RequestInterceptor.ts | 31 ++++------ 8 files changed, 59 insertions(+), 71 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e3f7abd0..8f8394180 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2849,9 +2849,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.1.tgz", - "integrity": "sha512-+LV37nQcd1EpFalkXksWNBiA17NZ5m5/WspmHGmZmdx1qBOg/VNq/c4eRJiA9VQQHBOs+N0ZhhdU10h2TyNK7Q==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -12330,7 +12330,7 @@ }, "packages/runtime": { "name": "@nmshd/runtime", - "version": "4.10.5", + "version": "4.10.6", "license": "MIT", "dependencies": { "@js-soft/docdb-querytranslator": "^1.1.4", @@ -12340,7 +12340,7 @@ "@nmshd/consumption": "3.11.0", "@nmshd/content": "2.10.1", "@nmshd/crypto": "2.0.6", - "@nmshd/transport": "2.7.4", + "@nmshd/transport": "2.7.5", "ajv": "^8.13.0", "ajv-errors": "^3.0.0", "ajv-formats": "^3.0.1", @@ -12390,14 +12390,14 @@ }, "packages/transport": { "name": "@nmshd/transport", - "version": "2.7.4", + "version": "2.7.5", "license": "MIT", "dependencies": { "@js-soft/docdb-access-abstractions": "1.0.4", "@js-soft/logging-abstractions": "^1.0.1", "@js-soft/simple-logger": "1.0.4", "@js-soft/ts-utils": "^2.3.3", - "axios": "^1.7.1", + "axios": "^1.7.2", "fast-json-patch": "^3.1.1", "form-data": "^4.0.0", "https-proxy-agent": "^7.0.4", diff --git a/packages/runtime/package.json b/packages/runtime/package.json index e54d0fc32..f506ea832 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@nmshd/runtime", - "version": "4.10.5", + "version": "4.10.6", "description": "The enmeshed client runtime.", "homepage": "https://enmeshed.eu", "repository": { @@ -59,7 +59,7 @@ "@nmshd/consumption": "3.11.0", "@nmshd/content": "2.10.1", "@nmshd/crypto": "2.0.6", - "@nmshd/transport": "2.7.4", + "@nmshd/transport": "2.7.5", "ajv": "^8.13.0", "ajv-errors": "^3.0.0", "ajv-formats": "^3.0.1", diff --git a/packages/transport/package.json b/packages/transport/package.json index dbabc782d..55c8122c7 100644 --- a/packages/transport/package.json +++ b/packages/transport/package.json @@ -1,6 +1,6 @@ { "name": "@nmshd/transport", - "version": "2.7.4", + "version": "2.7.5", "description": "The transport library handles backbone communication and content encryption.", "homepage": "https://enmeshed.eu", "repository": { @@ -62,7 +62,7 @@ "@js-soft/logging-abstractions": "^1.0.1", "@js-soft/simple-logger": "1.0.4", "@js-soft/ts-utils": "^2.3.3", - "axios": "^1.7.1", + "axios": "^1.7.2", "fast-json-patch": "^3.1.1", "form-data": "^4.0.0", "https-proxy-agent": "^7.0.4", diff --git a/packages/transport/src/core/backbone/AuthClient.ts b/packages/transport/src/core/backbone/AuthClient.ts index 0c1ab8505..7c3e34b55 100644 --- a/packages/transport/src/core/backbone/AuthClient.ts +++ b/packages/transport/src/core/backbone/AuthClient.ts @@ -3,8 +3,8 @@ import qs from "qs"; import { CoreDate } from "../types"; import { ClientResult } from "./ClientResult"; import { PlatformParameters } from "./PlatformParameters"; -import { RESTClient } from "./RESTClient"; import { RequestError } from "./RequestError"; +import { RESTClient } from "./RESTClient"; export interface IAuthenticationRequest { grantType: string; @@ -25,7 +25,7 @@ export class AuthClient extends RESTClient { let response; try { - response = await this.createAxios().post>( + response = await this.axiosInstance.post>( path, qs.stringify({ client_id: params.clientId, // eslint-disable-line @typescript-eslint/naming-convention diff --git a/packages/transport/src/core/backbone/RESTClient.ts b/packages/transport/src/core/backbone/RESTClient.ts index 0f6dc93fa..458aa89b8 100644 --- a/packages/transport/src/core/backbone/RESTClient.ts +++ b/packages/transport/src/core/backbone/RESTClient.ts @@ -49,6 +49,7 @@ export interface IRESTClientConfig { export class RESTClient { protected _logger: ILogger; protected _logDirective = RESTClientLogDirective.LogAll; + protected axiosInstance: AxiosInstance; public logRequest(): boolean { return this._logDirective === RESTClientLogDirective.LogRequest || this._logDirective === RESTClientLogDirective.LogAll; @@ -65,7 +66,7 @@ export class RESTClient { public constructor( protected readonly config: IRESTClientConfig, - protected requestConfig: AxiosRequestConfig = {} + requestConfig: AxiosRequestConfig = {} ) { const defaults: AxiosRequestConfig = { baseURL: config.baseUrl, @@ -75,22 +76,22 @@ export class RESTClient { maxContentLength: Infinity, maxBodyLength: Infinity, validateStatus: (status) => status < 300 || status === 400 || status === 404 || status === 500, - paramsSerializer: { dots: true, indexes: null } + paramsSerializer: { dots: true, indexes: null }, + headers: this.config.platformAdditionalHeaders, + proxy: false }; - if (this.config.platformAdditionalHeaders) { - defaults.headers = _.defaultsDeep({}, defaults.headers, this.config.platformAdditionalHeaders); - } + const resultingRequestConfig = _.defaultsDeep(defaults, requestConfig); - if (typeof window === "undefined" && process.env.https_proxy) { - const httpsProxy = process.env.https_proxy; - defaults.httpsAgent = new HttpsProxyAgent(httpsProxy, this.config.httpsAgentOptions); + if (typeof window === "undefined" && (process.env.https_proxy ?? process.env.HTTPS_PROXY)) { + const httpsProxy = (process.env.https_proxy ?? process.env.HTTPS_PROXY)!; + resultingRequestConfig.httpsAgent = new HttpsProxyAgent(httpsProxy, this.config.httpsAgentOptions); } else { try { // eslint-disable-next-line @typescript-eslint/no-require-imports const httpsAgent = require("https")?.Agent; - if (httpsAgent) defaults.httpsAgent = new httpsAgent(this.config.httpsAgentOptions); + if (httpsAgent) resultingRequestConfig.httpsAgent = new httpsAgent(this.config.httpsAgentOptions); } catch (e) { // ignore } @@ -100,23 +101,17 @@ export class RESTClient { // eslint-disable-next-line @typescript-eslint/no-require-imports const agent = require("http")?.Agent; - if (agent) defaults.httpAgent = new agent(this.config.httpAgentOptions); + if (agent) resultingRequestConfig.httpAgent = new agent(this.config.httpAgentOptions); } catch (e) { // ignore } - this.requestConfig = _.defaultsDeep(this.requestConfig, defaults); - this._logger = TransportLoggerFactory.getLogger(RESTClient); - } - - protected createAxios(): AxiosInstance { - const axiosInstance = axios.create(this.requestConfig); + this.axiosInstance = axios.create(resultingRequestConfig); if (this.config.debug) { - this.addAxiosLoggingInterceptors(axiosInstance); + this.addAxiosLoggingInterceptors(this.axiosInstance); } - return axiosInstance; } private addAxiosLoggingInterceptors(axiosInstance: AxiosInstance) { @@ -295,7 +290,7 @@ export class RESTClient { public async get(path: string, params: any = {}, config?: AxiosRequestConfig): Promise> { const id = await this.generateRequestId(); - const conf = _.defaultsDeep({ params: params }, config, this.requestConfig); + const conf = _.defaultsDeep({ params: params }, config); if (this.logRequest()) { const anyThis = this as any; if (anyThis._username) { @@ -306,7 +301,7 @@ export class RESTClient { } try { - const response = await this.createAxios().get>(path, conf); + const response = await this.axiosInstance.get>(path, conf); return this.getResult("GET", path, response, id); } catch (e: any) { const err = RequestError.fromAxiosError("GET", path, e, id); @@ -317,10 +312,10 @@ export class RESTClient { public async getPaged(path: string, params: any = {}, config?: AxiosRequestConfig, progessCallback?: PaginatorPercentageCallback): Promise>> { const id = await this.generateRequestId(); - const conf = _.defaultsDeep({ params: params }, config, this.requestConfig); + const conf = _.defaultsDeep({ params: params }, config); try { - const response = await this.createAxios().get>(path, conf); + const response = await this.axiosInstance.get>(path, conf); return this.getPaginator(path, response, id, params, progessCallback); } catch (e: any) { const err = RequestError.fromAxiosError("GET", path, e, id); @@ -331,7 +326,7 @@ export class RESTClient { public async post(path: string, data: any, params: any = {}, config?: AxiosRequestConfig): Promise> { const id = await this.generateRequestId(); - const conf = _.defaultsDeep({ params: params }, config, this.requestConfig); + const conf = _.defaultsDeep({ params: params }, config); if (this.logRequest()) { const anyThis = this as any; @@ -343,7 +338,7 @@ export class RESTClient { } try { - const response = await this.createAxios().post>(path, data, conf); + const response = await this.axiosInstance.post>(path, data, conf); return this.getResult("POST", path, response, id); } catch (e: any) { const err = RequestError.fromAxiosError("POST", path, e, id); @@ -377,7 +372,7 @@ export class RESTClient { } } - const conf = _.defaultsDeep({}, config, this.requestConfig); + const conf = _.defaultsDeep({}, config); let sendData = formData; if (typeof formData.getHeaders !== "undefined") { const h = formData.getHeaders(); @@ -397,7 +392,7 @@ export class RESTClient { } try { - const response = await this.createAxios().post>(path, sendData, conf); + const response = await this.axiosInstance.post>(path, sendData, conf); return this.getResult("POST-Upload", path, response, id); } catch (e: any) { const err = RequestError.fromAxiosError("POST-Upload", path, e, id); @@ -408,7 +403,7 @@ export class RESTClient { public async put(path: string, data: any, config?: AxiosRequestConfig): Promise> { const id = await this.generateRequestId(); - const conf = _.defaultsDeep({}, config, this.requestConfig); + const conf = _.defaultsDeep({}, config); if (this.logRequest()) { const anyThis = this as any; if (anyThis._username) { @@ -419,7 +414,7 @@ export class RESTClient { } try { - const response = await this.createAxios().put>(path, data, conf); + const response = await this.axiosInstance.put>(path, data, conf); return this.getResult("PUT", path, response, id); } catch (e: any) { const err = RequestError.fromAxiosError("PUT", path, e, id); @@ -430,7 +425,7 @@ export class RESTClient { public async delete(path: string, config?: AxiosRequestConfig): Promise> { const id = await this.generateRequestId(); - const conf = _.defaultsDeep({}, config, this.requestConfig); + const conf = _.defaultsDeep({}, config); if (this.logRequest()) { const anyThis = this as any; if (anyThis._username) { @@ -441,7 +436,7 @@ export class RESTClient { } try { - const response = await this.createAxios().delete>(path, conf); + const response = await this.axiosInstance.delete>(path, conf); return this.getResult("DELETE", path, response, id); } catch (e: any) { const err = RequestError.fromAxiosError("DELETE", path, e, id); @@ -452,7 +447,7 @@ export class RESTClient { public async download(path: string, config?: AxiosRequestConfig): Promise> { const id = await this.generateRequestId(); - const conf = _.defaultsDeep({}, config, this.requestConfig); + const conf = _.defaultsDeep({}, config); conf.responseType = "arraybuffer"; if (this.logRequest()) { const anyThis = this as any; @@ -464,7 +459,7 @@ export class RESTClient { } try { - const response = await this.createAxios().get(path, conf); + const response = await this.axiosInstance.get(path, conf); const platformParameters = this.extractPlatformParameters(response); this._logResponse(response, platformParameters, id, "GET-Download", path); diff --git a/packages/transport/test/core/backbone/Authentication.test.ts b/packages/transport/test/core/backbone/Authentication.test.ts index 00ed130aa..82607f06e 100644 --- a/packages/transport/test/core/backbone/Authentication.test.ts +++ b/packages/transport/test/core/backbone/Authentication.test.ts @@ -26,9 +26,9 @@ describe("AuthenticationTest", function () { }; if (config.baseUrl) { - const authenticatorAsAny = controller.parent.authenticator as any; - oldBaseUrl = authenticatorAsAny.authClient.requestConfig.baseURL; - authenticatorAsAny.authClient.requestConfig.baseURL = config.baseUrl; + const authenticator = controller.parent.authenticator; + oldBaseUrl = authenticator["authClient"]["axiosInstance"].defaults.baseURL!; + authenticator["authClient"]["axiosInstance"].defaults.baseURL = config.baseUrl; } } @@ -36,7 +36,7 @@ describe("AuthenticationTest", function () { const anyC = controller as any; anyC.parent.activeDevice.getCredentials = oldGetCredentials; if (oldBaseUrl) { - (controller.parent.authenticator as any).authClient.requestConfig.baseURL = oldBaseUrl; + controller.parent.authenticator["authClient"]["axiosInstance"].defaults.baseURL = oldBaseUrl; oldBaseUrl = ""; } anyC.client._logger = oldLogger; diff --git a/packages/transport/test/modules/account/AccountController.test.ts b/packages/transport/test/modules/account/AccountController.test.ts index caf442ce1..580d9f66a 100644 --- a/packages/transport/test/modules/account/AccountController.test.ts +++ b/packages/transport/test/modules/account/AccountController.test.ts @@ -7,7 +7,7 @@ describe("AccountController", function () { let transport: Transport; - let account: AccountController; + let account: AccountController | undefined; beforeAll(async function () { connection = await TestUtil.createDatabaseConnection(); @@ -20,13 +20,13 @@ describe("AccountController", function () { }); afterAll(async function () { - await account.close(); + await account?.close(); await connection.close(); }); // eslint-disable-next-line jest/expect-expect test("should init a second time", async function () { - await account.init(); + await account!.init(); }); }); diff --git a/packages/transport/test/testHelpers/RequestInterceptor.ts b/packages/transport/test/testHelpers/RequestInterceptor.ts index a4f4a5e5d..169646a8a 100644 --- a/packages/transport/test/testHelpers/RequestInterceptor.ts +++ b/packages/transport/test/testHelpers/RequestInterceptor.ts @@ -22,8 +22,6 @@ export class RequestInterceptor { return this._client; } - private oldCreateAxios: any; - public constructor(client: RESTClient) { this._client = client; this._measuringRequests = true; @@ -32,23 +30,18 @@ export class RequestInterceptor { private injectToClient(client: RESTClient) { const that = this; - const anyC = client as any; - this.oldCreateAxios = anyC.createAxios; - function newCreateAxios() { - const axiosInstance = that.oldCreateAxios.apply(anyC); - axiosInstance.interceptors.request.use((req: AxiosRequestConfig) => { - if (!that._measuringRequests) return req; - that._requests.push(req); - return req; - }); - axiosInstance.interceptors.response.use((res: AxiosResponse) => { - if (!that._measuringRequests) return res; - that._responses.push(res); - return res; - }); - return axiosInstance; - } - anyC.createAxios = newCreateAxios; + + const axiosInstance = client["axiosInstance"]; + axiosInstance.interceptors.request.use((req) => { + if (!that._measuringRequests) return req; + that._requests.push(req); + return req; + }); + axiosInstance.interceptors.response.use((res) => { + if (!that._measuringRequests) return res; + that._responses.push(res); + return res; + }); } public start(): this {