New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

proxy-from-env

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

proxy-from-env - npm Package Compare versions

Comparing version
1.1.0
to
2.0.0
+66
.github/workflows/run-tests.yaml
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,
}
]);
+14
-19
'use strict';
var parseUrl = require('url').parse;
var DEFAULT_PORTS = {

@@ -14,14 +12,18 @@ ftp: 21,

var stringEndsWith = String.prototype.endsWith || function(s) {
return s.length <= this.length &&
this.indexOf(s, this.length - s.length) !== -1;
};
function parseUrl(urlString) {
try {
return new URL(urlString);
} catch {
return null;
}
}
/**
* @param {string|object} url - The URL, or the result from url.parse.
* @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 || {};
export function getProxyForUrl(url) {
var parsedUrl = (typeof url === 'string' ? parseUrl(url) : url) || {};
var proto = parsedUrl.protocol;

@@ -43,7 +45,3 @@ var hostname = parsedUrl.host;

var proxy =
getEnv('npm_config_' + proto + '_proxy') ||
getEnv(proto + '_proxy') ||
getEnv('npm_config_proxy') ||
getEnv('all_proxy');
var proxy = getEnv(proto + '_proxy') || getEnv('all_proxy');
if (proxy && proxy.indexOf('://') === -1) {

@@ -65,4 +63,3 @@ // Missing scheme in proxy, default to the requested URL's scheme.

function shouldProxy(hostname, port) {
var NO_PROXY =
(getEnv('npm_config_no_proxy') || getEnv('no_proxy')).toLowerCase();
var NO_PROXY = getEnv('no_proxy').toLowerCase();
if (!NO_PROXY) {

@@ -96,3 +93,3 @@ return true; // Always proxy if NO_PROXY is not set.

// Stop proxying if the hostname ends with the no_proxy host.
return !stringEndsWith.call(hostname, parsedProxyHostname);
return !hostname.endsWith(parsedProxyHostname);
});

@@ -111,3 +108,1 @@ }

}
exports.getProxyForUrl = getProxyForUrl;
{
"name": "proxy-from-env",
"version": "1.1.0",
"version": "2.0.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",
"scripts": {
"lint": "eslint *.js",
"test": "mocha ./test.js --reporter spec",
"test-coverage": "istanbul cover ./node_modules/.bin/_mocha -- --reporter spec"
"lint": "eslint *.js *.mjs",
"test": "node --test ./test.js",
"test-coverage": "node --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info ./test.js",
"test-coverage-as-html": "npm run test-coverage && genhtml lcov.info -o coverage/"
},
"repository": {
"type": "git",
"url": "https://github.com/Rob--W/proxy-from-env.git"
"url": "git+https://github.com/Rob--W/proxy-from-env.git"
},

@@ -29,7 +31,6 @@ "keywords": [

"devDependencies": {
"coveralls": "^3.0.9",
"eslint": "^6.8.0",
"istanbul": "^0.4.5",
"mocha": "^7.1.0"
}
"eslint": "^9.39.2"
},
"type": "module",
"sideEffects": false
}
# proxy-from-env
[![Build Status](https://travis-ci.org/Rob--W/proxy-from-env.svg?branch=master)](https://travis-ci.org/Rob--W/proxy-from-env)
![Build Status](https://github.com/Rob--W/proxy-from-env/actions/workflows/run-tests.yaml/badge.svg?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/Rob--W/proxy-from-env/badge.svg?branch=master)](https://coveralls.io/github/Rob--W/proxy-from-env?branch=master)
`proxy-from-env` is a Node.js package that exports a function (`getProxyForUrl`)
that takes an input URL (a string or
[`url.parse`](https://nodejs.org/docs/latest/api/url.html#url_url_parsing)'s
that takes an input URL (a string, an instance of
[`URL`](https://nodejs.org/docs/latest/api/url.html#the-whatwg-url-api),
or [`url.parse`](https://nodejs.org/docs/latest/api/url.html#url_url_parsing)'s
return value) and returns the desired proxy URL (also a string) based on

@@ -25,6 +26,10 @@ standard proxy environment variables. If no proxy is set, an empty string is

warning: this simple example works for http requests only. To support https,
you must establish a proxy tunnel via the
[http `connect` method](https://developer.mozilla.org/en-us/docs/web/http/reference/methods/connect).
```javascript
var http = require('http');
var parseUrl = require('url').parse;
var getProxyForUrl = require('proxy-from-env').getProxyForUrl;
import http from 'node:test';
import { getProxyForUrl } from 'proxy-from-env';
// ^ or: var getProxyForUrl = require('proxy-from-env').getProxyForUrl;

@@ -44,4 +49,4 @@ var some_url = 'http://example.com/something';

// Should be proxied through proxy_url.
var parsed_some_url = parseUrl(some_url);
var parsed_proxy_url = parseUrl(proxy_url);
var parsed_some_url = new URL(some_url);
var parsed_proxy_url = new URL(proxy_url);
// A HTTP proxy is quite simple. It is similar to a normal request, except the

@@ -68,5 +73,23 @@ // path is an absolute URL, and the proxied URL's host is put in the header

});
```
### Full proxy support
The simple example above works for http requests only. To support https, you
must establish a proxy tunnel via the
[http `connect` method](https://developer.mozilla.org/en-us/docs/web/http/reference/methods/connect).
An example of that is shown in the
[`https-proxy-agent` npm package](https://www.npmjs.com/package/https-proxy-agent).
The [`proxy-agent` npm package](https://www.npmjs.com/package/proxy-agent)
combines `https-proxy-agent` and `proxy-from-env` to offer a `http.Agent` that
supports proxies from environment variables.
### Built-in proxy support
Node.js is working on built-in support for proxy environment variables,
currently behind `NODE_USE_ENV_PROXY=1` or `--use-env-proxy`. For details, see:
- https://github.com/nodejs/node/issues/57872
- https://nodejs.org/api/http.html#built-in-proxy-support
## Environment variables

@@ -73,0 +96,0 @@ The environment variables can be specified in lowercase or uppercase, with the

+52
-103
/* eslint max-statements:0 */
'use strict';
var assert = require('assert');
var parseUrl = require('url').parse;
import {describe, it} from 'node:test';
import assert from 'node:assert';
import {parse as parseUrl} from 'node:url';
var getProxyForUrl = require('./').getProxyForUrl;
import {getProxyForUrl} from 'proxy-from-env';

@@ -30,10 +31,2 @@ // Runs the callback with process.env temporarily set to env.

// Save call stack for later use.
var stack = {};
Error.captureStackTrace(stack, testProxyUrl);
// Only use the last stack frame because that shows where this function is
// called, and that is sufficient for our purpose. No need to flood the logs
// with an uninteresting stack trace.
stack = stack.stack.split('\n', 2)[1];
it(title, function() {

@@ -44,14 +37,3 @@ var actual;

});
if (expected === actual) {
return; // Good!
}
try {
assert.strictEqual(expected, actual); // Create a formatted error message.
// Should not happen because previously we determined expected !== actual.
throw new Error('assert.strictEqual passed. This is impossible!');
} catch (e) {
// Use the original stack trace, so we can see a helpful line number.
e.stack = e.message + stack;
throw e;
}
assert.strictEqual(actual, expected);
});

