From d2cc89b0268afe0a4890cc3460a2d8618cb22dda Mon Sep 17 00:00:00 2001 From: Cory Johns Date: Mon, 2 Dec 2024 10:54:00 -0800 Subject: [PATCH 1/6] fix(api-gateway): support proxy when fetching jwk for token validation When fetching the JWK data needed to validate the auth token, the environment proxy settings are not honored. --- packages/cubejs-api-gateway/package.json | 1 + packages/cubejs-api-gateway/src/jwk.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/cubejs-api-gateway/package.json b/packages/cubejs-api-gateway/package.json index 743b05142bfa3..e6dac9a46637f 100644 --- a/packages/cubejs-api-gateway/package.json +++ b/packages/cubejs-api-gateway/package.json @@ -45,6 +45,7 @@ "moment-timezone": "^0.5.27", "nexus": "^1.1.0", "node-fetch": "^2.6.1", + "proxy-agent": "^6.4.0", "ramda": "^0.27.0", "uuid": "^8.3.2" }, diff --git a/packages/cubejs-api-gateway/src/jwk.ts b/packages/cubejs-api-gateway/src/jwk.ts index 06ae30ed6150a..9518b0b42a74a 100644 --- a/packages/cubejs-api-gateway/src/jwk.ts +++ b/packages/cubejs-api-gateway/src/jwk.ts @@ -3,6 +3,7 @@ import crypto from 'crypto'; import { asyncMemoizeBackground, asyncRetry, BackgroundMemoizeOptions } from '@cubejs-backend/shared'; import fetch from 'node-fetch'; import jwkToPem from 'jwk-to-pem'; +import { ProxyAgent } from 'proxy-agent'; import { JWTOptions } from './interfaces'; const HEADER_REGEXP = /([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?/g; @@ -51,7 +52,7 @@ export type JWKsFetcherOptions = Pick, 'onBac export const createJWKsFetcher = (jwtOptions: JWTOptions, options: JWKsFetcherOptions) => { const fetchJwkUrl = asyncMemoizeBackground(async (url: string) => { - const response = await asyncRetry(() => fetch(url), { + const response = await asyncRetry(() => fetch(url, { agent: new ProxyAgent() }), { times: jwtOptions.jwkRetry || 3, }); const json = await response.json(); From ec9bafb4fed42ee72bbf1995e7cff1e5ddac2d5f Mon Sep 17 00:00:00 2001 From: Cory Johns Date: Mon, 27 Jan 2025 14:52:12 -0500 Subject: [PATCH 2/6] Move proxy fix to cubejs-backend-shared instead and use that --- packages/cubejs-api-gateway/package.json | 1 - packages/cubejs-api-gateway/src/jwk.ts | 5 ++--- packages/cubejs-backend-shared/package.json | 2 +- packages/cubejs-backend-shared/src/proxy.ts | 7 +++---- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/cubejs-api-gateway/package.json b/packages/cubejs-api-gateway/package.json index c440807239d9f..ab4e6eb91ee1d 100644 --- a/packages/cubejs-api-gateway/package.json +++ b/packages/cubejs-api-gateway/package.json @@ -46,7 +46,6 @@ "moment-timezone": "^0.5.27", "nexus": "^1.1.0", "node-fetch": "^2.6.1", - "proxy-agent": "^6.4.0", "ramda": "^0.27.0", "uuid": "^8.3.2" }, diff --git a/packages/cubejs-api-gateway/src/jwk.ts b/packages/cubejs-api-gateway/src/jwk.ts index 9518b0b42a74a..84f31aca63063 100644 --- a/packages/cubejs-api-gateway/src/jwk.ts +++ b/packages/cubejs-api-gateway/src/jwk.ts @@ -1,9 +1,8 @@ /* eslint-disable no-restricted-syntax */ import crypto from 'crypto'; -import { asyncMemoizeBackground, asyncRetry, BackgroundMemoizeOptions } from '@cubejs-backend/shared'; +import { asyncMemoizeBackground, asyncRetry, BackgroundMemoizeOptions, getHttpAgentForProxySettings } from '@cubejs-backend/shared'; import fetch from 'node-fetch'; import jwkToPem from 'jwk-to-pem'; -import { ProxyAgent } from 'proxy-agent'; import { JWTOptions } from './interfaces'; const HEADER_REGEXP = /([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?/g; @@ -52,7 +51,7 @@ export type JWKsFetcherOptions = Pick, 'onBac export const createJWKsFetcher = (jwtOptions: JWTOptions, options: JWKsFetcherOptions) => { const fetchJwkUrl = asyncMemoizeBackground(async (url: string) => { - const response = await asyncRetry(() => fetch(url, { agent: new ProxyAgent() }), { + const response = await asyncRetry(() => fetch(url, { agent: await getHttpAgentForProxySettings() }), { times: jwtOptions.jwkRetry || 3, }); const json = await response.json(); diff --git a/packages/cubejs-backend-shared/package.json b/packages/cubejs-backend-shared/package.json index d0a59c6b98f42..1055c72177902 100644 --- a/packages/cubejs-backend-shared/package.json +++ b/packages/cubejs-backend-shared/package.json @@ -42,7 +42,7 @@ "decompress": "^4.2.1", "env-var": "^6.3.0", "fs-extra": "^9.1.0", - "http-proxy-agent": "^4.0.1", + "proxy-agent": "^6.4.0", "moment-range": "^4.0.1", "moment-timezone": "^0.5.33", "node-fetch": "^2.6.1", diff --git a/packages/cubejs-backend-shared/src/proxy.ts b/packages/cubejs-backend-shared/src/proxy.ts index 5f7ace5a654ad..923d41b6cf847 100644 --- a/packages/cubejs-backend-shared/src/proxy.ts +++ b/packages/cubejs-backend-shared/src/proxy.ts @@ -1,5 +1,5 @@ import { exec } from 'child_process'; -import HttpsProxyAgent from 'http-proxy-agent'; +import { ProxyAgent } from 'proxy-agent'; function getCommandOutput(command: string) { return new Promise((resolve, reject) => { @@ -14,6 +14,7 @@ function getCommandOutput(command: string) { }); } +// deprecated, use ProxyAgent instead export async function getProxySettings() { const [proxy] = ( await Promise.all([getCommandOutput('npm config -g get https-proxy'), getCommandOutput('npm config -g get proxy')]) @@ -25,7 +26,5 @@ export async function getProxySettings() { } export async function getHttpAgentForProxySettings() { - const proxy = await getProxySettings(); - - return proxy ? HttpsProxyAgent(proxy) : undefined; + return new ProxyAgent(); } From f4a1687fd232d023d3f3767f131a882f85c4c2c8 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Thu, 27 Feb 2025 20:07:20 +0200 Subject: [PATCH 3/6] fix errors and mark getProxySettings() as deprecated --- packages/cubejs-api-gateway/src/jwk.ts | 9 +++++++-- packages/cubejs-backend-shared/src/proxy.ts | 12 +++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/cubejs-api-gateway/src/jwk.ts b/packages/cubejs-api-gateway/src/jwk.ts index 84f31aca63063..baa2494707d33 100644 --- a/packages/cubejs-api-gateway/src/jwk.ts +++ b/packages/cubejs-api-gateway/src/jwk.ts @@ -1,6 +1,11 @@ /* eslint-disable no-restricted-syntax */ import crypto from 'crypto'; -import { asyncMemoizeBackground, asyncRetry, BackgroundMemoizeOptions, getHttpAgentForProxySettings } from '@cubejs-backend/shared'; +import { + asyncMemoizeBackground, + asyncRetry, + BackgroundMemoizeOptions, + getHttpAgentForProxySettings +} from '@cubejs-backend/shared'; import fetch from 'node-fetch'; import jwkToPem from 'jwk-to-pem'; import { JWTOptions } from './interfaces'; @@ -51,7 +56,7 @@ export type JWKsFetcherOptions = Pick, 'onBac export const createJWKsFetcher = (jwtOptions: JWTOptions, options: JWKsFetcherOptions) => { const fetchJwkUrl = asyncMemoizeBackground(async (url: string) => { - const response = await asyncRetry(() => fetch(url, { agent: await getHttpAgentForProxySettings() }), { + const response = await asyncRetry(async () => fetch(url, { agent: await getHttpAgentForProxySettings() }), { times: jwtOptions.jwkRetry || 3, }); const json = await response.json(); diff --git a/packages/cubejs-backend-shared/src/proxy.ts b/packages/cubejs-backend-shared/src/proxy.ts index 923d41b6cf847..30af2131d2617 100644 --- a/packages/cubejs-backend-shared/src/proxy.ts +++ b/packages/cubejs-backend-shared/src/proxy.ts @@ -14,7 +14,10 @@ function getCommandOutput(command: string) { }); } -// deprecated, use ProxyAgent instead +/** + * @deprecated + * use ProxyAgent instead + */ export async function getProxySettings() { const [proxy] = ( await Promise.all([getCommandOutput('npm config -g get https-proxy'), getCommandOutput('npm config -g get proxy')]) @@ -26,5 +29,12 @@ export async function getProxySettings() { } export async function getHttpAgentForProxySettings() { + const proxy = await getProxySettings(); + + if (proxy) { + console.warn('Npm proxy settings are deprecated. Please use HTTP_PROXY, HTTPS_PROXY environment variables instead.'); + return proxy; + } + return new ProxyAgent(); } From 522b087a454f47711556ecfb40e4680475a1101e Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Thu, 27 Feb 2025 20:12:55 +0200 Subject: [PATCH 4/6] optimize yarn.lock --- yarn.lock | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4134006c9f296..102f410395924 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18252,15 +18252,7 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-proxy-agent@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" - integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== - dependencies: - agent-base "^7.1.0" - debug "^4.3.4" - -http-proxy-agent@^7.0.1, http-proxy-agent@^7.0.2: +http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1, http-proxy-agent@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== @@ -18318,7 +18310,7 @@ http-signature@~1.4.0: jsprim "^2.0.2" sshpk "^1.18.0" -https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: +https-proxy-agent@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== @@ -18326,23 +18318,15 @@ https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168" - integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== - dependencies: - agent-base "^7.0.2" - debug "4" - -https-proxy-agent@^7.0.1: - version "7.0.2" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" - integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== dependencies: - agent-base "^7.0.2" + agent-base "6" debug "4" -https-proxy-agent@^7.0.6: +https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== From 99959ee33ae2779b0727773b63b1810465318906 Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Thu, 27 Feb 2025 20:34:49 +0200 Subject: [PATCH 5/6] fix proxy --- packages/cubejs-backend-shared/package.json | 3 ++- packages/cubejs-backend-shared/src/proxy.ts | 3 ++- yarn.lock | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/cubejs-backend-shared/package.json b/packages/cubejs-backend-shared/package.json index e12aa7f01dd28..e5a48df43171a 100644 --- a/packages/cubejs-backend-shared/package.json +++ b/packages/cubejs-backend-shared/package.json @@ -42,10 +42,11 @@ "decompress": "^4.2.1", "env-var": "^6.3.0", "fs-extra": "^9.1.0", - "proxy-agent": "^6.4.0", + "https-proxy-agent": "^7.0.6", "moment-range": "^4.0.2", "moment-timezone": "^0.5.47", "node-fetch": "^2.6.1", + "proxy-agent": "^6.5.0", "shelljs": "^0.8.5", "throttle-debounce": "^3.0.1", "uuid": "^8.3.2" diff --git a/packages/cubejs-backend-shared/src/proxy.ts b/packages/cubejs-backend-shared/src/proxy.ts index 30af2131d2617..c75a92e1a2ff2 100644 --- a/packages/cubejs-backend-shared/src/proxy.ts +++ b/packages/cubejs-backend-shared/src/proxy.ts @@ -1,5 +1,6 @@ import { exec } from 'child_process'; import { ProxyAgent } from 'proxy-agent'; +import { HttpsProxyAgent } from 'https-proxy-agent'; function getCommandOutput(command: string) { return new Promise((resolve, reject) => { @@ -33,7 +34,7 @@ export async function getHttpAgentForProxySettings() { if (proxy) { console.warn('Npm proxy settings are deprecated. Please use HTTP_PROXY, HTTPS_PROXY environment variables instead.'); - return proxy; + return new HttpsProxyAgent(proxy); } return new ProxyAgent(); diff --git a/yarn.lock b/yarn.lock index 102f410395924..9c44f534d6663 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24509,7 +24509,7 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -proxy-agent@^6.4.0: +proxy-agent@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.5.0.tgz#9e49acba8e4ee234aacb539f89ed9c23d02f232d" integrity sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A== From 77e704fead50305fa76feb9373896954dd0f739b Mon Sep 17 00:00:00 2001 From: Konstantin Burkalev Date: Wed, 5 Mar 2025 19:37:25 +0200 Subject: [PATCH 6/6] Cache npm proxy --- packages/cubejs-backend-shared/src/proxy.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/cubejs-backend-shared/src/proxy.ts b/packages/cubejs-backend-shared/src/proxy.ts index c75a92e1a2ff2..55ecf84e8cb3d 100644 --- a/packages/cubejs-backend-shared/src/proxy.ts +++ b/packages/cubejs-backend-shared/src/proxy.ts @@ -2,6 +2,9 @@ import { exec } from 'child_process'; import { ProxyAgent } from 'proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent'; +let npmProxy: string; +let npmProxyInitialized = false; + function getCommandOutput(command: string) { return new Promise((resolve, reject) => { exec(command, (error, stdout) => { @@ -19,22 +22,26 @@ function getCommandOutput(command: string) { * @deprecated * use ProxyAgent instead */ -export async function getProxySettings() { +export async function getProxySettings(): Promise { const [proxy] = ( await Promise.all([getCommandOutput('npm config -g get https-proxy'), getCommandOutput('npm config -g get proxy')]) ) .map((s) => s.trim()) .filter((s) => !['null', 'undefined', ''].includes(s)); + npmProxyInitialized = true; + return proxy; } export async function getHttpAgentForProxySettings() { - const proxy = await getProxySettings(); + if (!npmProxyInitialized) { + npmProxy = await getProxySettings(); + } - if (proxy) { + if (npmProxy) { console.warn('Npm proxy settings are deprecated. Please use HTTP_PROXY, HTTPS_PROXY environment variables instead.'); - return new HttpsProxyAgent(proxy); + return new HttpsProxyAgent(npmProxy); } return new ProxyAgent();