From 70fd3d719b6d0bca1ea5c2abea102e784e2a82f5 Mon Sep 17 00:00:00 2001 From: Reinier Criel Date: Thu, 4 Dec 2025 13:13:39 -0800 Subject: [PATCH] Some small tweaks --- package-lock.json | 20 +++++++ package.json | 8 ++- .../src/registryProxy/tunnelRequestHandler.js | 52 +++---------------- 3 files changed, 33 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3fb6a1c..cd466da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,11 @@ "packages/*", "test/e2e" ], + "dependencies": { + "proxy-from-env": "^1.1.0" + }, "devDependencies": { + "@types/proxy-from-env": "^1.0.4", "@yao-pkg/pkg": "6.10.1", "esbuild": "^0.27.0", "oxlint": "^1.22.0" @@ -822,6 +826,16 @@ "@types/node": "*" } }, + "node_modules/@types/proxy-from-env": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/proxy-from-env/-/proxy-from-env-1.0.4.tgz", + "integrity": "sha512-TPR9/bCZAr3V1eHN4G3LD3OLicdJjqX1QRXWuNcCYgE66f/K8jO2ZRtHxI2D9MbnuUP6+qiKSS8eUHp6TFHGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/retry": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.5.tgz", @@ -2542,6 +2556,12 @@ "node": ">=10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pump": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", diff --git a/package.json b/package.json index 2793f9c..8217c76 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,12 @@ "author": "Aikido Security", "license": "AGPL-3.0-or-later", "devDependencies": { - "oxlint": "^1.22.0", + "@types/proxy-from-env": "^1.0.4", + "@yao-pkg/pkg": "6.10.1", "esbuild": "^0.27.0", - "@yao-pkg/pkg": "6.10.1" + "oxlint": "^1.22.0" + }, + "dependencies": { + "proxy-from-env": "^1.1.0" } } diff --git a/packages/safe-chain/src/registryProxy/tunnelRequestHandler.js b/packages/safe-chain/src/registryProxy/tunnelRequestHandler.js index 83a9d20..6a66afd 100644 --- a/packages/safe-chain/src/registryProxy/tunnelRequestHandler.js +++ b/packages/safe-chain/src/registryProxy/tunnelRequestHandler.js @@ -1,4 +1,5 @@ import * as net from "net"; +import { getProxyForUrl } from "proxy-from-env"; import { ui } from "../environment/userInteraction.js"; /** @@ -9,21 +10,13 @@ import { ui } from "../environment/userInteraction.js"; * @returns {void} */ export function tunnelRequest(req, clientSocket, head) { - const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy; - const noProxy = process.env.NO_PROXY || process.env.no_proxy; + // req.url in a CONNECT request is usually "hostname:port" + // We assume HTTPS for CONNECT requests to ensure we check HTTPS_PROXY + const proxyUrl = getProxyForUrl(`https://${req.url}`); - if (httpsProxy && !shouldBypassProxy(req.url, noProxy)) { - // If an HTTPS proxy is set, tunnel the request via the proxy - // This is the system proxy, not the safe-chain proxy - // The package manager will run via the safe-chain proxy - // The safe-chain proxy will then send the request to the system proxy - // Typical flow: package manager -> safe-chain proxy -> system proxy -> destination - - // There are 2 processes involved in this: - // 1. Safe-chain process: has HTTPS_PROXY set to system proxy - // 2. Package manager process: has HTTPS_PROXY set to safe-chain proxy - - tunnelRequestViaProxy(req, clientSocket, head, httpsProxy); + if (proxyUrl) { + // If a proxy is returned, it means we should use it (NO_PROXY check passed) + tunnelRequestViaProxy(req, clientSocket, head, proxyUrl); } else { tunnelRequestToDestination(req, clientSocket, head); } @@ -156,35 +149,4 @@ function tunnelRequestViaProxy(req, clientSocket, head, proxyUrl) { }); } -/** - * @param {string | undefined} url - * @param {string | undefined} noProxy - * @returns {boolean} - */ -function shouldBypassProxy(url, noProxy) { - if (!url || !noProxy) { - return false; - } - if (noProxy === "*") { - return true; - } - - try { - const { hostname } = new URL(`http://${url}`); - const noProxyList = noProxy.split(",").map((s) => s.trim().toLowerCase()); - - return noProxyList.some((noProxyItem) => { - if (!noProxyItem) return false; - if (noProxyItem === hostname) return true; - // Handle domain matching (e.g. .example.com matches sub.example.com) - if (noProxyItem.startsWith(".") && hostname.endsWith(noProxyItem)) - return true; - // Handle implicit domain matching (e.g. example.com matches sub.example.com) - if (hostname.endsWith(`.${noProxyItem}`)) return true; - return false; - }); - } catch { - return false; - } -}