@@ -83,2 +65,3 @@ }

testProxyUrl(env, '', '__proto__://');
testProxyUrl(env, '', 'http://abc\x00/');
testProxyUrl(env, '', undefined);

@@ -89,2 +72,42 @@ testProxyUrl(env, '', null);

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);
});
});

@@ -395,94 +418,20 @@

// 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_http_proxy should work', function() {
describe('npm_config_*_proxy variables are unsupported', function() {
var env = {};
// eslint-disable-next-line camelcase
env.npm_config_http_proxy = 'http://http-proxy';
testProxyUrl(env, '', 'https://example');
testProxyUrl(env, 'http://http-proxy', 'http://example');
// eslint-disable-next-line camelcase
env.npm_config_http_proxy = 'http://priority';
testProxyUrl(env, 'http://priority', 'http://example');
});
// eslint-disable-next-line max-len
describe('npm_config_http_proxy should take precedence over HTTP_PROXY and npm_config_proxy', function() {
var env = {};
// eslint-disable-next-line camelcase
env.npm_config_http_proxy = 'http://http-proxy';
// eslint-disable-next-line camelcase
env.npm_config_proxy = 'http://unexpected-proxy';
env.HTTP_PROXY = 'http://unexpected-proxy';
testProxyUrl(env, 'http://http-proxy', 'http://example');
});
describe('npm_config_https_proxy should work', function() {
var env = {};
// eslint-disable-next-line camelcase
env.npm_config_http_proxy = 'http://unexpected.proxy';
testProxyUrl(env, '', 'https://example');
// eslint-disable-next-line camelcase
env.npm_config_https_proxy = 'http://https-proxy';
testProxyUrl(env, 'http://https-proxy', 'https://example');
// eslint-disable-next-line camelcase
env.npm_config_https_proxy = 'http://priority';
testProxyUrl(env, 'http://priority', 'https://example');
});
// eslint-disable-next-line max-len
describe('npm_config_https_proxy should take precedence over HTTPS_PROXY and npm_config_proxy', function() {
var env = {};
// 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';
env.HTTPS_PROXY = 'http://unexpected-proxy';
testProxyUrl(env, 'http://https-proxy', 'https://example');
});
describe('npm_config_proxy should work', function() {
var env = {};
// eslint-disable-next-line camelcase
env.npm_config_proxy = 'http://http-proxy';
testProxyUrl(env, 'http://http-proxy', 'http://example');
testProxyUrl(env, 'http://http-proxy', 'https://example');
// eslint-disable-next-line camelcase
env.npm_config_proxy = 'http://priority';
testProxyUrl(env, 'http://priority', 'http://example');
testProxyUrl(env, 'http://priority', 'https://example');
});
// eslint-disable-next-line max-len
describe('HTTP_PROXY and HTTPS_PROXY should take precedence over npm_config_proxy', function() {
var env = {};
env.HTTP_PROXY = 'http://http-proxy';
env.HTTPS_PROXY = 'http://https-proxy';
// eslint-disable-next-line camelcase
env.npm_config_proxy = 'http://unexpected-proxy';
testProxyUrl(env, 'http://http-proxy', 'http://example');
testProxyUrl(env, 'http://https-proxy', 'https://example');
});
describe('npm_config_no_proxy should work', function() {
var env = {};
env.HTTP_PROXY = 'http://proxy';
// eslint-disable-next-line camelcase
env.npm_config_no_proxy = 'example';
testProxyUrl(env, '', 'http://example');
testProxyUrl(env, 'http://proxy', 'http://otherwebsite');
testProxyUrl(env, '', 'https://example');
});
// eslint-disable-next-line max-len
describe('npm_config_no_proxy should take precedence over NO_PROXY', function() {
var env = {};
env.HTTP_PROXY = 'http://proxy';
env.NO_PROXY = 'otherwebsite';
// eslint-disable-next-line camelcase
env.npm_config_no_proxy = 'example';
testProxyUrl(env, '', 'http://example');
testProxyUrl(env, 'http://proxy', 'http://otherwebsite');
});
});
});
{
"env": {
"node": true
},
"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
}
}
language: node_js
node_js:
- node
- lts/*
script:
- npm run lint
# test-coverage will also run the tests, but does not print helpful output upon test failure.
# So we also run the tests separately.
- npm run test
- npm run test-coverage && cat coverage/lcov.info | ./node_modules/.bin/coveralls && rm -rf coverage