proxy-from-env
Advanced tools
+105
| 'use strict'; | ||
| var DEFAULT_PORTS = { | ||
| ftp: 21, | ||
| gopher: 70, | ||
| http: 80, | ||
| https: 443, | ||
| ws: 80, | ||
| wss: 443, | ||
| }; | ||
| function parseUrl(urlString) { | ||
| try { | ||
| return new URL(urlString); | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
| /** | ||
| * @param {string|object|URL} url - The URL as a string or URL instance, or a | ||
| * compatible object (such as the result from legacy url.parse). | ||
| * @return {string} The URL of the proxy that should handle the request to the | ||
| * given URL. If no proxy is set, this will be an empty string. | ||
| */ | ||
| function getProxyForUrl(url) { | ||
| var parsedUrl = (typeof url === 'string' ? parseUrl(url) : url) || {}; | ||
| var proto = parsedUrl.protocol; | ||
| var hostname = parsedUrl.host; | ||
| var port = parsedUrl.port; | ||
| if (typeof hostname !== 'string' || !hostname || typeof proto !== 'string') { | ||
| return ''; // Don't proxy URLs without a valid scheme or host. | ||
| } | ||
| proto = proto.split(':', 1)[0]; | ||
| // Stripping ports in this way instead of using parsedUrl.hostname to make | ||
| // sure that the brackets around IPv6 addresses are kept. | ||
| hostname = hostname.replace(/:\d*$/, ''); | ||
| port = parseInt(port) || DEFAULT_PORTS[proto] || 0; | ||
| if (!shouldProxy(hostname, port)) { | ||
| return ''; // Don't proxy URLs that match NO_PROXY. | ||
| } | ||
| var proxy = getEnv(proto + '_proxy') || getEnv('all_proxy'); | ||
| if (proxy && proxy.indexOf('://') === -1) { | ||
| // Missing scheme in proxy, default to the requested URL's scheme. | ||
| proxy = proto + '://' + proxy; | ||
| } | ||
| return proxy; | ||
| } | ||
| /** | ||
| * Determines whether a given URL should be proxied. | ||
| * | ||
| * @param {string} hostname - The host name of the URL. | ||
| * @param {number} port - The effective port of the URL. | ||
| * @returns {boolean} Whether the given URL should be proxied. | ||
| * @private | ||
| */ | ||
| function shouldProxy(hostname, port) { | ||
| var NO_PROXY = getEnv('no_proxy').toLowerCase(); | ||
| if (!NO_PROXY) { | ||
| return true; // Always proxy if NO_PROXY is not set. | ||
| } | ||
| if (NO_PROXY === '*') { | ||
| return false; // Never proxy if wildcard is set. | ||
| } | ||
| return NO_PROXY.split(/[,\s]/).every(function(proxy) { | ||
| if (!proxy) { | ||
| return true; // Skip zero-length hosts. | ||
| } | ||
| var parsedProxy = proxy.match(/^(.+):(\d+)$/); | ||
| var parsedProxyHostname = parsedProxy ? parsedProxy[1] : proxy; | ||
| var parsedProxyPort = parsedProxy ? parseInt(parsedProxy[2]) : 0; | ||
| if (parsedProxyPort && parsedProxyPort !== port) { | ||
| return true; // Skip if ports don't match. | ||
| } | ||
| if (!/^[.*]/.test(parsedProxyHostname)) { | ||
| // No wildcards, so stop proxying if there is an exact match. | ||
| return hostname !== parsedProxyHostname; | ||
| } | ||
| if (parsedProxyHostname.charAt(0) === '*') { | ||
| // Remove leading wildcard. | ||
| parsedProxyHostname = parsedProxyHostname.slice(1); | ||
| } | ||
| // Stop proxying if the hostname ends with the no_proxy host. | ||
| return !hostname.endsWith(parsedProxyHostname); | ||
| }); | ||
| } | ||
| /** | ||
| * Get the value for an environment variable. | ||
| * | ||
| * @param {string} key - The name of the environment variable. | ||
| * @return {string} The value of the environment variable. | ||
| * @private | ||
| */ | ||
| function getEnv(key) { | ||
| return process.env[key.toLowerCase()] || process.env[key.toUpperCase()] || ''; | ||
| } | ||
| exports.getProxyForUrl = getProxyForUrl; |
+12
-4
| { | ||
| "name": "proxy-from-env", | ||
| "version": "2.0.0", | ||
| "version": "2.1.0", | ||
| "description": "Offers getProxyForUrl to get the proxy URL for a URL, respecting the *_PROXY (e.g. HTTP_PROXY) and NO_PROXY environment variables.", | ||
| "main": "index.js", | ||
| "exports": "./index.js", | ||
| "main": "index.cjs", | ||
| "exports": { | ||
| "import": "./index.js", | ||
| "require": "./index.cjs" | ||
| }, | ||
| "files": ["index.js", "index.cjs"], | ||
| "scripts": { | ||
| "lint": "eslint *.js *.mjs", | ||
| "lint": "eslint *.js *.mjs *.cjs", | ||
| "test": "node --test ./test.js", | ||
| "test-require": "node ./test-require.cjs", | ||
| "test-coverage": "node --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info ./test.js", | ||
@@ -34,3 +39,6 @@ "test-coverage-as-html": "npm run test-coverage && genhtml lcov.info -o coverage/" | ||
| "type": "module", | ||
| "engines": { | ||
| "node": ">=10" | ||
| }, | ||
| "sideEffects": false | ||
| } |
+11
-2
@@ -14,2 +14,11 @@ # proxy-from-env | ||
| If your application makes important (security) decisions based on the URL, be | ||
| consistent in the mechanism to parse and validate URLs, as differences in URL | ||
| parsing behavior can affect the outcome of proxy resolution. | ||
| Strings are parsed with the standard `URL` API, as of `proxy-from-env@2.0.0`. | ||
| Older versions relied on the (now deprecated) `url.parse` method instead. | ||
| Invalid values in environment variables are not handled by the library | ||
| ([#41](https://github.com/Rob--W/proxy-from-env/issues/41)). | ||
| It is your responsibility to actually proxy the request using the given URL. | ||
@@ -94,4 +103,4 @@ | ||
| ## Environment variables | ||
| The environment variables can be specified in lowercase or uppercase, with the | ||
| lowercase name having precedence over the uppercase variant. A variable that is | ||
| The environment variables can be specified in all lowercase or all uppercase, | ||
| with lowercase taking precedence over the uppercase variant. A variable that is | ||
| not set has the same meaning as a variable that is set but has no value. | ||
@@ -98,0 +107,0 @@ |
| on: [ push, pull_request, workflow_dispatch ] | ||
| name: Tests | ||
| jobs: | ||
| lint: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: actions/setup-node@v6 | ||
| - run: npm install # install eslint | ||
| - run: npm run lint | ||
| test-node: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| node_version: | ||
| # The oldest Node.js version that we can still test. | ||
| # Node v20.11.0+ required for --test-reporter=lcov (test-coverage) | ||
| # Node v20.19.0 required for require(esm) require("proxy-from-env") | ||
| - 20 | ||
| # Other Node.js versions that have not reached End-of-life status per | ||
| # https://nodejs.org/en/about/previous-releases | ||
| - 24 | ||
| - 22 | ||
| - 25 | ||
| # ^ latest version may be an unstable (odd) version when the latest | ||
| # (even) version is not yet available. | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - name: Use Node.js ${{ matrix.node_version }} | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ matrix.node_version }} | ||
| # Note: no npm ci / npm install: | ||
| # The package has no non-dev dependencies. | ||
| # We rely on Node.js's built-in test module and reporter, | ||
| # and do not require any dev dependencies either. | ||
| # test-coverage will also run the tests, but does not print helpful output upon test failure. | ||
| # So we also run the tests separately. | ||
| - run: npm test | ||
| # note: --experimental-test-coverage requires Node v18.15.0+ | ||
| # note: --test-reporter=lcov requires Node v20.11.0+ (https://github.com/nodejs/node/pull/50018) | ||
| - run: npm run test-coverage | ||
| - name: Send coverage for Node ${{ matrix.node_version }} to Coveralls | ||
| uses: coverallsapp/github-action@v2 | ||
| with: | ||
| parallel: true | ||
| file: lcov.info | ||
| flag-name: coverage-node-${{ matrix.node_version }} | ||
| coveralls: | ||
| name: Report to Coveralls | ||
| needs: [ test-node ] | ||
| if: ${{ github.repository == 'Rob--W/proxy-from-env' }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: coverallsapp/github-action@v2 | ||
| with: | ||
| parallel-finished: true |
| import {defineConfig, globalIgnores} from 'eslint/config'; | ||
| // These rules are from node-style-guide@1.0.0 to ensure some consistent style. | ||
| // Many of these rules are depecated and will be removed in eslint@11. At that | ||
| // point we should consider migration to @stylistic/eslint-plugin or prettier. | ||
| const rules = { | ||
| 'array-bracket-spacing': [2, 'never'], | ||
| 'block-scoped-var': 2, | ||
| 'brace-style': [2, '1tbs'], | ||
| 'camelcase': 1, | ||
| 'computed-property-spacing': [2, 'never'], | ||
| 'curly': 2, | ||
| 'eol-last': 2, | ||
| 'eqeqeq': [2, 'smart'], | ||
| 'max-depth': [1, 3], | ||
| 'max-len': [1, 80], | ||
| 'max-statements': [1, 15], | ||
| 'new-cap': 1, | ||
| 'no-extend-native': 2, | ||
| 'no-mixed-spaces-and-tabs': 2, | ||
| 'no-trailing-spaces': 2, | ||
| 'no-unused-vars': 1, | ||
| 'no-use-before-define': [2, 'nofunc'], | ||
| 'object-curly-spacing': [2, 'never'], | ||
| 'quotes': [2, 'single', 'avoid-escape'], | ||
| 'semi': [2, 'always'], | ||
| 'keyword-spacing': [2, {'before': true, 'after': true}], | ||
| 'space-unary-ops': 2 | ||
| }; | ||
| export default defineConfig([ | ||
| globalIgnores([ | ||
| 'coverage/', // Generated by: npm run test-coverage-as-html | ||
| ]), | ||
| { | ||
| languageOptions: { | ||
| globals: { | ||
| // Minimum set of globals, supported in Node. | ||
| process: 'readonly', | ||
| } | ||
| }, | ||
| rules, | ||
| }, | ||
| { | ||
| files: ['test.js'], | ||
| languageOptions: { | ||
| globals: { | ||
| // Minimum set of globals, supported in Node. | ||
| process: 'readonly', | ||
| } | ||
| }, | ||
| rules, | ||
| } | ||
| ]); |
-432
| /* eslint max-statements:0 */ | ||
| 'use strict'; | ||
| import {describe, it} from 'node:test'; | ||
| import assert from 'node:assert'; | ||
| import {parse as parseUrl} from 'node:url'; | ||
| import {getProxyForUrl} from 'proxy-from-env'; | ||
| // Runs the callback with process.env temporarily set to env. | ||
| function runWithEnv(env, callback) { | ||
| var originalEnv = process.env; | ||
| process.env = env; | ||
| try { | ||
| callback(); | ||
| } finally { | ||
| process.env = originalEnv; | ||
| } | ||
| } | ||
| // Defines a test case that checks whether getProxyForUrl(input) === expected. | ||
| function testProxyUrl(env, expected, input) { | ||
| assert(typeof env === 'object' && env !== null); | ||
| // Copy object to make sure that the in param does not get modified between | ||
| // the call of this function and the use of it below. | ||
| env = JSON.parse(JSON.stringify(env)); | ||
| var title = 'getProxyForUrl(' + JSON.stringify(input) + ')' + | ||
| ' === ' + JSON.stringify(expected); | ||
| it(title, function() { | ||
| var actual; | ||
| runWithEnv(env, function() { | ||
| actual = getProxyForUrl(input); | ||
| }); | ||
| assert.strictEqual(actual, expected); | ||
| }); | ||
| } | ||
| describe('getProxyForUrl', function() { | ||
| describe('No proxy variables', function() { | ||
| var env = {}; | ||
| testProxyUrl(env, '', 'http://example.com'); | ||
| testProxyUrl(env, '', 'https://example.com'); | ||
| testProxyUrl(env, '', 'ftp://example.com'); | ||
| }); | ||
| describe('Invalid URLs', function() { | ||
| var env = {}; | ||
| env.ALL_PROXY = 'http://unexpected.proxy'; | ||
| testProxyUrl(env, '', 'bogus'); | ||
| testProxyUrl(env, '', '//example.com'); | ||
| testProxyUrl(env, '', '://example.com'); | ||
| testProxyUrl(env, '', '://'); | ||
| testProxyUrl(env, '', '/path'); | ||
| testProxyUrl(env, '', ''); | ||
| testProxyUrl(env, '', 'http:'); | ||
| testProxyUrl(env, '', 'http:/'); | ||
| testProxyUrl(env, '', 'http://'); | ||
| testProxyUrl(env, '', 'prototype://'); | ||
| testProxyUrl(env, '', 'hasOwnProperty://'); | ||
| testProxyUrl(env, '', '__proto__://'); | ||
| testProxyUrl(env, '', 'http://abc\x00/'); | ||
| testProxyUrl(env, '', undefined); | ||
| testProxyUrl(env, '', null); | ||
| testProxyUrl(env, '', {}); | ||
| testProxyUrl(env, '', {host: 'x', protocol: 1}); | ||
| testProxyUrl(env, '', {host: 1, protocol: 'x'}); | ||
| describe('difference between url.parse and WHATWG URL', function() { | ||
| // Node 24 and later raise the following warning when url.parse is used: | ||
| // | ||
| // (node:11623) [DEP0169] DeprecationWarning: `url.parse()` behavior is | ||
| // not standardized and prone to errors that have security implications. | ||
| // Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` | ||
| // vulnerabilities. | ||
| // | ||
| // The above refers to https://hackerone.com/reports/678487 which shows | ||
| // that a bare percentage sign is parsed inconsistently: | ||
| // - `url.parse` splits hosts. | ||
| // - WHATWG `URL` constructor raised an error. | ||
| // | ||
| // This test case shows the difference. | ||
| // | ||
| // For comparison: | ||
| // - curl (8.17.0) refuses to connect: | ||
| // $ http_proxy=http://localhost:1337 curl http://bad% | ||
| // curl:(3) URL rejected: Bad hostname | ||
| // - wget (GNU wget 1.25.0) passes "bad%" as Host header: | ||
| // $ http_proxy=http://localhost:1337 wget http://bad% | ||
| // (nc -l 1337 receives request with "bad% as Host header) | ||
| // - Python (3.13.11) passes "bad%" as Host header: | ||
| // $ http_proxy=http://localhost:1337 python3 -c \ | ||
| // 'import urllib.request;urllib.request.urlopen("http://bad%")' | ||
| // (nc -l 1337 receives request with "bad% as Host header) | ||
| // A canonical URL does not have a single "%". | ||
| var badUrl = 'http://bad%'; | ||
| // proxy-from-env@1.1.0 and earlier accepted bad URLs: | ||
| testProxyUrl(env, 'http://unexpected.proxy', parseUrl(badUrl)); | ||
| // Sanity check: WHATWG URL constructor rejects badUrl. | ||
| assert(!URL.canParse(badUrl)); | ||
| // Verify current proxy-from-env behavior. Should reject without throwing. | ||
| testProxyUrl(env, '', badUrl); | ||
| }); | ||
| }); | ||
| describe('http_proxy and HTTP_PROXY', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://http-proxy'; | ||
| testProxyUrl(env, '', 'https://example'); | ||
| testProxyUrl(env, 'http://http-proxy', 'http://example'); | ||
| testProxyUrl(env, 'http://http-proxy', parseUrl('http://example')); | ||
| // eslint-disable-next-line camelcase | ||
| env.http_proxy = 'http://priority'; | ||
| testProxyUrl(env, 'http://priority', 'http://example'); | ||
| }); | ||
| describe('http_proxy with non-sensical value', function() { | ||
| var env = {}; | ||
| // Crazy values should be passed as-is. It is the responsibility of the | ||
| // one who launches the application that the value makes sense. | ||
| // TODO: Should we be stricter and perform validation? | ||
| env.HTTP_PROXY = 'Crazy \n!() { ::// }'; | ||
| testProxyUrl(env, 'Crazy \n!() { ::// }', 'http://wow'); | ||
| // The implementation assumes that the HTTP_PROXY environment variable is | ||
| // somewhat reasonable, and if the scheme is missing, it is added. | ||
| // Garbage in, garbage out some would say... | ||
| env.HTTP_PROXY = 'crazy without colon slash slash'; | ||
| testProxyUrl(env, 'http://crazy without colon slash slash', 'http://wow'); | ||
| }); | ||
| describe('https_proxy and HTTPS_PROXY', function() { | ||
| var env = {}; | ||
| // Assert that there is no fall back to http_proxy | ||
| env.HTTP_PROXY = 'http://unexpected.proxy'; | ||
| testProxyUrl(env, '', 'https://example'); | ||
| env.HTTPS_PROXY = 'http://https-proxy'; | ||
| testProxyUrl(env, 'http://https-proxy', 'https://example'); | ||
| // eslint-disable-next-line camelcase | ||
| env.https_proxy = 'http://priority'; | ||
| testProxyUrl(env, 'http://priority', 'https://example'); | ||
| }); | ||
| describe('ftp_proxy', function() { | ||
| var env = {}; | ||
| // Something else than http_proxy / https, as a sanity check. | ||
| env.FTP_PROXY = 'http://ftp-proxy'; | ||
| testProxyUrl(env, 'http://ftp-proxy', 'ftp://example'); | ||
| testProxyUrl(env, '', 'ftps://example'); | ||
| }); | ||
| describe('all_proxy', function() { | ||
| var env = {}; | ||
| env.ALL_PROXY = 'http://catch-all'; | ||
| testProxyUrl(env, 'http://catch-all', 'https://example'); | ||
| // eslint-disable-next-line camelcase | ||
| env.all_proxy = 'http://priority'; | ||
| testProxyUrl(env, 'http://priority', 'https://example'); | ||
| }); | ||
| describe('all_proxy without scheme', function() { | ||
| var env = {}; | ||
| env.ALL_PROXY = 'noscheme'; | ||
| testProxyUrl(env, 'http://noscheme', 'http://example'); | ||
| testProxyUrl(env, 'https://noscheme', 'https://example'); | ||
| // The module does not impose restrictions on the scheme. | ||
| testProxyUrl(env, 'bogus-scheme://noscheme', 'bogus-scheme://example'); | ||
| // But the URL should still be valid. | ||
| testProxyUrl(env, '', 'bogus'); | ||
| }); | ||
| describe('no_proxy empty', function() { | ||
| var env = {}; | ||
| env.HTTPS_PROXY = 'http://proxy'; | ||
| // NO_PROXY set but empty. | ||
| env.NO_PROXY = ''; | ||
| testProxyUrl(env, 'http://proxy', 'https://example'); | ||
| // No entries in NO_PROXY (comma). | ||
| env.NO_PROXY = ','; | ||
| testProxyUrl(env, 'http://proxy', 'https://example'); | ||
| // No entries in NO_PROXY (whitespace). | ||
| env.NO_PROXY = ' '; | ||
| testProxyUrl(env, 'http://proxy', 'https://example'); | ||
| // No entries in NO_PROXY (multiple whitespace / commas). | ||
| env.NO_PROXY = ',\t,,,\n, ,\r'; | ||
| testProxyUrl(env, 'http://proxy', 'https://example'); | ||
| }); | ||
| describe('no_proxy=example (single host)', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = 'example'; | ||
| testProxyUrl(env, '', 'http://example'); | ||
| testProxyUrl(env, '', 'http://example:80'); | ||
| testProxyUrl(env, '', 'http://example:0'); | ||
| testProxyUrl(env, '', 'http://example:1337'); | ||
| testProxyUrl(env, 'http://proxy', 'http://sub.example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://prefexample'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example.no'); | ||
| testProxyUrl(env, 'http://proxy', 'http://a.b.example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://host/example'); | ||
| }); | ||
| describe('no_proxy=sub.example (subdomain)', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = 'sub.example'; | ||
| testProxyUrl(env, 'http://proxy', 'http://example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example:80'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example:0'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example:1337'); | ||
| testProxyUrl(env, '', 'http://sub.example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://no.sub.example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://sub-example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example.sub'); | ||
| }); | ||
| describe('no_proxy=example:80 (host + port)', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = 'example:80'; | ||
| testProxyUrl(env, '', 'http://example'); | ||
| testProxyUrl(env, '', 'http://example:80'); | ||
| testProxyUrl(env, '', 'http://example:0'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example:1337'); | ||
| testProxyUrl(env, 'http://proxy', 'http://sub.example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://prefexample'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example.no'); | ||
| testProxyUrl(env, 'http://proxy', 'http://a.b.example'); | ||
| }); | ||
| describe('no_proxy=.example (host suffix)', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = '.example'; | ||
| testProxyUrl(env, 'http://proxy', 'http://example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example:80'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example:1337'); | ||
| testProxyUrl(env, '', 'http://sub.example'); | ||
| testProxyUrl(env, '', 'http://sub.example:80'); | ||
| testProxyUrl(env, '', 'http://sub.example:1337'); | ||
| testProxyUrl(env, 'http://proxy', 'http://prefexample'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example.no'); | ||
| testProxyUrl(env, '', 'http://a.b.example'); | ||
| }); | ||
| describe('no_proxy=*', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = '*'; | ||
| testProxyUrl(env, '', 'http://example.com'); | ||
| }); | ||
| describe('no_proxy=*.example (host suffix with *.)', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = '*.example'; | ||
| testProxyUrl(env, 'http://proxy', 'http://example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example:80'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example:1337'); | ||
| testProxyUrl(env, '', 'http://sub.example'); | ||
| testProxyUrl(env, '', 'http://sub.example:80'); | ||
| testProxyUrl(env, '', 'http://sub.example:1337'); | ||
| testProxyUrl(env, 'http://proxy', 'http://prefexample'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example.no'); | ||
| testProxyUrl(env, '', 'http://a.b.example'); | ||
| }); | ||
| describe('no_proxy=*example (substring suffix)', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = '*example'; | ||
| testProxyUrl(env, '', 'http://example'); | ||
| testProxyUrl(env, '', 'http://example:80'); | ||
| testProxyUrl(env, '', 'http://example:1337'); | ||
| testProxyUrl(env, '', 'http://sub.example'); | ||
| testProxyUrl(env, '', 'http://sub.example:80'); | ||
| testProxyUrl(env, '', 'http://sub.example:1337'); | ||
| testProxyUrl(env, '', 'http://prefexample'); | ||
| testProxyUrl(env, '', 'http://a.b.example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://example.no'); | ||
| testProxyUrl(env, 'http://proxy', 'http://host/example'); | ||
| }); | ||
| describe('no_proxy=.*example (arbitrary wildcards are NOT supported)', | ||
| function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = '.*example'; | ||
| testProxyUrl(env, 'http://proxy', 'http://example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://sub.example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://sub.example'); | ||
| testProxyUrl(env, 'http://proxy', 'http://prefexample'); | ||
| testProxyUrl(env, 'http://proxy', 'http://x.prefexample'); | ||
| testProxyUrl(env, 'http://proxy', 'http://a.b.example'); | ||
| }); | ||
| describe('no_proxy=[::1],[::2]:80,10.0.0.1,10.0.0.2:80 (IP addresses)', | ||
| function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = '[::1],[::2]:80,10.0.0.1,10.0.0.2:80'; | ||
| testProxyUrl(env, '', 'http://[::1]/'); | ||
| testProxyUrl(env, '', 'http://[::1]:80/'); | ||
| testProxyUrl(env, '', 'http://[::1]:1337/'); | ||
| testProxyUrl(env, '', 'http://[::2]/'); | ||
| testProxyUrl(env, '', 'http://[::2]:80/'); | ||
| testProxyUrl(env, 'http://proxy', 'http://[::2]:1337/'); | ||
| testProxyUrl(env, '', 'http://10.0.0.1/'); | ||
| testProxyUrl(env, '', 'http://10.0.0.1:80/'); | ||
| testProxyUrl(env, '', 'http://10.0.0.1:1337/'); | ||
| testProxyUrl(env, '', 'http://10.0.0.2/'); | ||
| testProxyUrl(env, '', 'http://10.0.0.2:80/'); | ||
| testProxyUrl(env, 'http://proxy', 'http://10.0.0.2:1337/'); | ||
| }); | ||
| describe('no_proxy=127.0.0.1/32 (CIDR is NOT supported)', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = '127.0.0.1/32'; | ||
| testProxyUrl(env, 'http://proxy', 'http://127.0.0.1'); | ||
| testProxyUrl(env, 'http://proxy', 'http://127.0.0.1/32'); | ||
| }); | ||
| describe('no_proxy=127.0.0.1 does NOT match localhost', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = '127.0.0.1'; | ||
| testProxyUrl(env, '', 'http://127.0.0.1'); | ||
| // We're not performing DNS queries, so this shouldn't match. | ||
| testProxyUrl(env, 'http://proxy', 'http://localhost'); | ||
| }); | ||
| describe('no_proxy with protocols that have a default port', function() { | ||
| var env = {}; | ||
| env.WS_PROXY = 'http://ws'; | ||
| env.WSS_PROXY = 'http://wss'; | ||
| env.HTTP_PROXY = 'http://http'; | ||
| env.HTTPS_PROXY = 'http://https'; | ||
| env.GOPHER_PROXY = 'http://gopher'; | ||
| env.FTP_PROXY = 'http://ftp'; | ||
| env.ALL_PROXY = 'http://all'; | ||
| env.NO_PROXY = 'xxx:21,xxx:70,xxx:80,xxx:443'; | ||
| testProxyUrl(env, '', 'http://xxx'); | ||
| testProxyUrl(env, '', 'http://xxx:80'); | ||
| testProxyUrl(env, 'http://http', 'http://xxx:1337'); | ||
| testProxyUrl(env, '', 'ws://xxx'); | ||
| testProxyUrl(env, '', 'ws://xxx:80'); | ||
| testProxyUrl(env, 'http://ws', 'ws://xxx:1337'); | ||
| testProxyUrl(env, '', 'https://xxx'); | ||
| testProxyUrl(env, '', 'https://xxx:443'); | ||
| testProxyUrl(env, 'http://https', 'https://xxx:1337'); | ||
| testProxyUrl(env, '', 'wss://xxx'); | ||
| testProxyUrl(env, '', 'wss://xxx:443'); | ||
| testProxyUrl(env, 'http://wss', 'wss://xxx:1337'); | ||
| testProxyUrl(env, '', 'gopher://xxx'); | ||
| testProxyUrl(env, '', 'gopher://xxx:70'); | ||
| testProxyUrl(env, 'http://gopher', 'gopher://xxx:1337'); | ||
| testProxyUrl(env, '', 'ftp://xxx'); | ||
| testProxyUrl(env, '', 'ftp://xxx:21'); | ||
| testProxyUrl(env, 'http://ftp', 'ftp://xxx:1337'); | ||
| }); | ||
| describe('no_proxy should not be case-sensitive', function() { | ||
| var env = {}; | ||
| env.HTTP_PROXY = 'http://proxy'; | ||
| env.NO_PROXY = 'XXX,YYY,ZzZ'; | ||
| testProxyUrl(env, '', 'http://xxx'); | ||
| testProxyUrl(env, '', 'http://XXX'); | ||
| testProxyUrl(env, '', 'http://yyy'); | ||
| testProxyUrl(env, '', 'http://YYY'); | ||
| testProxyUrl(env, '', 'http://ZzZ'); | ||
| testProxyUrl(env, '', 'http://zZz'); | ||
| }); | ||
| // Up until proxy-from-env@1.1.0, proxy-from-env had undocumented support for | ||
| // specifying proxies through npm_config_ prefixes. The historical reasons | ||
| // for them are no longer relevant: | ||
| // https://github.com/Rob--W/proxy-from-env/issues/13#issuecomment-3150256653 | ||
| describe('NPM proxy configuration', function() { | ||
| describe('npm_config_*_proxy variables are unsupported', function() { | ||
| var env = {}; | ||
| // eslint-disable-next-line camelcase | ||
| env.npm_config_http_proxy = 'http://http-proxy'; | ||
| // eslint-disable-next-line camelcase | ||
| env.npm_config_https_proxy = 'http://https-proxy'; | ||
| // eslint-disable-next-line camelcase | ||
| env.npm_config_proxy = 'http://unexpected-proxy'; | ||
| testProxyUrl(env, '', 'http://example'); | ||
| testProxyUrl(env, '', 'https://example'); | ||
| }); | ||
| }); | ||
| }); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
164
5.81%4
-42.86%15643
-49.77%5
-28.57%187
-63.19%1
Infinity%